Skip to content

Add fork-session lane, /kill command, and auto-routing#20

Closed
1872-svg wants to merge 3 commits intomoazbuilds:masterfrom
1872-svg:feature/fork-agent
Closed

Add fork-session lane, /kill command, and auto-routing#20
1872-svg wants to merge 3 commits intomoazbuilds:masterfrom
1872-svg:feature/fork-agent

Conversation

@1872-svg
Copy link
Copy Markdown

Summary

  • Fork agent lane: /fork <prompt> spawns a parallel Claude session that doesn't touch the main session or queue. Useful for checking progress or asking quick questions while the main agent is running a long task.
  • /kill command: Terminates the currently running Claude subprocess immediately.
  • Auto-routing: When the main agent is busy, incoming messages are automatically routed to the fork lane instead of queuing behind the current task.
  • Fork agent uses Haiku model with a speed-focused system prompt — denies long tasks (compiling, downloads, fuzzing) and answers in 1-3 sentences.

How it works

runner.ts exports killActive(), isMainBusy(), and runFork(). The fork agent runs with --output-format json in a separate subprocess, bypassing the serial queue used by the main session.

In telegram.ts, handleMessage checks isMainBusy() before dispatching — busy → fork, idle → main session.

Test plan

  • Send a long-running prompt, then /fork what are you doing? — should get a fast response without interrupting the main task
  • Send a long-running prompt, then send another message mid-run — should be auto-routed to fork
  • /kill while a task is running — should terminate and confirm
  • /kill with nothing running — should report "No active agent running"

- /fork <prompt>: spawns a parallel lightweight watcher agent outside
  the main serial queue. Uses a dedicated system prompt that hard-denies
  long-running tasks (compilation, downloads, fuzzing) to keep it
  responsive for monitoring the main agent.
- /kill: sends SIGTERM to the active claude subprocess immediately.
- activeProc tracking in runClaudeOnce() enables kill to work from
  any handler without exposing the proc externally.
- Fork agent is given the session JSONL path so it can peek at main
  agent progress mid-task.
When the main serial queue is processing a task, new incoming messages
are automatically handled by the fork agent instead of queuing behind it.
This makes fork behavior transparent — users just chat normally without
needing to type /fork manually.

- Add mainRunning flag + isMainBusy() export in runner.ts
- telegram.ts checks isMainBusy() before dispatching and routes
  to runFork() if main is occupied
Hardcode FORK_MODEL to claude-haiku-4-5-20251001 — forks are meant
to be fast watchers, not reasoning agents. Add explicit speed
instructions to the system prompt: 1-3 sentences, no preamble,
no over-analysis.
@1872-svg 1872-svg force-pushed the feature/fork-agent branch from 8bb7ab8 to 0f1f920 Compare March 11, 2026 03:37
Fenrur added a commit to Fenrur/claudeclaw that referenced this pull request Mar 13, 2026
… and /kill command

From upstream PR moazbuilds#21 by 1872-svg (streaming + verbose) and PR moazbuilds#20 (fork agent).
- Streaming output via editMessageText for real-time response display
- /verbose command to show tool calls in Telegram
- /fork command for parallel lightweight agent using Haiku
- /kill command to terminate active agent
- Auto-routing to fork when main agent is busy
- Merged with additionalDirs (moazbuilds#13) and session corruption fix (moazbuilds#26)

Co-Authored-By: 1872-svg <1872-svg@users.noreply.github.com>
justmaker added a commit to justmaker/claudeclaw that referenced this pull request Mar 31, 2026
- 新增 tests/runner.test.ts(buildChildEnv、rate limit、security args、queue、timeout)
- 新增 tests/config.test.ts(resolvePrompt、parseSettings、Discord snowflake、exclude windows)
- 新增 tests/sessions.test.ts(session CRUD、turnCount、compactWarned、backup)
- package.json 新增 test script
- README 新增 Testing section(測試覆蓋範圍表格)
- 全部 178 tests 通過
@TerrysPOV TerrysPOV self-assigned this Apr 21, 2026
@TerrysPOV
Copy link
Copy Markdown
Collaborator

TerrysPOV commented Apr 21, 2026

Vision: PARTIAL — fork agent is lightweight but auto-routing silently switches to Haiku without user awareness, violating the "no hidden implicit behaviors" principle.

Overlapping PRs: #76 (modifies activeProc tracking in runner.ts — significant merge conflict risk), #82 (session isolation changes in runner.ts — moderate merge conflict risk)

Code review

Found 3 issues:

  1. activeProc overwritten by fork: /kill targets wrong processrunFork calls runClaudeOnce, which unconditionally sets activeProc = proc. If a fork spawns while the main agent is running, activeProc is overwritten to the fork's subprocess. A subsequent /kill kills the fork and leaves the main agent running as an untrackable orphan.

claudeclaw/src/runner.ts

Lines 109 to 117 in 0f1f920

activeProc = proc;
const [rawStdout, stderr] = await Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
]);
await proc.exited;
if (activeProc === proc) activeProc = null;

  1. Auto-routing silently switches model and context with no notification — When isMainBusy() is true, the message routes to a Haiku fork with a completely different system prompt, with no indication to the user. The response comes from a different model with different capabilities and no main-session context.

const prefixedPrompt = promptParts.join("\n");
const busy = isMainBusy();
const result = busy
? await runFork(prefixedPrompt)
: await runUserMessage("telegram", prefixedPrompt);
if (result.exitCode !== 0) {

  1. Fork auto-routing is always-on with no opt-in gate — Busy-check routing activates for all users on upgrade with no settings.json flag to disable or opt in. This contradicts the established pattern (see feat: Telegram topic/thread support + suppress HEARTBEAT_OK noise #15, Add agentic model routing for intelligent task-based model selection #17) where new routing behaviors must be opt-in.

const prefixedPrompt = promptParts.join("\n");
const busy = isMainBusy();
const result = busy
? await runFork(prefixedPrompt)
: await runUserMessage("telegram", prefixedPrompt);
if (result.exitCode !== 0) {


Closing in favour of #76. The fork agent idea is interesting, but this implementation has two blockers: (1) auto-routing silently switches to Haiku with no user notification — violates the "no hidden implicit behaviors" principle; (2) the feature is always-on with no settings.json opt-in, against the pattern from #15/#17. If you want to resubmit: make routing opt-in via settings, notify the user when a message routes to the fork ("Main busy — routing to fork agent"), and keep FORK_MODEL configurable. Happy to review a v2.

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@TerrysPOV TerrysPOV closed this Apr 21, 2026
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