Phantom is an open-source input simulation tool designed to automate realistic user interactions for developers and QA engineers. It generates mouse movements, keyboard activity, scrolling, and app switching to aid in UI testing, screen-lock prevention, demo environments, and accessibility testing.
Key Features:
Configurable simulation profiles for tailored interaction patterns.
A TUI dashboard providing real-time monitoring of activities.
Global hotkeys enabling quick control over simulations.
Stealth mode with process name masking and system tray integration.
Audience & Benefit:
Ideal for developers and QA engineers seeking to automate repetitive tasks or maintain active states in applications. It is also beneficial for anyone needing realistic user activity simulation for testing or demonstration purposes.
Phantom can be installed via winget, offering a seamless setup experience across supported platforms.
README
Phantom
Cross-platform activity simulator that keeps your computer looking busy.
graph LR
A[Phantom App] --> B[Scheduler]
B --> C{Weighted RandomSelection}
C --> D[🖱️ Mouse]
C --> E[⌨️ Keyboard]
C --> F[📜 Scroll]
C --> G[🔀 App Switcher]
C --> H[🌐 Browser Tabs]
D --> I[Bezier CurveMovement]
E --> J[Modifier KeysOnly]
B --> K[Anti-Detection]
K -->|blocks repeats| C
B --> L[Gaussian Timing+ Random Idle]
Phantom's scheduler runs in a daemon thread, picking a random simulator on each cycle. The selection is weighted — higher weight means chosen more often. Timing follows a normal distribution with configurable mean/stddev, plus random idle periods that mimic natural breaks. An anti-detection system prevents repetitive patterns (e.g., same action 4+ times in a row, or alternating A-B-A-B sequences).
Features
mindmap
root((Phantom))
Simulators
Mouse — Bezier curves + micro-corrections
Keyboard — modifier keys only, no visible output
Scroll — vertical + horizontal
App Switcher — Cmd+Tab / Alt+Tab
Browser Tabs — context-aware shortcuts
Stealth
Process name masking
Tray icon hiding
Anti-detection timing
Pattern variation
Cross-Platform
macOS
Windows
Linux X11
Interface
System tray icon
TUI dashboard
Rich colored logging
Global hotkeys
CLI flags
JSON config
Simulator
What it does
Default Weight
Mouse
Moves cursor along randomized cubic Bezier curves with 30% chance of micro-correction jitter at the end
Vertical scrolling (90%) or horizontal scrolling (10%), random direction and amount
15
App Switcher
Simulates Cmd+Tab (macOS) or Alt+Tab (Windows/Linux) to switch 1-3 apps
10
Browser Tabs
Context-aware tab switching — detects the active app and sends the correct shortcut (e.g. Cmd+Shift+] for browsers on macOS, Ctrl+Tab for VS Code). Falls back to Ctrl+Tab when detection is unavailable
Both installers are fully cross-platform — use whichever you prefer on any OS:
Method
Command
Works on
Bash
git clone https://github.com/hammadxcm/go-phantom.git && cd phantom && ./install.sh
macOS, Linux, Windows (Git Bash / WSL / MSYS2)
PowerShell
git clone https://github.com/hammadxcm/go-phantom.git; cd phantom; .\install.ps1
Windows, macOS (pwsh), Linux (pwsh)
CMD
git clone https://github.com/hammadxcm/go-phantom.git && cd phantom && install.bat
Windows (Command Prompt)
Make
git clone https://github.com/hammadxcm/go-phantom.git && cd phantom && make setup
macOS, Linux, Windows (Git Bash / MSYS2)
graph TD
A[Run installer] --> B{Detect OS}
B -->|macOS| C[Check Python 3.8+]
B -->|Linux| D[Check Python 3.8+ & X11]
B -->|Windows| E[Check Python 3.8+]
B -->|WSL| F[Check Python 3.8+ & DISPLAY]
C --> G[Create venv at ~/.phantom]
D --> G
E --> G
F --> G
G --> H[pip install dependencies]
H --> I[Create phantom command in ~/.local/bin]
I --> J{OS-specific notes}
J -->|macOS| K[Grant Accessibility permission]
J -->|Windows| L[Add AV exclusion]
J -->|Linux| M[Ensure X11 + tray support]
J -->|WSL| N[Configure X11 display server]
style A fill:#4CAF50,color:#fff
style J fill:#FF9800,color:#fff
The installer automatically:
Detects your OS and checks prerequisites (Python 3.8+, X11 on Linux, DISPLAY on WSL)
Creates an isolated virtual environment at ~/.phantom/
Weights control how often each simulator is picked. Higher = more frequent.
# Mouse-heavy (80% mouse, 20% keyboard)
phantom --only mouse,keyboard --mouse-weight 80 --keyboard-weight 20
# Equal distribution across all simulators
phantom --all --mouse-weight 20 --keyboard-weight 20 --scroll-weight 20 \
--app-switcher-weight 20 --browser-tabs-weight 20
# Mostly scrolling with some mouse
phantom --only mouse,scroll --scroll-weight 70 --mouse-weight 30
Stealth Options
# Maximum stealth (rename process + hide tray icon)
phantom --stealth
# Custom process name
phantom --process-name "WindowServer"
# No stealth at all
phantom --no-stealth
> Note: TUI mode and system tray are mutually exclusive. The --tui flag runs the dashboard on the main thread; without it, the system tray runs instead.
CLI Reference
Run phantom --help to see all options. Key flags:
Flag
Description
-c, --config
Path to config.json
-v, --verbose
Debug logging
--tui
TUI dashboard mode
--mouse-only
Mouse simulator only
--keyboard-only
Keyboard simulator only
--scroll-only
Scroll simulator only
--only SIMS
Comma-separated simulators
--enable SIMS
Add simulators to defaults
--disable SIMS
Remove simulators
--all
Enable all 5 simulators
--interval SEC
Mean action interval
--idle-chance P
Idle probability (0-1)
--mouse-distance MIN MAX
Movement range (px)
--mouse-speed STEPS
Bezier smoothness
--key-presses MAX
Max keys per action
--scroll-clicks MIN MAX
Scroll range
--mouse-weight W
Mouse frequency weight
--stealth
Max stealth mode
--no-stealth
Disable stealth
--process-name NAME
Custom process name
--hotkey-toggle KEYS
Toggle hotkey
--hotkey-quit KEYS
Quit hotkey
Global Hotkeys
Hotkey
Action
Description
Ctrl+Alt+S
Toggle
Start or pause simulation
Ctrl+Alt+Q
Quit
Gracefully exit Phantom
Ctrl+Alt+H
Hide
Toggle tray icon visibility
System Tray
When running, Phantom shows a system tray icon with a right-click menu:
$ python -m phantom -v
14:13:44 [INFO] phantom.config.manager: No config file found, using defaults
14:13:44 [WARNING] phantom.core.platform: macOS requires Accessibility permission...
14:13:45 [INFO] phantom.stealth.process: Process renamed to 'system_service'
14:13:45 [INFO] phantom.hotkeys.manager: Hotkeys registered: toggle=++s, quit=++q
14:13:45 [INFO] phantom.core.scheduler: Simulation loop started
14:13:45 [INFO] phantom.app: Phantom started. Press ++s to toggle.
14:13:47 [DEBUG] MouseSimulator: Mouse moved to (1474, 829)
14:13:52 [DEBUG] KeyboardSimulator: Keyboard: 2 modifier presses
14:13:58 [DEBUG] ScrollSimulator: Scroll: 3 clicks, direction=1
14:14:05 [DEBUG] MouseSimulator: Mouse moved to (892, 341)
14:14:13 [DEBUG] Idle period: 23.4s
Platform Setup
🍎 macOS
Click to expand macOS setup instructions
Prerequisites
macOS 10.15+ (Catalina or later)
Python 3.8+
Accessibility Permission (Required)
Phantom needs Accessibility access to control mouse and keyboard input. Without it, simulators will fail silently.
System Settings → Privacy & Security → Accessibility
Step by step:
Open System Settings (or System Preferences on older macOS)
Navigate to Privacy & Security → Accessibility
Click the 🔒 lock icon and authenticate
Click + and add your terminal app:
Terminal.app — if using default terminal
iTerm.app — if using iTerm2
Visual Studio Code.app — if running from VS Code terminal
If running the built binary, add phantom directly
Verify it works
# Create venv and install
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
# Run with verbose logging — watch for mouse movement logs
python -m phantom -v
# Expected output:
# [INFO] phantom.stealth.process: Process renamed to 'system_service'
# [INFO] phantom.core.scheduler: Simulation loop started
# [DEBUG] MouseSimulator: Mouse moved to (x, y) ← confirms Accessibility works
macOS-specific behavior
Behavior
Details
Main thread
pystray requires the main thread on macOS — Phantom handles this automatically (tray runs on main, scheduler on daemon thread)
App Switcher
Uses Cmd+Tab (not Alt+Tab)
Process masking
Uses setproctitle with libc.dylib fallback
Gatekeeper
Built binary may need: right-click → Open → confirm
Troubleshooting
# Check if Accessibility is working
python3 -c "import pyautogui; print(pyautogui.position())"
# Should print current mouse coordinates, not throw an error
# If pystray crashes on startup
# Ensure you're NOT running in a headless/SSH session
echo $DISPLAY # Should not be empty if using XQuartz
🪟 Windows
Click to expand Windows setup instructions
Prerequisites
Windows 10/11
Python 3.8+ (python.org — check "Add to PATH" during install)
Installation
# Clone and install
git clone https://github.com/hammadxcm/go-phantom.git
cd phantom
python -m venv .venv
.venv\Scripts\activate
pip install -e .
Antivirus Exclusion
Some AV software flags Phantom because it simulates input. To add an exclusion in Windows Defender:
Windows Security → Virus & threat protection → Manage settings
→ Exclusions → Add or remove exclusions → Add an exclusion
Add either:
The phantom directory (folder exclusion)
The built phantom.exe (file exclusion)
Verify it works
# Run with verbose logging
python -m phantom -v
# Expected output:
# [INFO] phantom.stealth.process: Console title set to 'system_service'
# [INFO] phantom.core.scheduler: Simulation loop started
# [DEBUG] MouseSimulator: Mouse moved to (x, y)
Windows-specific behavior
Behavior
Details
Process masking
Uses SetConsoleTitleW via ctypes — changes console window title, limited effect on modern Windows Terminal
# In another terminal, after starting Phantom:
ps aux | grep system_service
# Should show the phantom process with name 'system_service'
# Or use htop — search for 'system_service'
Troubleshooting
# If mouse simulation fails
python3 -c "import pyautogui; print(pyautogui.position())"
# Error? → You're probably on Wayland
# If tray icon doesn't appear (GNOME)
# Install AppIndicator support:
sudo apt install gnome-shell-extension-appindicator
# Then enable it in GNOME Extensions app
# If hotkeys don't work
# Check for conflicts: some DEs grab Ctrl+Alt combos globally
# Change hotkeys in config.json to avoid conflicts
Configuration
Phantom looks for config.json in this order:
graph LR
A[1. CLI flag-c path] -->|not provided| B[2. Beside executable<i>PyInstaller only</i>]
B -->|not found| C[3. Current directory./config.json]
C -->|not found| D[4. Home directory~/.phantom/config.json]
D -->|not found| E[5. Built-in defaults]
style A fill:#4CAF50,color:#fff
style E fill:#2196F3,color:#fff
Average seconds between actions (normal distribution center)
interval_stddev
float
4.0
Standard deviation — higher = more variation
interval_min
float
0.5
Floor — actions never fire faster than this
idle_chance
float
0.10
Probability (0-1) of entering an idle period per cycle
idle_min
float
15.0
Minimum idle pause in seconds
idle_max
float
120.0
Maximum idle pause in seconds
Tuning tips:
// Fast mode — frequent small actions
{ "interval_mean": 3.0, "interval_stddev": 1.5, "idle_chance": 0.05 }
// Relaxed mode — slow, natural pace
{ "interval_mean": 15.0, "interval_stddev": 8.0, "idle_chance": 0.20 }
mouse — Bezier curve mouse movement
Key
Type
Default
Description
enabled
bool
true
Enable/disable mouse simulator
weight
float
40.0
Selection probability (relative to other simulators)
min_distance
int
50
Minimum pixels to move per action
max_distance
int
500
Maximum pixels to move per action
bezier_steps
int
50
Number of points on the curve — higher = smoother
graph LR
A((Start)) -->|"Bezier curve50 steps"| B((End))
A -.->|"Control Point 1(random offset)"| CP1(( ))
CP1 -.-> B
A -.->|"Control Point 2(random offset)"| CP2(( ))
CP2 -.-> B
B -->|"30% chance"| C((Micro-correction±3px jitter))
keyboard — Modifier key simulation
Key
Type
Default
Description
enabled
bool
true
Enable/disable keyboard simulator
weight
float
30.0
Selection probability weight
max_presses
int
3
Maximum key presses per action (1 to N)
Safe keys used:Shift, Ctrl, Alt + CapsLock double-tap (15% chance, toggles on then off immediately).
These keys produce no visible output — they won't type into your active application.
scroll — Scroll wheel simulation
Key
Type
Default
Description
enabled
bool
true
Enable/disable scroll simulator
weight
float
15.0
Selection probability weight
min_clicks
int
1
Minimum scroll clicks per action
max_clicks
int
5
Maximum scroll clicks per action
90% vertical scroll, 10% horizontal scroll. Direction is random (up/down or left/right).
app_switcher — Application switching
Key
Type
Default
Description
enabled
bool
false
Disabled by default — will switch your active window
weight
float
10.0
Selection probability weight
Uses Cmd+Tab on macOS, Alt+Tab on Windows/Linux. Switches 1-3 applications per action.
> ⚠️ Warning: This will change your focused application. Only enable if you want realistic app-switching behavior.
browser_tabs — Context-aware tab switching
Key
Type
Default
Description
enabled
bool
false
Disabled by default — will switch browser tabs
weight
float
5.0
Selection probability weight
context_aware
bool
true
Detect active window and send the correct shortcut for that app/OS
backward_chance
float
0.3
Probability of switching to the previous tab (vs. next tab)
When context_aware is enabled, Phantom detects the foreground application and sends the correct tab-switching shortcut:
Set context_aware: false to restore the original blind Ctrl+Tab behavior.
> ⚠️ Warning: Only effective when a tabbed application is the active window. Enable alongside app_switcher for realistic browsing simulation.
>
> Note: Active window detection is not supported on Wayland — falls back to Ctrl+Tab.
sequenceDiagram
participant Main as Main Thread
participant Tray as Tray (Main)
participant HK as Hotkey (Daemon)
participant Sched as Scheduler (Daemon)
Main->>Main: Parse args, load config
Main->>Main: Check platform, mask process
Main->>HK: Start hotkey listener
Main->>Sched: Start scheduler
Main->>Tray: Run tray event loop (blocks)
loop Every ~8s (gaussian)
Sched->>Sched: Pick weighted random simulator
Sched->>Sched: Anti-detection check
Sched->>Sched: Execute simulator
Sched->>Sched: Wait (gaussian interval)
end
HK-->>Main: Ctrl+Alt+S (toggle)
Main->>Sched: toggle()
Main->>Tray: update_status()
HK-->>Main: Ctrl+Alt+Q (quit)
Main->>Sched: shutdown()
Main->>HK: stop()
Main->>Tray: stop()
Building
Build standalone executable
# Install dev dependencies
pip install -e ".[dev]"
# Build (uses PyInstaller spec in build/phantom.spec)
make build
# Output
ls -la dist/phantom
# -rwxr-xr-x 1 user staff 12345678 phantom
Makefile targets
Target
Command
Description
make install
pip install -e .
Install in editable mode
make dev
pip install -e ".[dev]"
Install with dev tools (ruff, pyinstaller)
make lint
ruff check phantom/
Check code style
make format
ruff format phantom/
Auto-format code
make run
python -m phantom
Run normally
make run-verbose
python -m phantom -v
Run with debug logging
make tui
python -m phantom --tui
Run with TUI dashboard
make release
git tag v* && git push --tags
Create release tag
make build
pyinstaller build/phantom.spec ...
Build single executable
make clean
rm -rf dist/ build/tmp/ ...
Remove build artifacts
Testing
# Install test dependencies
pip install -e ".[dev]"
pip install pytest pytest-cov
# Run all tests
pytest
# Run with short traceback
pytest --tb=short
# Run with coverage report
pytest --cov=phantom
# Run a specific test file
pytest tests/test_simulators.py
# Run a specific test
pytest tests/test_simulators.py::test_mouse_clamp -v