Skip to content

Add optional Remote Control for task sessions#557

Open
kylecarbonneau wants to merge 4 commits into
bborn:mainfrom
kylecarbonneau:pr/remote-control
Open

Add optional Remote Control for task sessions#557
kylecarbonneau wants to merge 4 commits into
bborn:mainfrom
kylecarbonneau:pr/remote-control

Conversation

@kylecarbonneau
Copy link
Copy Markdown

@kylecarbonneau kylecarbonneau commented Jun 5, 2026

Add optional Remote Control for task sessions

What

Adds an opt-in --remote-control mode for tasks. When enabled, a task launches its
Claude session as a remote-drivable session (claude --remote-control "<name>"),
so it appears at claude.ai/code and in the phone app — while remaining fully ty-managed
(status tracking, ty input / ty output).

  • New RemoteControl bool on the Task model — DB column remote_control (default 0,
    with migration), wired through CreateTask / UpdateTask and all scan sites.
  • ty create --remote-control flag.
  • remote_control boolean on the taskyou_create_task MCP tool.
  • Executor launches claude with --remote-control "<title>" (falls back to task-<id>).
    For remote-control (interactive) sessions it skips the initial piped task prompt, so the
    human gets a clean interactive session to drive. Non-RC behavior is byte-identical.
    (The hardcoded task-guidance system prompt is removed separately in Remove hardcoded TASK GUIDANCE; default 'code' task type owns it instead #559; this PR no
    longer touches it.)

Why

Some tasks are better driven interactively by a human (from the web or phone) while still
benefiting from ty's queue, worktree isolation, and status tracking. This makes that a
first-class, opt-in option instead of an either/or choice.

How tested

  • go build ./... clean; go vet ./... clean; go test ./internal/executor/... ./internal/db/... passing.
  • Gate test: a remote-control task coexists with ty hooks — status tracks processing ⇄ blocked,
    and the session is drivable by both Remote Control and ty input / ty output.
  • Cross-platform: no OS-specific code paths added.

Notes

@kylecarbonneau
Copy link
Copy Markdown
Author

#559 Makes "suppresses the task-guidance system-prompt preamble" irrelevant.

kylecarbonneau and others added 3 commits June 6, 2026 11:19
Lets a task opt into launching its Claude session as a remote-drivable
(--remote-control) session, so it appears at claude.ai/code and on phone
while remaining ty-managed.

- RemoteControl flag on tasks (DB column + CreateTask/UpdateTask + scans)
- ty create --remote-control; remote_control on taskyou_create_task MCP tool
- Executor launches claude with --remote-control and suppresses the
  task-guidance preamble + initial prompt for RC (interactive) sessions
Extract the triplicated Remote Control flag logic into a single
rcFlag(task) helper alongside effortFlag/claudePermissionFlag, and
replace the two inlined blocks at the claude launch sites with calls to
it. Behavior is byte-identical; the systemPromptFlag/promptArg
RC-suppression stays inline.

Add tests:
- internal/db: RemoteControl CreateTask -> GetTask round-trip (true and
  default-false).
- internal/executor: rcFlag unit test (enabled contains flag + name,
  disabled empty, empty title falls back to task-<id>).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ommand injection

rcFlag built the flag with fmt's %q (Go-string quoting), then the result is
concatenated into a script run via `sh -c`. %q does not escape $, backticks,
etc., so a task title like $(...) or `...` executed arbitrary commands. Titles
are arbitrary user/MCP/daemon-supplied text, so this was a real injection vector.

Quote the name with proper shell single-quoting instead. Adds a regression test
that runs the flag through `sh` and asserts injected commands never fire.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@bborn
Copy link
Copy Markdown
Owner

bborn commented Jun 7, 2026

Pushed a fix directly to this branch (a99e382d) — flagging it here since it changes behavior.

Why: rcFlag built the flag with fmt.Sprintf("--remote-control %q ", task.Title), and that string gets concatenated into the script we run via sh -c (in runClaude / runClaudeResume). Go's %q is Go-string quoting, not shell quoting — it escapes " and \ but leaves $, backticks, and $(...) live. So a task titled $(rm -rf ~) (or any title containing `/$) would have its command substitution executed by the shell when the session launches.

This matters because task titles are arbitrary text and can arrive from the MCP create_task tool and the SSH daemon, not just a human typing locally — so it's a genuine command-injection vector, not just a self-inflicted footgun. I verified it end-to-end: a $(touch …) title creates the file when the generated string is run through sh -c.

Fix: quote the name with proper shell single-quoting ('…' with the standard '\'' escape for embedded quotes) via a small shellSingleQuote helper, instead of %q. Added a regression test (TestRCFlagShellInjection) that runs the flag through sh with several malicious titles and asserts the injected command never fires — it fails against the old %q version and passes now.

The flag itself is correct and the rest of the PR is clean — nice, well-scoped feature with good gating and tests. A few non-blocking notes I had while reviewing (no changes made, your call):

  • On resume of an RC task, the typed feedback is written to feedbackFile but promptArg is then blanked, so feedback is silently dropped. Intended? If so maybe worth a comment; if not, worth still delivering it.
  • No guard if the installed claude predates --remote-control — the session just errors at launch. A capability/version check would make the failure clearer.
  • RC + dangerous permission mode = a phone/claude.ai-drivable session running --dangerously-skip-permissions. Inherent to the feature, but might be worth a conscious warning when both are on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants