Text your computer. It does the work. Self-hosted Windows tray app bridging a Telegram bot to Claude Code, turning your phone into a remote control for an AI agent that runs on — and fully operates — your PC (mouse/keyboard, browser, files, code, reboot). Think remote desktop meets autonomous AI assistant.
⚠️ Full unattended PC control. Default mode lets the agent run any command on your machine with no per-action approval. Self-host only on a machine you own, and lockAllowedUserIdsto yourself. See Permissions & safety.
- 🤖 Operate your PC — mouse/keyboard/hotkeys, screenshots, clipboard, windows/processes, launch apps, lock/reboot. Prefers cua-driver (background computer-use — drives apps without stealing focus) and falls back to built-in UI-Automation/OCR/screenshots.
- 🌐 Drive the browser — Playwright, DOM-level (click/fill/scrape/login).
- 🗣️ Any input — text, voice notes (auto-transcribed), photo/document/video (video → frames + timestamped transcript).
- 💻 Real dev work — git, build, test, edit code, worktrees, tickets. Can edit its own source and restart itself.
- 🧵 Multiple agents — spawn sessions per folder/project, each its own Telegram topic.
- 🎫 Work your YouTrack queue on its own (opt-in, dry-run by default) — scans the tickets
assigned to you, gives each one its own git worktree, branch (
am/XT-18778, from a template you edit) and Claude session, runs your repo's build and tests itself before believing the work is done, then pushes and opens a draft merge request against the release branch from the ticket's Fixed in Version, updates the ticket, and notifies you. When QA sends a ticket back it resumes the same session, on the same branch and merge request. Approve the plan and the push from Telegram or from the task board in the window. - ⏰ Cron-style scheduled tasks.
- 🧠 Memory — persistent facts (
!remember) plus continuous learning: withClaude.ContinuousLearning=true(default), each session readsmemory/learnings.mdat task start and appends new learnings after tasks — the file Claude grows on its own, separate from user-set memory. - 🔒 Locked to you — allowlisted Telegram user IDs only, fails closed if unset; known secrets scrubbed from replies.
- 🪟 Set-and-forget — runs at login, tray icon, auto-restart on crash.
Telegram message ──► Threadwright (tray app) ──► Claude Code session ──► your PC / browser / code
▲ │
└──────────── formatted reply, screenshots ──────┘
Claude acts on the machine through MCP tool servers — cua-driver and machine-control (desktop) and Playwright (browser).
- Windows 11 + .NET 10 SDK
- Claude Code CLI on
PATH - A Telegram bot (@BotFather) + a forum-enabled supergroup (Topics ON)
- (optional) Node.js/
npxfor the browser agent. Voice works out of the box (model auto-downloads). - (optional) cua-driver for background computer-use
(drives the desktop without stealing focus). Install per-user (no admin) via the trycua/cua
installer; the bridge auto-detects
%LOCALAPPDATA%\Programs\Cua\...or set the path in Settings. Absent → the built-inmachine-controlserver is used instead.
-
Get your Telegram user ID from @userinfobot.
-
Create
appsettings.local.jsonin repo root (gitignored):{ "Telegram": { "BotToken": "123456:ABC...", "ChatId": -1001234567890, "AllowedUserIds": [ 827464027 ] }, "Claude": { "PermissionMode": "bypassPermissions" } }- BotToken — from BotFather.
- ChatId — your forum group's id (negative); add bot, post a message, then check
https://api.telegram.org/bot<TOKEN>/getUpdates→chat.id. - AllowedUserIds — empty = bot ignores everyone (fails closed). Always set this.
-
Run:
dotnet run -c Release --project src/Threadwright(from repo root). Message the group's General topic to talk to themainsession. -
Run at login (optional):
dotnet run -c Release --project src/Threadwright -- install(drops Startup shortcut →supervisor.ps1, rebuilds+relaunches on restart requests).
For a target machine with no SDK, build a self-contained Windows installer.
Build machine needs: .NET 10 SDK, git, Inno Setup 6
(ISCC.exe on PATH / Program Files / %LOCALAPPDATA%\Programs\Inno Setup 6).
pwsh installer/build-installer.ps1Publishes app + MCP server self-contained (win-x64) into installer/stage/, stages
config/assets, runs ISCC.exe → installer/output/Threadwright-Setup-<version>.exe.
Close any running Threadwright/MachineControlMcp.exe first (file-lock).
CI: .github/workflows/release.yml builds + publishes a GitHub Release
(v1.0.<commit-count>) with the installer attached, on every push to main.
Installed build: per-user install (%LOCALAPPDATA%\Threadwright, no admin), optional
login/desktop shortcuts, proper uninstall entry, dark wizard. First launch with no config
opens Settings automatically. Trade-off: no SDK/source → self-edit+rebuild and
supervisor.ps1 don't apply; /restart still works via Launch.ps1. Claude CLI (and
Node for browser) still required on target.
1.0.<git-commit-count> — every commit bumps it (Directory.Build.props). Shown in
window title, tray tooltip, startup log, --version.
-
Text / voice / photo / video / file → handed to Claude as a turn.
-
Claude
/slashcommands pass straight through. -
::keys→ answer a blocked interactive dialog (::enter,::y,::1, …). -
Bridge
!commands:Command Does !new <name> <dir> [prompt]spawn a new agent session (own topic) !sessions/!status/!costlist sessions / state / token usage !model <opus|sonnet|haiku>switch this session's model (keeps context) !remember <text>save a fact to persistent memory !git/!build/!testgit, scoped build/test !worktree <branch>/!ticket <id>/!yt <id>worktree session / YouTrack ticket !screenshot [n]/!screenrecord <n> <secs>capture desktop !ps <list|kill|stats>process operations !repo/!cd <name|dir>repo registry / switch session folder !watch <project> [id]list a project's Claude sessions, or read-only mirror one (incl. IDE sessions) to its own topic !restart/!stop/!exitrestart host / interrupt turn / close session !restartsysreboot machine !helplist all commands -
Ticket-agent
!commands (see Working your YouTrack queue):Command Does !agent <on|off|scan|status>start/stop scanning, scan now, status !tasks/!task <id>the queue / one ticket in detail !approve <id> [push]approve the plan, or the push !reject <id> <why>send the plan back with feedback !target <id> <branch>answer an unresolved merge target !pause/!unpause/!drop <id>pause, resume, or abandon a ticket
Off by default. Switch it on in Settings → YouTrack ticket agent: paste your personal YouTrack token (there is a Test connection button), map each project to a repository, and leave Dry run on for the first tickets — it then does everything except push, open merge requests and write to YouTrack, and reports exactly what it would have done.
What each ticket gets: its own worktree and branch (template {user}/{ticket} → am/XT-18778),
its own Telegram topic and chat, a plan you approve, and a merge request into the branch from the
ticket's Fixed in Version (desktop/{version}; when that branch does not exist yet you choose
what happens — use the default branch, ask you, or block). The host runs your repo's build and
test commands and feeds failures back to the session, so "it built" is never taken on trust, and it
refuses to push a protected branch or a change that touches a forbidden path.
Prefer no interruptions? Tick Work autonomously and it runs plan → implement → verify → push → merge request without stopping for approval; dry run and the push guards still apply.
- Tray icon → Show / Settings… / Restart / Exit.
- Task board — left rail lists every ticket and session with its phase; the header strip has Approve / Reject / Pause / Abort and links to the ticket and the merge request.
- Settings — startup toggle, permission mode, Claude model, Claude CLI command (e.g.
claude-mefor a different subscription), bot token/chat id/allowed users, video limits, persistent memory, continuous-learning toggle, message verbosity (how much tool activity is relayed — Quiet/Normal/Verbose), scheduled tasks, extra dev MCP servers, and the whole YouTrack ticket agent (token, query, branch/target templates with a live preview, project→repository map, merge-request options). Saving restarts everything. - Open Terminal — hands-on
claudeterminal in the session's folder, tools pre-loaded.
Settings → Scheduled tasks (or schedules.txt), one job per line:
name | spec | target | prompt
- spec —
daily HH:mmorevery 30m/every 2h/every 1d. - target — session name (
main/spawned) orspawn:C:/path.
morning | daily 09:00 | main | Summarize repo status and any failing tests.
nightly | daily 02:00 | spawn:C:/Projects/app | Run the test suite and report results.
Missed runs (app off during the scheduled minute) are not replayed.
Claude.PermissionMode in appsettings.local.json:
acceptEdits— auto-approves file edits only; other tools need aClaude.AllowedToolswhitelist.bypassPermissions(default) — Claude runs any command unattended. Only safe behindAllowedUserIds; the app auto-accepts the one-time consent screen.
This gives an AI agent full, unattended control of your PC. Run only on a machine you
own, lock AllowedUserIds to yourself, and remember code/secrets transit Telegram (a third
party). ProtectSecrets (default on) scrubs known secrets from outbound messages —
defence-in-depth, not a sandbox.
.NET 10 WPF tray app (no console). Drives Claude Code via interactive PTY (ConPTY), reads output from its JSONL transcript, relays to Telegram. MCP tool servers:
cua-driver(trycua/cua, MIT) — primary desktop driver: background computer-use over UI-Automation patterns (no focus steal). External per-user install, invoked via config (not redistributed); path is Settings-editable.machine-control(src/MCP/MachineControl/, bundled) — fallback desktop server: UI Automation, Windows OCR, Set-of-Mark annotation, vision screenshot/click, batchedrun_actions. Used whenever cua-driver is unavailable or can't act.playwright(@playwright/mcp) — DOM-level browser control, snapshot → act on refs, multi-tab.
All auto-load every session, no approval prompt. Voice via Whisper.net/Concentus
(no ffmpeg); video framing uses ffmpeg (auto-downloaded on first use).
dotnet build -c Release Threadwright.slnx # whole solution
dotnet run -c Release --project src/Threadwright # run tray app
dotnet test tests/Threadwright.Tests # E2E tests (PowerShell-host fallback)Logs: logs/agent.log (app), logs/pty.log (raw Claude TUI stream). Deeper architecture
map: CLAUDE.md.
MIT licensed — see LICENSE. PRs welcome, see CONTRIBUTING.md.
Read SECURITY.md before running this — full unattended machine control.