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:
@@ -341,7 +341,7 @@ Each agent gets a **spawn manifest** at `/app/tool-manifest.json` listing the ve
|
||||
|
||||
| Role | Flow verbs (beyond `i_am_idle`) |
|
||||
|---------------|--------------------------------------------------------------------------------------------------|
|
||||
| developer | `give_me_work`, `i_will_work_on`, `open_pr`, `i_am_done`, `i_am_blocked`, `resume`, `unclaim` |
|
||||
| developer | `give_me_work`, `i_will_work_on`, `open_pr`, `i_am_done`, `i_am_blocked`, `resume`, `sync_branch`, `unclaim` |
|
||||
| qa | `give_me_work`, `claim_review`, `pass_review`, `fail_review`, `i_am_blocked`, `resume`, `unclaim` |
|
||||
| documenter | `give_me_work`, `claim_doc_task`, `i_documented`, `i_am_blocked`, `resume`, `unclaim` |
|
||||
| cell_pm | `give_me_work`, `i_will_plan`, `delegate`, `complete`, `submit_up`, `triage`, `unblock`, `escalate_up`, `reassign`, `resume`, `unclaim` |
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ i_am_idle() → no work in your queue right now
|
||||
|
||||
| MCP server | Verbs you can call |
|
||||
|-----------------------|--------------------|
|
||||
| `roboco-flow` | `give_me_work`, `i_will_work_on`, `open_pr`, `i_am_done`, `i_am_blocked`, `unclaim`, `resume`, `i_am_idle` |
|
||||
| `roboco-flow` | `give_me_work`, `i_will_work_on`, `open_pr`, `i_am_done`, `i_am_blocked`, `unclaim`, `resume`, `sync_branch`, `i_am_idle` |
|
||||
| `roboco-do` | `commit`, `note`, `say`, `dm`, `evidence` |
|
||||
| `roboco-git-readonly` | `roboco_git_status`, `roboco_git_log`, `roboco_git_diff`, `roboco_git_branch_list` |
|
||||
| `roboco-optimal` | `roboco_ask_mentor`, `roboco_kb_search` |
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
| `git checkout` of a task branch | None — branch is auto-checked-out by `i_will_work_on(task_id)` (devs) or `i_will_plan(task_id, plan)` (PMs) |
|
||||
| Open a PR | None — PR is opened by the choreographer when the dev calls `open_pr(task_id)` |
|
||||
| Merge a PR | `complete(task_id, notes)` (PMs only) — Cell PM merges leaf PR; Main PM merges parent and escalates to CEO |
|
||||
| `git fetch` / `git pull` / `git rebase` | None at the agent layer — there is no pull/rebase verb. If your branch is **behind its base**, ESCALATE (`escalate_up` / `i_am_blocked`) — that, not unclaim, is the fix. Use `unclaim` + re-`claim` only to rebuild a branch fresh from the current base, and only on instruction |
|
||||
| `git fetch` / `git pull` / `git rebase` | Devs have `sync_branch(task_id)` — the gate-level rebase (fetch + rebase + force-with-lease push). If your branch is **behind its base**, call `sync_branch(task_id)`; do NOT improvise shell git. PMs have no rebase verb — for a cell/root integration branch behind its base, `escalate_up(...)`. Use `unclaim` + re-`claim` only to rebuild a branch fresh from the current base, and only on instruction |
|
||||
|
||||
## Write/Edit Outside Workspace
|
||||
|
||||
|
||||
@@ -52,11 +52,13 @@ Don't checkout by hand — there is no `roboco_git_checkout` tool.
|
||||
|
||||
## Branch Behind Its Base / master
|
||||
|
||||
**Symptom:** `roboco_git_status` shows `behind > 0` against the base branch when you go to submit.
|
||||
**Symptom:** `roboco_git_status` shows `behind > 0` against the base branch when you go to submit, OR `i_am_done` refuses with "your branch is N commit(s) behind its base".
|
||||
|
||||
**Cause:** The base (cell branch or master) advanced after your branch was cut, so your branch is stale.
|
||||
**Cause:** The base (cell branch or master) advanced after your branch was cut, so your branch is stale — a sibling's PR merged into the parent branch while you worked.
|
||||
|
||||
**Fix:** You have no rebase verb — do **not** create a rebase task or improvise with shell git. Bringing the branch current is a platform/PM action. Escalate: devs `i_am_blocked(reason="branch behind base — needs rebase")`; PMs `escalate_up(...)`.
|
||||
**Fix (devs):** Call `sync_branch(task_id)` — that is your gate-level rebase verb (raw `Bash git rebase` is denied). It fetches, rebases your branch onto its base, and force-pushes with-lease. 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 rebase task or improvise shell git. After it returns `rebased`, continue editing + `commit`, then `open_pr` / `i_am_done` as normal.
|
||||
|
||||
**Fix (PMs, for a cell/root integration branch — NOT a dev leaf):** `escalate_up(task_id, reason='branch behind base — needs rebase')` — bringing an integration branch current is a platform action. A dev's own leaf branch is the dev's to `sync_branch`.
|
||||
|
||||
## src refspec does not match any (during open_pr)
|
||||
|
||||
@@ -70,7 +72,7 @@ Don't checkout by hand — there is no `roboco_git_checkout` tool.
|
||||
|
||||
**Cause:** Your branch is behind its remote, so the push can't fast-forward.
|
||||
|
||||
**Fix:** Escalate rather than improvise — devs `i_am_blocked(...)`, PMs `escalate_up(...)`. There is no agent-layer pull/rebase to reconcile it.
|
||||
**Fix (devs):** Call `sync_branch(task_id)` to rebase onto your base through the gate, then retry the push-bearing verb (`open_pr` / `i_am_done`). **PMs** escalate: `escalate_up(...)`. There is no agent-layer pull — `sync_branch` is the dev's rebase path.
|
||||
|
||||
## NO_PR on pass / fail
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ When something goes wrong, the failure is almost always one of a handful of thin
|
||||
| Agents spawn but do nothing useful (tool-discovery churn) | The role's tool-manifest didn't mount; the agent falls back to discovering verbs | Check the manifest mount (below) |
|
||||
| Agent containers respawn in a loop, MCP servers stuck "pending" | MCP server launched without `--no-sync` against a workspace clone | Already fixed in the orchestrator; verify your image is current (below) |
|
||||
| A provider's agents go quiet all at once | The provider is **parked-and-probing** after a 429 / overload / session-limit — not hung | Wait; it self-resumes. See [Resilience](../models/resilience.md) |
|
||||
| A task sits **blocked: "branch behind base / needs rebase"** | The agent's branch fell behind its base while it worked; there is no agent-layer rebase verb, so the agent escalates instead of improvising | Rebase it yourself from the panel **Git** tab (below) |
|
||||
| A task sits **blocked: "branch behind base / needs rebase"** | The agent's branch fell behind its base while it worked; devs now self-rebase via the `sync_branch` gate verb, so a leaf branch rarely blocks here. A **cell/root integration branch** behind its base still escalates (PMs have no rebase verb) | Rebase the integration branch from the panel **Git** tab (below) |
|
||||
| KB / `ask_mentor` returns nothing | Ollama unhealthy or models not pulled | Check `ollama-init` logs (below) |
|
||||
| Agent containers exit immediately | `~/.claude` not mounted, or a Grok token expired | Check the mount / refresh the token (below) |
|
||||
| Clone fails, agent can't reach the repo | Missing or invalid project PAT, or HTTPS URL with no token | Set the project token (below) |
|
||||
@@ -76,7 +76,7 @@ When the orchestrator won't come up at all on a fresh deploy:
|
||||
|
||||
## A task is stuck on a branch behind its base
|
||||
|
||||
Agents have no rebase, pull, or merge verb — a task branch is brought current with its base only at claim. If the base (a cell branch, or master) moves forward while the agent works, the branch falls behind, and the agent escalates rather than improvising git surgery: the task surfaces **blocked** with a reason like *"branch behind base — needs rebase."* That escalation is by design — bringing the branch current is your call, not a unit of work the company decomposes. Rebase it from the panel **Git** tab — select the branch and **Rebase** it onto its base (or master) — and the task resumes on the next dispatch. (Automatic rebase-at-spawn, so a stale branch never reaches you at all, is on the roadmap.)
|
||||
A task branch is brought current with its base only at claim. If the base moves forward while the agent works, the branch falls behind. **Developer leaf branches** now self-rebase through the `sync_branch` gate verb — the dev calls `sync_branch(task_id)` (or `i_am_done` refuses a behind branch and points them at it), so a leaf rarely escalates to you. What still escalates is a **cell or root integration branch** behind its base: PMs have no rebase verb, so a PM `escalate_up`s and the task surfaces **blocked** with a reason like *"branch behind base — needs rebase."* That escalation is by design for an integration branch — bringing it current is your call, not a unit of work the company decomposes. Rebase it from the panel **Git** tab — select the branch and **Rebase** it onto its base (or master) — and the task resumes on the next dispatch. (Automatic rebase-at-spawn, so a stale branch never reaches you at all, is on the roadmap.)
|
||||
|
||||
## Next
|
||||
|
||||
|
||||
Reference in New Issue
Block a user