@scemoon/cdh 1.0.0 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/cdh/__pycache__/cli.cpython-314.pyc +0 -0
  2. package/cdh/__pycache__/scaffold.cpython-314.pyc +0 -0
  3. package/cdh/cli.py +473 -87
  4. package/cdh/scaffold.py +386 -121
  5. package/onecode/__pycache__/cli.cpython-314.pyc +0 -0
  6. package/onecode/__pycache__/commands.cpython-314.pyc +0 -0
  7. package/onecode/__pycache__/config.cpython-314.pyc +0 -0
  8. package/onecode/agent/__pycache__/cdh_loader.cpython-314.pyc +0 -0
  9. package/onecode/agent/__pycache__/engine.cpython-314.pyc +0 -0
  10. package/onecode/agent/__pycache__/onecode_agent_acp.cpython-314.pyc +0 -0
  11. package/onecode/agent/__pycache__/session.cpython-314.pyc +0 -0
  12. package/onecode/agent/agents/__pycache__/types.cpython-314.pyc +0 -0
  13. package/onecode/agent/agents/types.py +123 -79
  14. package/onecode/agent/cdh_loader.py +26 -13
  15. package/onecode/agent/engine.py +426 -235
  16. package/onecode/agent/onecode_agent_acp.py +202 -75
  17. package/onecode/agent/session.py +8 -13
  18. package/onecode/agent/tools/__pycache__/agent_tools.cpython-314.pyc +0 -0
  19. package/onecode/agent/tools/__pycache__/todo_tools.cpython-314.pyc +0 -0
  20. package/onecode/agent/tools/agent_tools.py +4 -4
  21. package/onecode/agent/tools/todo_tools.py +188 -0
  22. package/onecode/cli.py +3 -3
  23. package/onecode/commands.py +439 -194
  24. package/onecode/config.py +3 -3
  25. package/onecode/config_screen.py +4 -2
  26. package/onecode/models/__pycache__/errors.cpython-314.pyc +0 -0
  27. package/onecode/models/__pycache__/messages.cpython-314.pyc +0 -0
  28. package/onecode/models/__pycache__/provider.cpython-314.pyc +0 -0
  29. package/onecode/models/errors.py +11 -1
  30. package/onecode/models/messages.py +35 -16
  31. package/onecode/models/provider.py +243 -12
  32. package/onecode/models/providers/__pycache__/anthropic_provider.cpython-314.pyc +0 -0
  33. package/onecode/models/providers/__pycache__/deepseek_provider.cpython-314.pyc +0 -0
  34. package/onecode/models/providers/__pycache__/glm_provider.cpython-314.pyc +0 -0
  35. package/onecode/models/providers/__pycache__/minimax_provider.cpython-314.pyc +0 -0
  36. package/onecode/models/providers/__pycache__/minimaxi_provider.cpython-314.pyc +0 -0
  37. package/onecode/models/providers/__pycache__/ollama_provider.cpython-314.pyc +0 -0
  38. package/onecode/models/providers/__pycache__/openai_provider.cpython-314.pyc +0 -0
  39. package/onecode/models/providers/anthropic_provider.py +4 -2
  40. package/onecode/models/providers/deepseek_provider.py +2 -0
  41. package/onecode/models/providers/glm_provider.py +2 -1
  42. package/onecode/models/providers/minimax_provider.py +2 -1
  43. package/onecode/models/providers/minimaxi_provider.py +76 -25
  44. package/onecode/models/providers/ollama_provider.py +2 -1
  45. package/onecode/models/providers/openai_provider.py +4 -0
  46. package/onecode/tasks/manager.py +1 -1
  47. package/package.json +1 -1
  48. package/pyproject.toml +10 -0
  49. package/run.js +24 -7
  50. package/tui/__pycache__/agents.cpython-314.pyc +0 -0
  51. package/tui/__pycache__/app.cpython-314.pyc +0 -0
  52. package/tui/__pycache__/db.cpython-314.pyc +0 -0
  53. package/tui/__pycache__/directory_watcher.cpython-314.pyc +0 -0
  54. package/tui/__pycache__/messages.cpython-314.pyc +0 -0
  55. package/tui/__pycache__/paths.cpython-314.pyc +0 -0
  56. package/tui/__pycache__/settings_schema.cpython-314.pyc +0 -0
  57. package/tui/acp/__pycache__/agent.cpython-314.pyc +0 -0
  58. package/tui/acp/__pycache__/api.cpython-314.pyc +0 -0
  59. package/tui/acp/__pycache__/messages.cpython-314.pyc +0 -0
  60. package/tui/acp/__pycache__/prompt.cpython-314.pyc +0 -0
  61. package/tui/acp/__pycache__/protocol.cpython-314.pyc +0 -0
  62. package/tui/acp/agent.py +60 -11
  63. package/tui/acp/api.py +6 -0
  64. package/tui/acp/messages.py +11 -0
  65. package/tui/acp/prompt.py +1 -1
  66. package/tui/acp/protocol.py +31 -0
  67. package/tui/agents.py +8 -7
  68. package/tui/app.py +60 -8
  69. package/tui/data/agents/ampcode.com.toml +1 -0
  70. package/tui/data/agents/augmentcode.com.toml +1 -0
  71. package/tui/data/agents/cdh.cloud-dev-harness.toml +3 -2
  72. package/tui/data/agents/crowai.dev.toml +1 -0
  73. package/tui/data/agents/deepagents.langchain.com +1 -0
  74. package/tui/data/agents/docker.com.toml +1 -0
  75. package/tui/data/agents/goose.ai.toml +1 -0
  76. package/tui/data/agents/inference.huggingface.co.toml +1 -1
  77. package/tui/data/agents/kiro.dev.toml +1 -0
  78. package/tui/data/agents/onecode.dev.toml +22 -0
  79. package/tui/data/agents/openclaw.ai.toml +1 -1
  80. package/tui/data/agents/openhands.dev.toml +1 -0
  81. package/tui/data/agents/stakpak.dev.toml +1 -0
  82. package/tui/data/agents/vibe.mistral.ai.toml +1 -0
  83. package/tui/data/agents/vtcode.dev.toml +1 -0
  84. package/tui/db.py +23 -0
  85. package/tui/directory_watcher.py +35 -1
  86. package/tui/messages.py +4 -1
  87. package/tui/paths.py +3 -3
  88. package/tui/screens/__pycache__/main.cpython-314.pyc +0 -0
  89. package/tui/screens/component_picker.py +148 -0
  90. package/tui/screens/main.py +47 -95
  91. package/tui/screens/projects.tcss +10 -0
  92. package/tui/screens/projects_app.py +33 -5
  93. package/tui/screens/projects_screen.py +171 -9
  94. package/tui/screens/store.py +1 -1
  95. package/tui/settings_schema.py +1 -1
  96. package/tui/widgets/__pycache__/ask_user.cpython-314.pyc +0 -0
  97. package/tui/widgets/__pycache__/conversation.cpython-314.pyc +0 -0
  98. package/tui/widgets/__pycache__/modified_files.cpython-314.pyc +0 -0
  99. package/tui/widgets/__pycache__/plan.cpython-314.pyc +0 -0
  100. package/tui/widgets/__pycache__/project_directory_tree.cpython-314.pyc +0 -0
  101. package/tui/widgets/__pycache__/question.cpython-314.pyc +0 -0
  102. package/tui/widgets/__pycache__/subagent.cpython-314.pyc +0 -0
  103. package/tui/widgets/__pycache__/tool_call.cpython-314.pyc +0 -0
  104. package/tui/widgets/ask_user.py +1 -1
  105. package/tui/widgets/conversation.py +99 -42
  106. package/tui/widgets/modified_files.py +191 -65
  107. package/tui/widgets/plan.py +22 -0
  108. package/tui/widgets/project_directory_tree.py +22 -10
  109. package/tui/widgets/project_grid_select.py +23 -1
  110. package/tui/widgets/question.py +1 -1
  111. package/tui/widgets/subagent.py +202 -36
  112. package/tui/widgets/subagent_screen.py +186 -0
  113. package/tui/widgets/tool_call.py +5 -8
  114. package/cdh/__pycache__/__init__.cpython-313.pyc +0 -0
  115. package/cdh/__pycache__/scaffold.cpython-313.pyc +0 -0
  116. package/onecode/__pycache__/config_screen.cpython-314.pyc +0 -0
  117. package/onecode/__pycache__/mock_data.cpython-314.pyc +0 -0
  118. package/onecode/agent/__pycache__/cdh_agent_acp.cpython-313.pyc +0 -0
  119. package/onecode/agent/__pycache__/cdh_agent_acp.cpython-314.pyc +0 -0
  120. package/onecode/agent/__pycache__/harness_skill.cpython-314.pyc +0 -0
  121. package/onecode/agent/tools/__pycache__/task_tools.cpython-314.pyc +0 -0
  122. package/onecode/agent/tools/task_tools.py +0 -249
  123. package/onecode/codebase/__pycache__/config.cpython-314.pyc +0 -0
  124. package/onecode/models/providers/__pycache__/mock_provider.cpython-314.pyc +0 -0
  125. package/onecode/skills/__pycache__/manager.cpython-314.pyc +0 -0
  126. package/tui/__pycache__/danger.cpython-314.pyc +0 -0
  127. package/tui/__pycache__/directory_suggester.cpython-314.pyc +0 -0
  128. package/tui/screens/__pycache__/log.cpython-314.pyc +0 -0
  129. package/tui/screens/__pycache__/projects_screen.cpython-314.pyc +0 -0
  130. package/tui/screens/__pycache__/sessions.cpython-314.pyc +0 -0
  131. package/tui/screens/__pycache__/settings.cpython-314.pyc +0 -0
  132. package/tui/screens/__pycache__/store.cpython-314.pyc +0 -0
  133. package/tui/widgets/__pycache__/acp_content.cpython-314.pyc +0 -0
  134. package/tui/widgets/__pycache__/conversation.cpython-313.pyc +0 -0
  135. package/tui/widgets/__pycache__/diff_view.cpython-314.pyc +0 -0
  136. package/tui/widgets/__pycache__/directory_input.cpython-314.pyc +0 -0
  137. package/tui/widgets/__pycache__/future_text.cpython-314.pyc +0 -0
  138. package/tui/widgets/__pycache__/grid_select.cpython-314.pyc +0 -0
  139. package/tui/widgets/__pycache__/mandelbrot.cpython-314.pyc +0 -0
  140. package/tui/widgets/__pycache__/markdown_note.cpython-314.pyc +0 -0
  141. package/tui/widgets/__pycache__/project_grid_select.cpython-314.pyc +0 -0
  142. package/tui/widgets/__pycache__/project_summary.cpython-314.pyc +0 -0
  143. package/tui/widgets/__pycache__/session_grid_select.cpython-314.pyc +0 -0
  144. package/tui/widgets/__pycache__/session_summary.cpython-314.pyc +0 -0
  145. package/tui/widgets/__pycache__/shell_result.cpython-314.pyc +0 -0
  146. package/tui/widgets/__pycache__/terminal.cpython-313.pyc +0 -0
  147. package/tui/widgets/__pycache__/tool_call.cpython-313.pyc +0 -0
@@ -114,7 +114,12 @@ class BuildAgent(AgentConfig):
114
114
  def __init__(self):
115
115
  super().__init__(
116
116
  name="build",
117
- description="Full development agent with all tools enabled. Edits and shell commands require user approval. Uses CoT reasoning + ReAct loop with Task-first delegation.",
117
+ description=(
118
+ "Full development agent with all tools enabled. Edits and shell "
119
+ "commands require user approval. Uses CoT reasoning + ReAct loop "
120
+ "with routing by complexity: simple work → TodoCreate, complex "
121
+ "work → Spawn subagent."
122
+ ),
118
123
  mode=AgentMode.PRIMARY,
119
124
  permission_edit=AgentPermission.ASK,
120
125
  permission_bash=AgentPermission.ASK,
@@ -131,7 +136,13 @@ class PlanAgent(AgentConfig):
131
136
  def __init__(self):
132
137
  super().__init__(
133
138
  name="plan",
134
- description="Plan mode: CoT + ReAct (思考→行动→观察) agent with hard plan gate and Task-first delegation. Creates task plans first, presents for user review, then delegates execution via Task subagents with Human-in-the-loop.",
139
+ description=(
140
+ "Plan mode: CoT + ReAct (思考→行动→观察) agent with hard plan "
141
+ "gate. Creates a todo plan first via TodoCreate, presents for "
142
+ "user review, then routes execution by complexity: simple todos "
143
+ "run directly, complex todos are delegated to Spawn subagents. "
144
+ "Human-in-the-loop."
145
+ ),
135
146
  mode=AgentMode.PRIMARY,
136
147
  permission_edit=AgentPermission.ASK,
137
148
  permission_bash=AgentPermission.ASK,
@@ -148,7 +159,12 @@ class SoloAgent(AgentConfig):
148
159
  def __init__(self):
149
160
  super().__init__(
150
161
  name="solo",
151
- description="Independent agent that plans first, then acts with full tool access. Uses CoT reasoning + ReAct loop with Task-first delegation. Shell commands require user approval.",
162
+ description=(
163
+ "Independent agent that plans first, then acts with full tool "
164
+ "access. Uses CoT reasoning + ReAct loop with routing by "
165
+ "complexity: simple work → TodoCreate, complex work → Spawn "
166
+ "subagent. Shell commands require user approval."
167
+ ),
152
168
  mode=AgentMode.PRIMARY,
153
169
  permission_edit=AgentPermission.ALLOW,
154
170
  permission_bash=AgentPermission.ASK,
@@ -165,13 +181,19 @@ class GeneralAgent(AgentConfig):
165
181
  def __init__(self):
166
182
  super().__init__(
167
183
  name="general",
168
- description="General-purpose subagent for complex multi-step tasks. Executes focused work delegated by parent agent via Task tool. Uses CoT + ReAct internally.",
184
+ description=(
185
+ "General-purpose subagent for complex multi-step tasks. Executes "
186
+ "focused work delegated by parent agent via Spawn tool. Uses "
187
+ "CoT + ReAct internally."
188
+ ),
169
189
  mode=AgentMode.SUBAGENT,
170
190
  permission_edit=AgentPermission.ALLOW,
171
191
  permission_bash=AgentPermission.ALLOW,
172
192
  permission_read=AgentPermission.ALLOW,
193
+ permission_task=AgentPermission.DENY,
194
+ permission_question=AgentPermission.DENY,
173
195
  permission_todowrite=AgentPermission.DENY,
174
- tools=[],
196
+ disallowed_tools=["Spawn", "Agent", "AskUser"],
175
197
  )
176
198
 
177
199
 
@@ -184,8 +206,11 @@ class ExploreAgent(AgentConfig):
184
206
  permission_edit=AgentPermission.DENY,
185
207
  permission_bash=AgentPermission.DENY,
186
208
  permission_read=AgentPermission.ALLOW,
209
+ permission_task=AgentPermission.DENY,
210
+ permission_question=AgentPermission.DENY,
211
+ permission_todowrite=AgentPermission.DENY,
212
+ disallowed_tools=["Spawn", "Agent", "AskUser"],
187
213
  hidden=True,
188
- tools=[],
189
214
  )
190
215
 
191
216
 
@@ -200,8 +225,11 @@ class ScoutAgent(AgentConfig):
200
225
  permission_read=AgentPermission.ALLOW,
201
226
  permission_webfetch=AgentPermission.ALLOW,
202
227
  permission_websearch=AgentPermission.ALLOW,
228
+ permission_task=AgentPermission.DENY,
229
+ permission_question=AgentPermission.DENY,
230
+ permission_todowrite=AgentPermission.DENY,
231
+ disallowed_tools=["Spawn", "Agent", "AskUser"],
203
232
  hidden=True,
204
- tools=[],
205
233
  )
206
234
 
207
235
 
@@ -291,6 +319,19 @@ def get_agent_by_name(name: str) -> Optional[AgentConfig]:
291
319
  return None
292
320
 
293
321
 
322
+ SUBAGENT_CONSTRAINTS = """
323
+ ### Constraints (subagent)
324
+ You are running as a subagent spawned by a parent agent via the Spawn tool.
325
+ - You CANNOT spawn subagents (Spawn tool is disabled).
326
+ - You CANNOT execute batched tool calls (Agent tool is disabled).
327
+ - You CANNOT manage task plans (TodoCreate/TodoUpdate/TodoStop are disabled).
328
+ - You CANNOT interact with the user (AskUser is disabled).
329
+ - You are a leaf node in the agent hierarchy. Execute the task in your prompt
330
+ and return a structured SUMMARY/CHANGES/EVIDENCE/RISKS/BLOCKERS response.
331
+ - Do not narrate "I will now..." in visible text; all reasoning in <thinking>.
332
+ """
333
+
334
+
294
335
  def get_system_prompt(agent_type: str) -> str:
295
336
  agent = create_agent(agent_type)
296
337
  lines = [
@@ -303,6 +344,9 @@ def get_system_prompt(agent_type: str) -> str:
303
344
  if agent.should_ask_for_bash():
304
345
  lines.append("- Shell commands require user approval")
305
346
 
347
+ if agent.mode == AgentMode.SUBAGENT:
348
+ lines.append(SUBAGENT_CONSTRAINTS)
349
+
306
350
  return "\n".join(lines)
307
351
 
308
352
 
@@ -426,15 +470,13 @@ Rules:
426
470
  - **ConfigWrite**: config_write(key, value) - Set allowed configuration values (does NOT expose secrets).
427
471
 
428
472
  ### Tasks & Planning (CDH)
429
- - **TaskCreate**: task_create(subject, description, activeForm="", metadata={}) - Create a task. Returns task id.
430
- - **TaskGet**: task_get(taskId) - Retrieve a task by ID.
431
- - **TaskList**: task_list() - List all tasks with status, owner, and blockers.
432
- - **TaskUpdate**: task_update(taskId, subject, description, activeForm, status, owner, addBlocks, addBlockedBy, metadata, output) - Update task fields and dependencies.
433
- - **TaskOutput**: task_output(task_id) - Get output from a task.
434
- - **TaskStop**: task_stop(task_id) - Stop a running task.
435
- - **TodoCreate**: todo_create(text) - Create a todo item. Returns todo id.
436
- - **TodoList**: todo_list() - List all todos.
437
- - **TodoComplete**: todo_complete(todo_id) - Mark a todo as complete.
473
+ - **TodoCreate**: todo_create(subject, description, activeForm="", metadata={}) - Create a task. Returns task id.
474
+ - **TodoGet**: todo_get(taskId) - Retrieve a task by ID.
475
+ - **TodoList**: todo_list() - List all tasks with status, owner, and blockers.
476
+ - **TodoUpdate**: todo_update(taskId, subject, description, activeForm, status, owner, addBlocks, addBlockedBy, metadata, output) - Update task fields and dependencies.
477
+ - **TodoOutput**: todo_output(task_id) - Get output from a task.
478
+ - **TodoStop**: todo_stop(task_id) - Stop a running task.
479
+ - **Spawn**: spawn(agent_type, prompt) - Delegate a subtask to a specialized subagent.
438
480
  """
439
481
 
440
482
  def filter_tool_descriptions(
@@ -498,29 +540,31 @@ Before any action, reason step by step inside `<thinking>`:
498
540
  1. **Current state**: What do I know? What has been done? What are the results?
499
541
  2. **Goal**: What needs to be accomplished next?
500
542
  3. **Plan**: How should I approach it? What's the smallest next step?
501
- 4. **Tool selection**: Which tool is appropriate?
502
- - **For multi-step or independent work always use `Task`** to spawn a subagent
503
- - For simple queries use read/search tools directly
504
- - For execution (Write/Edit/Insert/ApplyPatch/Bash)prefer delegating via `Task`
543
+ 4. **Routing choose by complexity**:
544
+ - **Simple / single-step** → use a direct read/search/exec tool, optionally
545
+ track with `TodoCreate` so the sidebar shows progress.
546
+ - **Complex / multi-step** use `Spawn(agent_type, prompt)` to delegate to
547
+ a focused subagent.
548
+ - **Multi-file refactor / new feature** → ALWAYS use `Spawn`.
505
549
 
506
550
  ### Action Phase (行动阶段)
507
551
  Execute the chosen action. **Action types (in priority order)**:
508
- 1. **Delegate via Task**: `Task(agent_type="general"|"explore"|"scout", prompt="...")` — **preferred for any substantial work**. Multi-step logic, file modifications, research, and any task that needs >1-2 tool calls should be delegated.
509
- 2. **Plan**: `task_create()` / `task_update()` / `todo_create()` to organize the work DAG.
510
- 3. **Research**: `Read()` / `Grep()` / `Glob()` / `WebFetch()` / `WebSearch()` for information gathering.
511
- 4. **Direct execute**: Only for trivial single-step operations that cannot justify a subagent.
552
+ 1. **Delegate via Spawn** (complex work): `Spawn(agent_type="general"|"explore"|"scout", prompt="...")`.
553
+ 2. **Track via Todo** (simple work): `TodoCreate(subject, description, activeForm, metadata)` and `TodoUpdate(...)`. The sidebar shows progress to the user.
554
+ 3. **Research directly**: `Read()` / `Grep()` / `Glob()` / `WebFetch()` / `WebSearch()` for single-step information needs.
555
+ 4. **Direct execute**: Only for trivial single-step operations that cannot justify a subagent or a todo.
512
556
 
513
557
  ### Observation Phase (观察阶段)
514
558
  The tool result IS your observation. Process it:
515
- - **Success**: Note key outputs, update task status, move to next step
559
+ - **Success**: Note key outputs, update todo status via `TodoUpdate(status="completed")`, move to next step
516
560
  - **Error**: Diagnose root cause, decide: retry with fix | modify plan | ask user
517
561
  - **Partial**: Extract what worked, adjust approach for remaining work
518
562
 
519
563
  ### Core Rules
520
564
  - **ALL reasoning goes in `<thinking>`**: Never narrate "I will now..." in visible text
521
- - **Prefer Task over direct execution**: File edits, multi-step logic, researchalways use `Task()`
522
- - **One responsibility per Task**: Each subagent should have a clear, focused goal
523
- - **Pass context**: Include relevant context (file paths, findings) in Task prompts
565
+ - **Route by complexity**: Simple Todo, complexSpawn. Never blindly use Spawn for trivial work.
566
+ - **One responsibility per Spawn / Todo**: Each unit should have a clear, focused goal
567
+ - **Pass context**: Include relevant context (file paths, findings) in Spawn prompts and Todo descriptions
524
568
  - **CoT every cycle**: Every turn starts with `<thinking>` reasoning before any action
525
569
  """
526
570
 
@@ -528,26 +572,25 @@ PLAN_INSTRUCTIONS = """
528
572
  ## ReAct Workflow (Thought → Action → Observation)
529
573
 
530
574
  The agent is a **ReAct** implementation: each cycle is **Thought → Action → Observation**.
531
- **Action always delegates to `Task` subagents for any substantial work.**
532
575
  **Human-in-the-loop** means you involve the user at key decision points.
533
576
 
534
577
  ```
535
578
  Loop:
536
579
  Thought → Reason step by step (CoT) inside <thinking>
537
- Always ask: "Should I delegate this to a Task subagent?"
538
- Action → Prefer Task(agent_type, prompt) for multi-step work
539
- Only use direct tools for trivial single-step operations
580
+ Always ask: "Is this simple (Todo) or complex (Spawn)?"
581
+ Action → Simple TodoCreate + direct tool
582
+ Complex Spawn(agent_type, prompt)
540
583
  Observation → Incorporate results into the next Thought
541
584
  ```
542
585
 
543
- Plan/Build/Solo are different configurations of this same ReAct engine. The
544
- difference is how strictly planning is enforced before execution:
545
- - **plan** mode: hard gate — execution tools blocked until a task plan exists
546
- - **build**/**solo** mode: soft gate — execution allowed but planning encouraged
586
+ Plan/Build/Solo are different configurations of this same ReAct engine:
587
+ - **plan** mode: hard gate execution tools blocked until a todo plan exists.
588
+ - **build**/**solo** mode: soft gate — execution allowed but planning encouraged.
547
589
 
548
- **Task-first principle**: Any action that requires >1 tool call or involves
549
- file modification MUST be delegated to a `Task` subagent. Direct execution
550
- (Write/Edit/Insert/ApplyPatch/Bash) is only for trivial single-step operations.
590
+ **Routing principle**:
591
+ - **Simple todo** = 1 tool call, 1 file, ≤2 lines of code change, single Read/Glob. Use `TodoCreate` + direct tool.
592
+ - **Complex work** = >1 tool call, multi-file, research, refactor, new feature. Use `Spawn(agent_type, prompt)`.
593
+ - When in doubt, choose `Spawn`. Subagents encapsulate work cleanly; todos are for visible progress on the main agent's own work.
551
594
 
552
595
  ---
553
596
 
@@ -556,57 +599,58 @@ file modification MUST be delegated to a `Task` subagent. Direct execution
556
599
  Analyze the request with step-by-step reasoning before any action.
557
600
 
558
601
  - Wrap ALL reasoning in `<thinking>...</thinking>` — visible text is for the user only
559
- - Think step by step: What's the goal? What's the current state? What's the best approach?
560
- - **Always consider**: "Can this be delegated to a Task subagent?"
602
+ - Think step by step: What's the goal? What's the current state? Is this simple or complex?
603
+ - **Decide routing**:
604
+ - For simple work → proceed to `TodoCreate` then act directly.
605
+ - For complex work → proceed to spawn subagents.
561
606
  - Read relevant files, grep for patterns, glob for structure
562
607
  - Use `webfetch`/`websearch` for external APIs or docs
563
- - Delegate deep research to `explore`/`scout` subagents via `task()`
564
- - Ask the user via `ask_user()` if requirements are ambiguous
565
- - Do NOT create tasks yet — first understand what is needed
608
+ - Delegate deep research to `explore`/`scout` subagents via `Spawn`
609
+ - Ask the user via `AskUser` if requirements are ambiguous
610
+ - Do NOT create todos yet — first understand what is needed
566
611
 
567
612
  ---
568
613
 
569
- ### Step 2: Act (Plan) — Create the Task Plan
614
+ ### Step 2: Act (Plan) — Create the Todo Plan
570
615
 
571
- Once you understand the work, create a complete task plan via `task_create()`.
616
+ Once you understand the work, create a complete todo plan via `TodoCreate()`.
572
617
 
573
- **Task Granularity Rules**
574
- - One task = one concern (e.g. "Create User model", "Add login API endpoint")
575
- - Each task: **delegate to a Task subagent**. If a task needs >5 tool calls, split it.
576
- - Every task must have a **clear, verifiable completion criterion**
577
- - Use `todo_create()` only for truly trivial items (single config change, one quick check)
618
+ **Routing Granularity Rules**
619
+ - One todo = one focused unit of work (file, function, or concern).
620
+ - Each todo: decide at creation time whether it should be done by the main agent or delegated to a Spawn subagent.
621
+ - Mark delegatable todos with `metadata={"delegate_to": "general"}` so the main agent knows to use `Spawn` for that item.
622
+ - Simple todos (1 tool call) stay with the main agent.
623
+ - If a todo needs >5 tool calls, split it into smaller todos.
578
624
 
579
- **Creating Tasks**
625
+ **Creating Todos**
580
626
  ```
581
- task_create(subject="<verb + noun>", description="<what + acceptance criteria>",
582
- metadata={"priority": "high|medium|low", "effort": "small|medium|large"})
627
+ TodoCreate(subject="<verb + noun>", description="<what + acceptance criteria>",
628
+ metadata={"priority": "high|medium|low",
629
+ "effort": "small|medium|large",
630
+ "delegate_to": "general|explore|scout|main"})
583
631
  ```
584
- - Set `addBlockedBy` on dependent tasks so the dependency DAG is clear
585
- - **Create ALL tasks upfront** before presenting the plan to the user
632
+ - Set `addBlockedBy` on dependent todos so the dependency DAG is clear
633
+ - **Create ALL todos upfront** before presenting the plan to the user
586
634
 
587
635
  **Present Plan for Review (Human-in-the-loop)**
588
- After creating all tasks, use `send_message()` to summarize the plan, then
589
- `ask_user()` to get approval before executing:
590
- ```
591
- send_message("Plan: 1. Setup DB model 2. Add API endpoint 3. Write tests")
592
- ask_user("Shall I proceed with executing this plan?")
593
- ```
636
+ After creating all todos, use `AskUser` to summarize the plan and get approval
637
+ before executing.
594
638
  Wait for user approval before moving to execution.
595
639
 
596
640
  ---
597
641
 
598
- ### Step 3: Act (Execute) — Delegate to Task Subagents
642
+ ### Step 3: Act (Execute) — Route by Complexity
599
643
 
600
- Execute by **delegating to Task subagents** rather than using direct tools.
644
+ Execute each todo using the right tool for the work:
601
645
 
602
- - **PREFERRED**: `Task(agent_type="general", prompt="Detailed instructions with context...")`
603
- - Use `general` subagent for implementation work, `explore` for code search, `scout` for research
604
- - Pass enough context in the prompt: relevant file paths, code snippets, requirements
605
- - Update task status: `pending` `in_progress` → `completed`
606
- - Use `task_update(..., output=...)` to pass results to downstream tasks
607
- - Direct execution tools (Write/Edit/Insert/ApplyPatch/Bash) should be avoided
608
- in favor of `Task` delegation. Only use them for truly trivial operations.
609
- - After each task, report progress via `send_message()` to keep the user in the loop
646
+ - **Simple todos** (single tool call): execute directly with `Read`/`Edit`/`Bash`, then `TodoUpdate(status="completed")`.
647
+ - **Complex todos** (multi-step, multi-file, research):
648
+ `Spawn(agent_type="general", prompt="Detailed instructions with context...")`.
649
+ Wait for the subagent's SUMMARY/CHANGES/EVIDENCE/RISKS/BLOCKERS output, then
650
+ `TodoUpdate(status="completed")`.
651
+ - Use `general` subagent for implementation, `explore` for code search, `scout` for research
652
+ - Pass enough context in the Spawn prompt: relevant file paths, code snippets, requirements
653
+ - After each todo, advance its status: `pending` `in_progress` `completed`
610
654
 
611
655
  ---
612
656
 
@@ -614,20 +658,20 @@ Execute by **delegating to Task subagents** rather than using direct tools.
614
658
 
615
659
  After every Action, the tool result is your **Observation**. Use it to inform the
616
660
  next Thought:
617
- - Task subagent completed → review SUMMARY/CHANGES/EVIDENCE/RISKS/BLOCKERS sections
618
- - Task creation succeeded → proceed to present plan or delegate execution
661
+ - Spawn subagent completed → review SUMMARY/CHANGES/EVIDENCE/RISKS/BLOCKERS sections
662
+ - TodoCreate succeeded → proceed to present plan or execute the next todo
619
663
  - Error occurred → diagnose and decide: retry, modify plan, or ask the user
620
- - User denied an action → adapt the task plan accordingly
664
+ - User denied an action → adapt the todo plan accordingly
621
665
 
622
666
  ---
623
667
 
624
668
  ### Rules
625
669
 
626
- - **No top-level planning prose**: All planning goes through task/todo tools so the UI renders it.
670
+ - **No top-level planning prose**: All planning goes through `TodoCreate`/`TodoUpdate` so the sidebar renders it.
627
671
  - **CoT in `<thinking>`**: Every turn starts with chain-of-thought reasoning inside `<thinking>`. Never narrate "I will now…" in visible text.
628
- - **Task-first**: Any operation needing >1 tool call delegate via `Task()`. Direct tool use is exceptional.
629
- - **Task status discipline**: `pending` → `in_progress` → `completed`. Every task transitions through all three.
630
- - **No execution without a plan**: Write/Edit/Insert/ApplyPatch/Bash require tasks. Create tasks first.
672
+ - **Route by complexity**: SimpleTodo + direct tool. Complex Spawn.
673
+ - **Todo status discipline**: `pending` → `in_progress` → `completed`. Every todo transitions through all three.
674
+ - **No execution without a plan**: Write/Edit/Insert/ApplyPatch/Bash require todos. Create todos first.
631
675
  - **Human at key decisions**: Present the plan, get approval, then execute. Report progress as you go.
632
676
  """
633
677
 
@@ -11,7 +11,7 @@ def _walk_up_parents(workspace_root: Path):
11
11
  """Yield workspace root, then git root.
12
12
 
13
13
  Unlike :class:`~onecode.skills.loader.SkillLoader` we deliberately do
14
- **not** yield ``Path.home()`` — the global ``~/.onecode/`` is the onecode
14
+ **not** yield ``Path.home()`` — the global ``~/.cdh/`` is the onecode
15
15
  user-config directory, not a project-level ``.cdh/``, so including it
16
16
  would cause false-positive matches.
17
17
  """
@@ -41,8 +41,9 @@ class CdhProjectLoader:
41
41
  """
42
42
 
43
43
  CDH_DIRNAME = ".cdh"
44
+ STATE_FILENAME = "state.json"
44
45
  LAST_SESSION_FILENAME = "last_session.json"
45
- TASKS_FILENAME = "tasks.json"
46
+ TODOS_FILENAME = "todos.json"
46
47
  PERMISSIONS_FILENAME = "permissions.json"
47
48
 
48
49
  # ── discovery ──────────────────────────────────────────────
@@ -82,7 +83,7 @@ class CdhProjectLoader:
82
83
  @staticmethod
83
84
  def load_project_state(cdh_dir: Path) -> dict:
84
85
  """Read ``.cdh/state.json``."""
85
- state_path = cdh_dir / "state.json"
86
+ state_path = cdh_dir / CdhProjectLoader.STATE_FILENAME
86
87
  if state_path.exists():
87
88
  try:
88
89
  return json.loads(state_path.read_text(encoding="utf-8"))
@@ -90,6 +91,15 @@ class CdhProjectLoader:
90
91
  pass
91
92
  return {}
92
93
 
94
+ @staticmethod
95
+ def save_state(cdh_dir: Path, state_data: dict) -> None:
96
+ """Save project state to ``.cdh/state.json``."""
97
+ path = cdh_dir / CdhProjectLoader.STATE_FILENAME
98
+ path.write_text(
99
+ json.dumps(state_data, ensure_ascii=False, indent=2),
100
+ encoding="utf-8",
101
+ )
102
+
93
103
  @staticmethod
94
104
  def get_skill_content(cdh_dir: Path) -> str:
95
105
  """Read ``.cdh/SKILL.md`` if it exists."""
@@ -123,21 +133,24 @@ class CdhProjectLoader:
123
133
  pass
124
134
  return {}
125
135
 
126
- # ── task persistence ───────────────────────────────────────
136
+ # ── todo persistence ───────────────────────────────────────
127
137
 
128
138
  @staticmethod
129
- def save_tasks(cdh_dir: Path, tasks_data: dict) -> None:
130
- """Save tasks/todos to ``.cdh/tasks.json``."""
131
- path = cdh_dir / CdhProjectLoader.TASKS_FILENAME
139
+ def save_todos(cdh_dir: Path, todos_data: dict) -> None:
140
+ """Save todos to ``.cdh/todos.json``."""
141
+ path = cdh_dir / CdhProjectLoader.TODOS_FILENAME
132
142
  path.write_text(
133
- json.dumps(tasks_data, ensure_ascii=False, indent=2),
143
+ json.dumps(todos_data, ensure_ascii=False, indent=2),
134
144
  encoding="utf-8",
135
145
  )
136
146
 
137
147
  @staticmethod
138
- def load_tasks(cdh_dir: Path) -> dict:
139
- """Load tasks/todos from ``.cdh/tasks.json``."""
140
- path = cdh_dir / CdhProjectLoader.TASKS_FILENAME
148
+ def load_todos(cdh_dir: Path) -> dict:
149
+ """Load todos from ``.cdh/todos.json``.
150
+
151
+ Returns an empty dict if the file is missing or unreadable.
152
+ """
153
+ path = cdh_dir / CdhProjectLoader.TODOS_FILENAME
141
154
  if path.exists():
142
155
  try:
143
156
  return json.loads(path.read_text(encoding="utf-8"))
@@ -247,8 +260,8 @@ class CdhProjectLoader:
247
260
  config_path = cdh_dir / "config.yaml"
248
261
  config_path.write_text(yaml.dump(config, default_flow_style=False), encoding="utf-8")
249
262
 
250
- state = {"current_phase": phase}
251
- state_path = cdh_dir / "state.json"
263
+ state = {"current_phase": phase, "completed_phases": [], "gate_results": {}}
264
+ state_path = cdh_dir / CdhProjectLoader.STATE_FILENAME
252
265
  state_path.write_text(json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8")
253
266
 
254
267
  skill_path = cdh_dir / "SKILL.md"