Map legacy "bypassPermissions" config to "auto" at dispatch time; pass-through other modes (acceptEdits, plan, default). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.1 KiB
ClaudeDo.Worker
ASP.NET Core hosted service that executes tasks via Claude CLI in isolated environments.
Architecture
- Program.cs — loads config, inits schema, registers DI, configures SignalR on
/hub, binds to127.0.0.1:47821 - QueueService —
BackgroundServicewith two execution slots:- Queue slot: FIFO sequential processing of "agent"-tagged queued tasks
- Override slot: immediate execution via
RunNow(taskId) - Wake signaling via
SemaphoreSlim, backstop timer (30s default)
- StaleTaskRecovery — startup-only service, flips orphaned "running" tasks to "failed"
Task Execution Pipeline
TaskRunner orchestrates:
- Load task + list metadata from DB; resolve config from
list_config+ task-level overrides (model, system_prompt, agent_path) - Create worktree (if
WorkingDirset) or sandbox directory - Mark task "running", broadcast
TaskStarted - Build CLI args via
ClaudeArgsBuilder; invokeClaudeProcesswith task prompt - Stream NDJSON output through
StreamAnalyzer; lines forwarded to log file and SignalR (TaskMessage) - On success: auto-commit changes (worktree only), store run record, mark "done"
- On failure: retry once if session ID available (
--resume), then mark "failed"
Key Components
- ClaudeProcess — spawns
claude -p --output-format stream-json --verbose --permission-mode auto(or whatever permission mode the app settings specify). Writes prompt to stdin, reads NDJSON from stdout. Supports CancellationToken (kills process tree). - ClaudeArgsBuilder — dynamically constructs CLI args; supports
--model,--append-system-prompt,--agents,--json-schema,--resume - StreamAnalyzer — parses rich NDJSON output; extracts session_id, token counts, turn counts, result text, structured output. Replaces MessageParser.
- TaskResetService — discards a failed task's worktree and resets the task row to Manual; preserves run history.
- WorktreeManager — creates worktrees at
claudedo/{taskId[:8]}branches, commits changes with semantic messages, updates DB with head commit and diff stats - CommitMessageBuilder — formats
{commitType}(slug): title\n\ndescription\n\nClaudeDo-Task: taskId - AgentFileService — manages
~/.todo-app/agents/*.mdagent definition files; exposes list/refresh via SignalR - LogWriter — async StreamWriter wrapper, auto-creates parent dirs
Execution History
Each CLI invocation is recorded in the task_runs table via TaskRunRepository:
- Fields:
session_id, input/output/cache token counts, turn count,resulttext, structured output JSON - Enables auto-retry on failure (resume last session) and multi-turn follow-up via
ContinueAsync
Multi-Turn / Continue
TaskRunner.ContinueAsync sends a follow-up prompt to an existing Claude session using --resume <session_id> with the stored session ID from the last run.
SignalR Hub
WorkerHub methods: Ping, GetActive, RunNow, CancelTask, WakeQueue, ContinueTask, ResetTask, GetAgents, RefreshAgents, GetAppSettings, UpdateAppSettings, CleanupFinishedWorktrees, ResetAllWorktrees, MergeTask, GetMergeTargets, UpdateList, UpdateListConfig, GetListConfig, UpdateTaskAgentSettings
HubBroadcaster events: TaskStarted, TaskFinished, TaskMessage, WorktreeUpdated, TaskUpdated, RunCreated, ListUpdated
Config
Loaded from ~/.todo-app/worker.config.json:
db_path,sandbox_root,log_rootworktree_root_strategy("sibling" | "central"),central_worktree_rootqueue_backstop_interval_ms(default 30000)signalr_port(default 47821)claude_bin(path to claude CLI)
Per-list config (list_config in DB) provides defaults for model, system_prompt, agent_path; tasks can override each individually.
Notes
- The worker runs standalone — start it separately from the UI
- Only listens on loopback (127.0.0.1)
- ClaudeProcess uses
--permission-mode autoby default; legacy "bypassPermissions" settings are mapped toautoat dispatch time.acceptEdits,plan, anddefaultpass through unchanged. - Worktree branches follow
claudedo/{id}naming convention