Problem
The current tool assignment matrix creates dead-end delegation chains — a process gets delegated work but lacks the tools to complete it, so it delegates again, and the next process has even less context. Basic multi-step workflows that should complete in one hop require three or more hops, with context lost at each handoff.
Concrete failure scenario
- User asks Spacebot to sync open GitHub PRs with the internal taskboard
- Channel spawns a worker to gather PR data (correct — workers have shell/file tools)
- Worker runs
gh CLI, gathers data, writes a comprehensive analysis file to its workspace, reports summary back to channel
- User confirms: "yes, create the tasks"
- Channel can't create tasks (no task tools) → branches to think about it
- Branch has
task_create but no file tools → can't read the analysis file the worker wrote → spawns another worker to read the file
- New worker has file tools, reads the analysis file, but has no
task_create → has no idea about the internal taskboard → starts calling gh CLI looking for a GitHub Projects board
- Complete failure. Three hops, context lost at every handoff.
The worker that gathered the data should have been able to create tasks directly. Alternatively, the branch should have been able to read the file. Either path would have completed the workflow.
Root cause
Two critical gaps in the tool assignment matrix:
Gap 1: Workers cannot create or list tasks
Workers are the processes that do actual work — gathering data, running commands, producing artifacts. But they have no way to register outcomes on the internal taskboard.
The only task tool workers get is TaskUpdateTool::for_worker(), which is restricted to subtask/metadata updates on the worker's own assigned task (src/tools/task_update.rs:149-181). Workers cannot:
- Create new tasks (
task_create)
- List existing tasks (
task_list)
- Update the status/title/description of any task (including tasks they created)
Current worker tool registration (src/tools.rs:571-620):
ShellTool, TaskUpdateTool::for_worker (restricted), SetStatusTool, ReadSkillTool,
FileReadTool, FileWriteTool, FileEditTool, FileListTool,
SecretSetTool (conditional), Browser tools (conditional), WebSearchTool (conditional),
MCP tools (conditional)
Gap 2: Branches cannot read files
Branches are the thinking layer — they have the channel's full context, recall memories, make decisions, and create tasks. But if a worker produced results as files (which is what workers naturally do), a branch is completely blind to them. It must spawn yet another worker just to read a file, and that worker lacks the branch's context.
Current branch tool registration (src/tools.rs:514-560):
MemorySaveTool, MemoryRecallTool, MemoryDeleteTool, ChannelRecallTool,
SpacebotDocsTool, EmailSearchTool, WorkerInspectTool,
TaskCreateTool, TaskListTool, TaskUpdateTool::for_branch,
MemoryPersistenceCompleteTool (conditional), SpawnWorkerTool (conditional)
No file tools at all.
Proposed changes
1. Give workers task_create and task_list (high priority)
In create_worker_tool_server() (src/tools.rs:571), add:
TaskCreateTool::new(task_store, agent_id, "worker")
TaskListTool::new(task_store, agent_id)
This requires threading task_store and agent_id through from the existing params (both are already available — task_store is passed for TaskUpdateTool::for_worker() at line 587, and agent_id is passed at line 572).
The worker system prompt should mention the internal taskboard and these tools so the LLM knows to use them instead of looking for external project management.
Consider also: upgrading TaskUpdateTool::for_worker() to allow status changes on tasks the worker created (not just its assigned task). Currently the guard at src/tools/task_update.rs:149-181 only allows the worker to update task_store.get_by_worker_id(), and restricts updates to subtasks/metadata. A worker that creates 10 tasks from gathered data should be able to update their status too.
2. Give branches read-only file tools (high priority)
In create_branch_tool_server() (src/tools.rs:514), add:
FileReadTool
FileListTool
Not FileWriteTool or FileEditTool — branches think, they don't execute. Read-only access is the correct boundary.
This requires adding workspace: PathBuf and sandbox: Arc<Sandbox> to the function signature. The call site in channel_dispatch.rs:257 has access to both via state.deps.runtime_config.workspace_dir and state.deps.sandbox.
3. Consider giving workers memory_save (medium priority)
Workers gather information and produce results, but can't persist memories. A worker doing research writes to files that may never be read. If it could save key findings as memories, those findings would be available to future branches via memory_recall.
The compactor worker already gets memory_save via create_cortex_tool_server() (src/tools.rs:626-638). Extending this to task workers is the same pattern — add a MemorySaveTool with the memory event bus.
This is a secondary priority and could be a separate PR.
Affected code locations
| File |
Lines |
What to change |
src/tools.rs |
571-620 |
create_worker_tool_server() — add TaskCreateTool, TaskListTool |
src/tools.rs |
514-560 |
create_branch_tool_server() — add FileReadTool, FileListTool, expand signature |
src/tools.rs |
1-30 |
Module doc comment — update topology docs |
src/agent/channel_dispatch.rs |
257-268 |
Call site — pass workspace and sandbox to branch tool server |
src/tools/task_update.rs |
149-181 |
Worker scope guard — optionally allow status updates on worker-created tasks |
src/tools/task_create.rs |
1 |
Doc comment says "for branch processes" — update |
| Worker system prompt (prompts/) |
— |
Mention internal taskboard tools |
AGENTS.md |
Module Map, tools list |
Update tool assignments per process type |
README.md |
Process table |
Update "What Each Process Gets" table |
What NOT to change
- Channels stay delegation-only. No task tools, no file tools, no memory tools. The ambassador model is correct.
- Workers should NOT get
memory_recall or channel context. Fresh prompt + task description is the right model.
- Branches should NOT get
file_write/file_edit/shell. They think, they don't execute.
Full current tool matrix (for reference)
| Tool |
Channel |
Branch |
Worker |
Compactor |
Cortex Chat |
reply |
Yes* |
- |
- |
- |
- |
branch |
Yes |
- |
- |
- |
- |
spawn_worker |
Yes |
Yes** |
- |
- |
Yes |
route |
Yes |
- |
- |
- |
- |
cancel |
Yes |
- |
- |
- |
- |
skip |
Yes |
- |
- |
- |
- |
react |
Yes |
- |
- |
- |
- |
memory_save |
- |
Yes |
- |
Yes |
Yes |
memory_recall |
- |
Yes |
- |
- |
Yes |
memory_delete |
- |
Yes |
- |
- |
Yes |
channel_recall |
- |
Yes |
- |
- |
Yes |
spacebot_docs |
- |
Yes |
- |
- |
Yes |
task_create |
- |
Yes |
MISSING |
- |
Yes |
task_list |
- |
Yes |
MISSING |
- |
Yes |
task_update |
- |
Yes (full) |
Yes (restricted) |
- |
Yes (full) |
file_read |
- |
MISSING |
Yes |
- |
Yes |
file_list |
- |
MISSING |
Yes |
- |
Yes |
file_write |
- |
- |
Yes |
- |
Yes |
file_edit |
- |
- |
Yes |
- |
Yes |
shell |
- |
- |
Yes |
- |
Yes |
set_status |
- |
- |
Yes |
- |
- |
*Conditional on config/state — see add_channel_tools() in src/tools.rs:348-445 for details.
**Branch spawn_worker only available for channel-originated branches.
Related
Problem
The current tool assignment matrix creates dead-end delegation chains — a process gets delegated work but lacks the tools to complete it, so it delegates again, and the next process has even less context. Basic multi-step workflows that should complete in one hop require three or more hops, with context lost at each handoff.
Concrete failure scenario
ghCLI, gathers data, writes a comprehensive analysis file to its workspace, reports summary back to channeltask_createbut no file tools → can't read the analysis file the worker wrote → spawns another worker to read the filetask_create→ has no idea about the internal taskboard → starts callingghCLI looking for a GitHub Projects boardThe worker that gathered the data should have been able to create tasks directly. Alternatively, the branch should have been able to read the file. Either path would have completed the workflow.
Root cause
Two critical gaps in the tool assignment matrix:
Gap 1: Workers cannot create or list tasks
Workers are the processes that do actual work — gathering data, running commands, producing artifacts. But they have no way to register outcomes on the internal taskboard.
The only task tool workers get is
TaskUpdateTool::for_worker(), which is restricted to subtask/metadata updates on the worker's own assigned task (src/tools/task_update.rs:149-181). Workers cannot:task_create)task_list)Current worker tool registration (
src/tools.rs:571-620):Gap 2: Branches cannot read files
Branches are the thinking layer — they have the channel's full context, recall memories, make decisions, and create tasks. But if a worker produced results as files (which is what workers naturally do), a branch is completely blind to them. It must spawn yet another worker just to read a file, and that worker lacks the branch's context.
Current branch tool registration (
src/tools.rs:514-560):No file tools at all.
Proposed changes
1. Give workers
task_createandtask_list(high priority)In
create_worker_tool_server()(src/tools.rs:571), add:TaskCreateTool::new(task_store, agent_id, "worker")TaskListTool::new(task_store, agent_id)This requires threading
task_storeandagent_idthrough from the existing params (both are already available —task_storeis passed forTaskUpdateTool::for_worker()at line 587, andagent_idis passed at line 572).The worker system prompt should mention the internal taskboard and these tools so the LLM knows to use them instead of looking for external project management.
Consider also: upgrading
TaskUpdateTool::for_worker()to allow status changes on tasks the worker created (not just its assigned task). Currently the guard atsrc/tools/task_update.rs:149-181only allows the worker to updatetask_store.get_by_worker_id(), and restricts updates to subtasks/metadata. A worker that creates 10 tasks from gathered data should be able to update their status too.2. Give branches read-only file tools (high priority)
In
create_branch_tool_server()(src/tools.rs:514), add:FileReadToolFileListToolNot
FileWriteToolorFileEditTool— branches think, they don't execute. Read-only access is the correct boundary.This requires adding
workspace: PathBufandsandbox: Arc<Sandbox>to the function signature. The call site inchannel_dispatch.rs:257has access to both viastate.deps.runtime_config.workspace_dirandstate.deps.sandbox.3. Consider giving workers
memory_save(medium priority)Workers gather information and produce results, but can't persist memories. A worker doing research writes to files that may never be read. If it could save key findings as memories, those findings would be available to future branches via
memory_recall.The compactor worker already gets
memory_saveviacreate_cortex_tool_server()(src/tools.rs:626-638). Extending this to task workers is the same pattern — add aMemorySaveToolwith the memory event bus.This is a secondary priority and could be a separate PR.
Affected code locations
src/tools.rscreate_worker_tool_server()— addTaskCreateTool,TaskListToolsrc/tools.rscreate_branch_tool_server()— addFileReadTool,FileListTool, expand signaturesrc/tools.rssrc/agent/channel_dispatch.rsworkspaceandsandboxto branch tool serversrc/tools/task_update.rssrc/tools/task_create.rsAGENTS.mdREADME.mdWhat NOT to change
memory_recallor channel context. Fresh prompt + task description is the right model.file_write/file_edit/shell. They think, they don't execute.Full current tool matrix (for reference)
replybranchspawn_workerroutecancelskipreactmemory_savememory_recallmemory_deletechannel_recallspacebot_docstask_createtask_listtask_updatefile_readfile_listfile_writefile_editshellset_status*Conditional on config/state — see
add_channel_tools()insrc/tools.rs:348-445for details.**Branch
spawn_workeronly available for channel-originated branches.Related
task_updatereturns "success" but status doesn't change for branch-created tasks (may share root cause with task scoping)