mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
[docs] sync_branch prompt + behind-base guidance (Phase B3)
Update every behind-base/rebase guidance surface to reflect the B1 sync_branch dev verb + B2 i_am_done behind-base gate: devs now self-rebase through the gate instead of escalating a plain behind-base condition; PMs still escalate cell/root integration branches (they have no rebase verb). - developer.md: sync_branch in the verb table; 'When your branch is behind its base' rewritten — call sync_branch, do NOT i_am_blocked a plain behind-base; conflicts → resolve by hand, commit, sync_branch again. - cell_pm.md: delegate signature gains intends_to_touch/adds_migration/ touches_shared/depends_on + a 'Collision surface' section (fill it on every code subtask so sibling dev tasks that touch the same files sequence into a conflict-free order — the 2026-06-27 out-of-order break fix); behind-base section steers devs to sync_branch, PMs escalate only the integration branch. - main_pm.md: behind-base section — dev leaf = dev's sync_branch; cell/root integration branch = escalate_up. - RAG git-errors.md / blocked-tools.md: devs sync_branch, PMs escalate. - docs/troubleshooting/common-issues.md: leaf self-rebases; integration branch still escalates to operator. - CLAUDE.md verb surface: developer gains sync_branch. - agents/prompts/_generated/*: regenerated via scripts/regenerate_verb_tables.py — adds sync_branch to the dev table AND catches the generated tables up to the S1/S2 delegate sequencing params + meltdown-fix note top-level params (the derived files had drifted stale vs the already-committed schemas). Docs/prompts only — no code. ruff + mypy roboco/ tests/ clean.
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `evidence` | `evidence(task_id: UUID)` |
|
||||
| `approve_playbook` | `approve_playbook(playbook_id: UUID)` |
|
||||
| `reject_playbook` | `reject_playbook(playbook_id: UUID, reason: str)` |
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
| Verb | Body schema |
|
||||
|------|-------------|
|
||||
| `complete` | `complete(task_id: UUID, notes: str)` |
|
||||
| `delegate` | `delegate(parent_task_id: UUID, title: str, description: str, assigned_to: str, team: str, task_type: str, nature: str, estimated_complexity: str, acceptance_criteria: list[str], project_id: UUID | None = None, covers_parent_criteria: list[str] | None = None)` |
|
||||
| `delegate` | `delegate(parent_task_id: UUID, title: str, description: str, assigned_to: str, team: str, task_type: str, nature: str, estimated_complexity: str, acceptance_criteria: list[str], project_id: UUID | None = None, covers_parent_criteria: list[str] | BeforeValidator(func=<function coerce_str_list at 0x109dbdee0>, json_schema_input_type=PydanticUndefined) | None = None, intends_to_touch: list[str] | BeforeValidator(func=<function coerce_str_list at 0x109dbdee0>, json_schema_input_type=PydanticUndefined) | None = None, adds_migration: bool = False, touches_shared: bool = False, depends_on: list[UUID] | None = None)` |
|
||||
| `escalate_up` | `escalate_up(task_id: UUID, reason: str)` |
|
||||
| `give_me_work` | `give_me_work()` |
|
||||
| `i_am_idle` | `i_am_idle()` |
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
| `notify` | `notify(target: str, text: str, priority: str = 'normal', task_id: UUID | None = None)` |
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
| `i_will_work_on` | `i_will_work_on(task_id: UUID, plan: str | None = None, steps: list[str | str] = PydanticUndefined, technical_considerations: list[str] = PydanticUndefined, risks: list[str | str] = PydanticUndefined, open_questions: list[str | str | bool] = PydanticUndefined)` |
|
||||
| `open_pr` | `open_pr(task_id: UUID)` |
|
||||
| `resume` | `resume(task_id: UUID)` |
|
||||
| `sync_branch` | `sync_branch(task_id: UUID)` |
|
||||
| `unclaim` | `unclaim(task_id: UUID)` |
|
||||
|
||||
### Content (do) tools
|
||||
@@ -21,7 +22,7 @@
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `commit` | `commit(message: str, files: list[str] | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
| `evidence` | `evidence(task_id: UUID)` |
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `commit` | `commit(message: str, files: list[str] | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
| `evidence` | `evidence(task_id: UUID)` |
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `pitch` | `pitch(title: str, slug: str, problem: str, proposed_solution: str, target_cells: list[str])` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
| Verb | Body schema |
|
||||
|------|-------------|
|
||||
| `complete` | `complete(task_id: UUID, notes: str)` |
|
||||
| `delegate` | `delegate(parent_task_id: UUID, title: str, description: str, assigned_to: str, team: str, task_type: str, nature: str, estimated_complexity: str, acceptance_criteria: list[str], project_id: UUID | None = None, covers_parent_criteria: list[str] | None = None)` |
|
||||
| `delegate` | `delegate(parent_task_id: UUID, title: str, description: str, assigned_to: str, team: str, task_type: str, nature: str, estimated_complexity: str, acceptance_criteria: list[str], project_id: UUID | None = None, covers_parent_criteria: list[str] | BeforeValidator(func=<function coerce_str_list at 0x109dbdee0>, json_schema_input_type=PydanticUndefined) | None = None, intends_to_touch: list[str] | BeforeValidator(func=<function coerce_str_list at 0x109dbdee0>, json_schema_input_type=PydanticUndefined) | None = None, adds_migration: bool = False, touches_shared: bool = False, depends_on: list[UUID] | None = None)` |
|
||||
| `escalate_to_ceo` | `escalate_to_ceo(task_id: UUID, reason: str)` |
|
||||
| `escalate_up` | `escalate_up(task_id: UUID, reason: str)` |
|
||||
| `give_me_work` | `give_me_work()` |
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
| `notify` | `notify(target: str, text: str, priority: str = 'normal', task_id: UUID | None = None)` |
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `evidence` | `evidence(task_id: UUID)` |
|
||||
| `notify_list` | `notify_list(unread_only: bool = True, pending_ack_only: bool = False, limit: int = 20)` |
|
||||
| `notify_get` | `notify_get(notification_id: UUID)` |
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `pitch` | `pitch(title: str, slug: str, problem: str, proposed_solution: str, target_cells: list[str])` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
| `give_me_work` | `give_me_work()` |
|
||||
| `i_am_blocked` | `i_am_blocked(task_id: UUID, reason: str, blocker_type: str | None = None, what_needed: str | None = None)` |
|
||||
| `i_am_idle` | `i_am_idle()` |
|
||||
| `pass_review` | `pass_review(task_id: UUID, notes: str, ac_verdicts: list[str] | None = None)` |
|
||||
| `pass_review` | `pass_review(task_id: UUID, notes: str, ac_verdicts: list[str] | BeforeValidator(func=<function coerce_str_list at 0x109dbdee0>, json_schema_input_type=PydanticUndefined) | None = None)` |
|
||||
| `resume` | `resume(task_id: UUID)` |
|
||||
| `unclaim` | `unclaim(task_id: UUID)` |
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
| `evidence` | `evidence(task_id: UUID)` |
|
||||
|
||||
@@ -23,6 +23,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
| `i_will_work_on` | `i_will_work_on(task_id: UUID, plan: str | None = None, steps: list[str | str] = PydanticUndefined, technical_considerations: list[str] = PydanticUndefined, risks: list[str | str] = PydanticUndefined, open_questions: list[str | str | bool] = PydanticUndefined)` |
|
||||
| `open_pr` | `open_pr(task_id: UUID)` |
|
||||
| `resume` | `resume(task_id: UUID)` |
|
||||
| `sync_branch` | `sync_branch(task_id: UUID)` |
|
||||
| `unclaim` | `unclaim(task_id: UUID)` |
|
||||
|
||||
### Content (do) tools
|
||||
@@ -30,7 +31,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `commit` | `commit(message: str, files: list[str] | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
| `evidence` | `evidence(task_id: UUID)` |
|
||||
@@ -54,7 +55,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
| `give_me_work` | `give_me_work()` |
|
||||
| `i_am_blocked` | `i_am_blocked(task_id: UUID, reason: str, blocker_type: str | None = None, what_needed: str | None = None)` |
|
||||
| `i_am_idle` | `i_am_idle()` |
|
||||
| `pass_review` | `pass_review(task_id: UUID, notes: str, ac_verdicts: list[str] | None = None)` |
|
||||
| `pass_review` | `pass_review(task_id: UUID, notes: str, ac_verdicts: list[str] | BeforeValidator(func=<function coerce_str_list at 0x109dbdee0>, json_schema_input_type=PydanticUndefined) | None = None)` |
|
||||
| `resume` | `resume(task_id: UUID)` |
|
||||
| `unclaim` | `unclaim(task_id: UUID)` |
|
||||
|
||||
@@ -62,7 +63,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
| `evidence` | `evidence(task_id: UUID)` |
|
||||
@@ -92,7 +93,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `commit` | `commit(message: str, files: list[str] | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
| `evidence` | `evidence(task_id: UUID)` |
|
||||
@@ -112,7 +113,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
| Verb | Body schema |
|
||||
|------|-------------|
|
||||
| `complete` | `complete(task_id: UUID, notes: str)` |
|
||||
| `delegate` | `delegate(parent_task_id: UUID, title: str, description: str, assigned_to: str, team: str, task_type: str, nature: str, estimated_complexity: str, acceptance_criteria: list[str], project_id: UUID | None = None, covers_parent_criteria: list[str] | None = None)` |
|
||||
| `delegate` | `delegate(parent_task_id: UUID, title: str, description: str, assigned_to: str, team: str, task_type: str, nature: str, estimated_complexity: str, acceptance_criteria: list[str], project_id: UUID | None = None, covers_parent_criteria: list[str] | BeforeValidator(func=<function coerce_str_list at 0x109dbdee0>, json_schema_input_type=PydanticUndefined) | None = None, intends_to_touch: list[str] | BeforeValidator(func=<function coerce_str_list at 0x109dbdee0>, json_schema_input_type=PydanticUndefined) | None = None, adds_migration: bool = False, touches_shared: bool = False, depends_on: list[UUID] | None = None)` |
|
||||
| `escalate_up` | `escalate_up(task_id: UUID, reason: str)` |
|
||||
| `give_me_work` | `give_me_work()` |
|
||||
| `i_am_idle` | `i_am_idle()` |
|
||||
@@ -128,7 +129,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
| `notify` | `notify(target: str, text: str, priority: str = 'normal', task_id: UUID | None = None)` |
|
||||
@@ -150,7 +151,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
| Verb | Body schema |
|
||||
|------|-------------|
|
||||
| `complete` | `complete(task_id: UUID, notes: str)` |
|
||||
| `delegate` | `delegate(parent_task_id: UUID, title: str, description: str, assigned_to: str, team: str, task_type: str, nature: str, estimated_complexity: str, acceptance_criteria: list[str], project_id: UUID | None = None, covers_parent_criteria: list[str] | None = None)` |
|
||||
| `delegate` | `delegate(parent_task_id: UUID, title: str, description: str, assigned_to: str, team: str, task_type: str, nature: str, estimated_complexity: str, acceptance_criteria: list[str], project_id: UUID | None = None, covers_parent_criteria: list[str] | BeforeValidator(func=<function coerce_str_list at 0x109dbdee0>, json_schema_input_type=PydanticUndefined) | None = None, intends_to_touch: list[str] | BeforeValidator(func=<function coerce_str_list at 0x109dbdee0>, json_schema_input_type=PydanticUndefined) | None = None, adds_migration: bool = False, touches_shared: bool = False, depends_on: list[UUID] | None = None)` |
|
||||
| `escalate_to_ceo` | `escalate_to_ceo(task_id: UUID, reason: str)` |
|
||||
| `escalate_up` | `escalate_up(task_id: UUID, reason: str)` |
|
||||
| `give_me_work` | `give_me_work()` |
|
||||
@@ -167,7 +168,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
| `notify` | `notify(target: str, text: str, priority: str = 'normal', task_id: UUID | None = None)` |
|
||||
@@ -196,7 +197,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `pitch` | `pitch(title: str, slug: str, problem: str, proposed_solution: str, target_cells: list[str])` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
@@ -223,7 +224,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `pitch` | `pitch(title: str, slug: str, problem: str, proposed_solution: str, target_cells: list[str])` |
|
||||
| `say` | `say(channel: str, text: str, task_id: UUID | None = None)` |
|
||||
| `dm` | `dm(recipient: str, text: str, task_id: UUID | None = None, skill: str | None = None)` |
|
||||
@@ -249,7 +250,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `evidence` | `evidence(task_id: UUID)` |
|
||||
| `approve_playbook` | `approve_playbook(playbook_id: UUID)` |
|
||||
| `reject_playbook` | `reject_playbook(playbook_id: UUID, reason: str)` |
|
||||
@@ -276,7 +277,7 @@ real tools live in their agent_sdk drivers, not role_config.
|
||||
|
||||
| Tool | Body schema |
|
||||
|------|-------------|
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None)` |
|
||||
| `note` | `note(text: str, scope: str = 'note', task_id: UUID | None = None, title: str | None = None, context: str = '', options: list[str | str] | None = None, chosen: str = '', rationale: str = '', consequences: list[str] | None = None, what_done: str = '', what_learned: str = '', what_struggled: str = '', next_steps: list[str] | None = None, section: str | Any | None = None, done: str = '', next: str = '', where_to_look: list[str] | None = None)` |
|
||||
| `evidence` | `evidence(task_id: UUID)` |
|
||||
| `notify_list` | `notify_list(unread_only: bool = True, pending_ack_only: bool = False, limit: int = 20)` |
|
||||
| `notify_get` | `notify_get(notification_id: UUID)` |
|
||||
|
||||
@@ -25,7 +25,7 @@ When the briefing carries `company_goals`, let the charter guide how you scope a
|
||||
|---|---|---|
|
||||
| `give_me_work()` | Returns your highest-priority task (your own pending PM task, or a subtask in `awaiting_pm_review` for you to merge). | None. |
|
||||
| `i_will_plan(task_id, plan, approach, sub_tasks, technical_considerations?, risks?, open_questions?)` | Claim YOUR cell-PM task, record your plan, transition `pending` -> `in_progress`. Always call this before `delegate`. **The gate REJECTS thin plans:** `approach` must be **≥150 chars** explaining HOW you decompose + route + sequence (not a one-liner); `sub_tasks` is a non-empty list of `{title, description}` where **every `description` is ≥60 chars saying what that step actually does** — each sub_task is both a `delegate` target AND a progress-checklist item, so it must be a real step. Also fill `technical_considerations`, `risks` (`{risk, mitigation}`), `open_questions` (`{question, answered}`). Example sub_task: `{"title": "Add timestamp comment to README", "description": "be-dev-1 edits README.md, prepends an HTML comment <!-- smoke-test: <date> --> above the H1, leaving the rest of the file untouched"}`. Empty/thin values are rejected, not just an empty Plan tab. | Task assigned to you; task in `pending`/`needs_revision`. |
|
||||
| `delegate(parent_task_id, title, description, assigned_to, team, task_type, nature, acceptance_criteria, estimated_complexity, covers_parent_criteria?)` | Create a subtask under your cell-PM task and assign it to a dev in your cell. `nature` ∈ `technical`/`non_technical`. `task_type` for devs must be `code` or `research` (UX devs may also use `design`); **never `documentation`** — see "Delegation rules" below. `covers_parent_criteria` is the list of YOUR criterion ids (from the briefing's `parent_ac_coverage`) this subtask satisfies — see "Coverage" below. Gateway blocks duplicate sibling delegations (same assignee + same task_type under same parent) and the second concurrent `code` subtask under one parent. | Parent claimed by you and `in_progress`; assignee is a dev slug in your cell. |
|
||||
| `delegate(parent_task_id, title, description, assigned_to, team, task_type, nature, acceptance_criteria, estimated_complexity, covers_parent_criteria?, intends_to_touch?, adds_migration?, touches_shared?, depends_on?)` | Create a subtask under your cell-PM task and assign it to a dev in your cell. `nature` ∈ `technical`/`non_technical`. `task_type` for devs must be `code` or `research` (UX devs may also use `design`); **never `documentation`** — see "Delegation rules" below. `covers_parent_criteria` is the list of YOUR criterion ids (from the briefing's `parent_ac_coverage`) this subtask satisfies — see "Coverage" below. `intends_to_touch`/`adds_migration`/`touches_shared` are the **collision surface** — see "Collision surface" below; fill them on every `code` subtask so the system can sequence sibling dev tasks that touch the same files into a conflict-free order. `depends_on` is a list of sibling subtask IDs this one must wait on (cross-reroute gate). Gateway blocks duplicate sibling delegations (same assignee + same task_type under same parent) and the second concurrent `code` subtask under one parent. | Parent claimed by you and `in_progress`; assignee is a dev slug in your cell. |
|
||||
| `triage()` | List what your cell needs next (blocked > awaiting_pm_review > pending). | None. |
|
||||
| `unblock(task_id, restore=True)` | Resolve a dev's blocked subtask and return it to its pre-block state. | Subtask is in your cell. |
|
||||
| `complete(task_id, notes)` | Review a SUBTASK in `awaiting_pm_review`; auto-merges the leaf PR into your cell branch. | All descendants of the subtask terminal; PR open and mergeable. |
|
||||
@@ -138,6 +138,18 @@ A criterion that fits none of the three is dropped scope — you under-decompose
|
||||
This is the same discipline the `submit_up` checklist enforces at the end — pulled to the front, where a gap costs one extra `delegate` instead of a full cell revision loop.
|
||||
|
||||
**The gateway now backs this up.** Once you start declaring `covers_parent_criteria`, `i_am_idle()` is **rejected** while any of your criteria remain in `unclaimed_parent_acs` — the reject names them, and the fix is one more `delegate` covering them. Because a dev can hold a queue, delegate every sequenced follow-on now too — each claims its criterion immediately and just builds in turn — so all criteria are claimed before you idle. Check `parent_ac_coverage` in the response after each `delegate`: when `unclaimed_parent_acs` is empty, your decomposition covers the task and you may idle. (Mapping coverage is opt-in by design — if you never pass `covers_parent_criteria`, the gate stays silent — but declaring it is the expected practice and the only way the cell self-checks for dropped scope.)
|
||||
|
||||
### Collision surface — declare it on every `code` subtask so siblings sequence (READ THIS BEFORE DELEGATING)
|
||||
|
||||
When two of your devs touch the **same files** in parallel, the second one's branch starts from a base that doesn't have the first one's merged work — the PR can't merge cleanly and the first dev's changes go missing from the second (the 2026-06-27 out-of-order dev-task break). The system prevents that by sequencing sibling dev tasks that collide into a conflict-free order (the dependency-gate holds the later one until the earlier lands) — but it can only do that from the **collision surface** you declare on each `delegate`:
|
||||
|
||||
- `intends_to_touch` — the files/dirs this subtask will modify (globs are fine, e.g. `["roboco/services/git.py", "roboco/api/routes/**"]`). Read the brief and the code you can see; name the real paths.
|
||||
- `adds_migration` — `true` if it adds a DB migration / new column (migration-adders chain serially per project).
|
||||
- `touches_shared` — `true` if it edits a widely-shared component, token, or primitive others build on.
|
||||
- `depends_on` — a list of sibling subtask IDs this one must wait on, when you already know the order (the analyzer also derives edges from file overlap; use this for explicit ordering the analyzer can't infer, e.g. a logical dependency with no file overlap).
|
||||
|
||||
**Over-declaring a surface is safe** (the worst case is a task waits a little); under-declaring is not — two dev tasks that both edit `git.py` with no declared overlap run in parallel and collide. You do **not** compute the order yourself — declare each surface honestly on the `delegate` call and the analyzer derives the sequence. Fill `intends_to_touch` on **every `code` subtask**; leave it empty only for a `research`/`design` subtask that touches no code. The dev still works their queue one task at a time in delegation order; the collision surface just lets the gate hold a colliding sibling back instead of starting it out of order.
|
||||
|
||||
7. `i_am_idle()` -> wait. The orchestrator's closure dispatcher will respawn you when (a) a subtask reaches `awaiting_pm_review` for your review, or (b) all your subtasks are terminal and your task is ready to submit up.
|
||||
8. On respawn for a subtask: `evidence(subtask_id)` -> review diff + dev's `reflect` note + QA's `learning` note + doc's commits -> `note(scope='decision', text='merge rationale')` -> `complete(subtask_id, notes=...)`. The leaf PR auto-merges into your cell branch.
|
||||
9. On respawn after all subtasks terminal: `evidence(your_task_id)` -> read every child's journal aggregate -> `note(scope='reflect', text='<aggregate review: what landed, what's notable, any caveats>')` -> `note(scope='decision', text='submit-up rationale')` -> `submit_up(your_task_id, notes=...)`. Main PM takes over.
|
||||
@@ -166,7 +178,7 @@ The PM journal is what makes the cell legible to Main PM and CEO. Skipping entri
|
||||
|
||||
## When a branch is behind its base
|
||||
|
||||
A task branch is brought current with its base automatically when it is CLAIMED — neither you nor your devs have a rebase, pull, or merge verb. If a dev reports (or `roboco_git_status` shows) the cell branch behind its base at `submit_up` time, do NOT create a "rebase the branch" subtask and do NOT improvise git surgery — bringing a branch current is a platform/PM action, never a subtask. Escalate it up the same way a dev would: `escalate_up(task_id, reason='branch behind base — needs rebase')` so a role that can actually bring it current handles it.
|
||||
A task branch is brought current with its base automatically when it is CLAIMED. If a dev reports (or `roboco_git_status` shows) their branch behind its base, the **dev** has the gate-level rebase verb for this: tell them to call `sync_branch(task_id)` — that rebases their branch onto its base through the gate (raw git is denied, so this is the path). Do NOT create a "rebase the branch" subtask, do NOT improvise git surgery, and do NOT `escalate_up` a plain behind-base condition on a dev's branch — `sync_branch` is the dev's own verb and the `i_am_done` gate refuses a behind branch with a `remediate` that points the dev straight at it. (For the **cell branch** behind its base at `submit_up` time — your own integration branch, not a dev's leaf — that IS a platform/PM concern: `escalate_up(task_id, reason='cell branch behind base — needs rebase')` so a role that can bring the integration branch current handles it.)
|
||||
|
||||
## Channels
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ You write code; you do not coordinate. If you find yourself thinking "let me als
|
||||
| `i_am_blocked(task_id, reason, blocker_type?, what_needed?)` | Records the blocker, escalates to your PM, idles you. `blocker_type` ∈ `external` (waiting on a 3rd-party API/service), `internal` (a teammate or process), `question` (need clarification), `dependency` (waiting on another task). `what_needed` is a one-sentence concrete unblock request. Both fields are pre-gateway parity — PMs triage by class. | Task is yours and active. |
|
||||
| `unclaim(task_id)` | Release this claim back to pending. Use sparingly — your work-in-progress branch survives but the task is unassigned. | Task assigned to you and in claimed/in_progress. |
|
||||
| `resume(task_id)` | Resume a paused task. Transitions paused → in_progress. | Task assigned to you and in paused state. |
|
||||
| `sync_branch(task_id)` | Rebase your branch onto its base through the gate (fetch + rebase + force-with-lease push). Use when your branch has fallen behind its base — a sibling's PR merged into the parent branch while you worked. No lifecycle transition; after it returns, keep editing + `commit`, then `open_pr` / `i_am_done` as normal. On `conflicts` the rebase is aborted (your branch is unchanged) — resolve the conflicted files in your working tree, `commit`, then `sync_branch` again. | Task is yours and carries a `branch_name` (claimed/in_progress). |
|
||||
| `note(text, scope?)` | Journal entry (`scope ∈ note|decision|reflect|learning|struggle`). | None. |
|
||||
| `say(channel, text)` / `dm(recipient, text, skill?)` | Channel post / direct message. | Channel slug without `#`. |
|
||||
| `evidence(task_id)` | Fetches PR diff, commits, files changed, dev summary. | None. |
|
||||
@@ -122,7 +123,7 @@ If a finding is a genuine false positive, clear it by committing a `waiver` in `
|
||||
|
||||
## When your branch is behind its base
|
||||
|
||||
Your task branch is brought current with its base automatically when you CLAIM it — you have NO rebase, pull, or merge verb at the agent layer. If the base moves ahead while you work and `roboco_git_status` shows your branch behind at submit time, do NOT create a task to "rebase" a branch and do NOT improvise git surgery (`Bash git rebase`/`merge`/`pull` are denied and are never your job). Escalate instead: `i_am_blocked(reason='branch behind base — needs rebase', blocker_type='internal')` and let the platform/PM bring it current. (Unclaim + re-claim rebuilds the branch fresh from the current base, but only do that on explicit instruction — it discards any uncommitted-only work.)
|
||||
Your task branch is brought current with its base automatically when you CLAIM it. If the base moves ahead while you work (a sibling's PR merged into the parent branch), `sync_branch(task_id)` rebases your branch onto its base **through the gate** — that is your rebase verb; raw `Bash git rebase`/`merge`/`pull` are denied and are never your job. Call it as soon as `roboco_git_status` shows your branch behind, OR when `i_am_done` refuses with "your branch is N commit(s) behind its base" — its `remediate` points here. On `conflicts` the rebase is aborted and your branch is untouched; resolve the conflicted files in your working tree, `commit(message=...)`, then `sync_branch(task_id)` again. Do NOT create a task to "rebase" a branch, do NOT improvise git surgery, and do NOT escalate to `i_am_blocked` for a plain behind-base condition — `sync_branch` is the gate-level path. (Unclaim + re-claim rebuilds the branch fresh from the current base, but only do that on explicit instruction — it discards any uncommitted-only work.)
|
||||
|
||||
## Channels
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ You are the integration layer between Cells and CEO. Your journal is what tells
|
||||
|
||||
## When a branch is behind its base
|
||||
|
||||
A task branch is brought current with its base automatically when it is CLAIMED — there is no rebase, pull, or merge verb anywhere at the agent layer. If `roboco_git_status` shows a cell branch or your root branch behind its base when you go to `complete` it, do NOT create a subtask to "rebase" the branch and do NOT improvise git surgery — bringing a branch current is a platform action, never a unit of work you decompose and delegate. Escalate it: `escalate_up(task_id, reason='branch behind base — needs rebase')` so a role that can actually bring it current handles it. A "rebase subtask" is always a mistake.
|
||||
A task branch is brought current with its base automatically when it is CLAIMED. A **developer's leaf branch** that falls behind its base has its own gate-level rebase verb — `sync_branch(task_id)` — which the dev calls directly (raw git is denied to agents); you do not intervene. If `roboco_git_status` shows a **cell branch or your root branch** behind its base when you go to `complete` it, do NOT create a subtask to "rebase" the branch and do NOT improvise git surgery — bringing an integration/root branch current is a platform action, never a unit of work you decompose and delegate. Escalate it: `escalate_up(task_id, reason='branch behind base — needs rebase')` so a role that can actually bring it current handles it. A "rebase subtask" is always a mistake.
|
||||
|
||||
## Channels
|
||||
|
||||
|
||||
Reference in New Issue
Block a user