Many fixes and cleanups

This commit is contained in:
Renn F
2026-05-09 03:15:09 +02:00
parent d819c28893
commit 73e1e96851
23 changed files with 1321 additions and 1059 deletions
+7 -3
View File
@@ -460,9 +460,13 @@ tools:
- roboco_session_history_for_task # Get discussion history for your task - roboco_session_history_for_task # Get discussion history for your task
- roboco_report_blocker - roboco_report_blocker
# Git Operations (via roboco MCP tools) # Git Operations
- roboco_git_status, roboco_git_log, roboco_git_diff # Read-only inspection (via roboco-git-readonly MCP):
- roboco_git_commit, roboco_git_push, roboco_git_create_pr - roboco_git_status, roboco_git_log, roboco_git_diff, roboco_git_branch_list
# Write path (via roboco-do MCP) — `commit` auto-prefixes [task-id], pushes
# to your branch, and triggers PR creation through the choreographer.
# There is NO separate roboco_git_commit / push / create_pr tool.
- commit (message, files)
``` ```
## Permissions ## Permissions
+15 -2
View File
@@ -15,12 +15,25 @@ RUN corepack enable pnpm
FROM base AS builder FROM base AS builder
WORKDIR /app WORKDIR /app
# pnpm 11 prompts for confirmation on modules-purge unless told this is CI.
ENV CI=true
# Copy package manifests first (for layer caching) # Copy package manifests first (for layer caching)
COPY panel/package.json panel/pnpm-lock.yaml ./ COPY panel/package.json panel/pnpm-lock.yaml ./
# Install dependencies with shamefully-hoist to flatten node_modules # Install dependencies with shamefully-hoist to flatten node_modules
# This prevents symlink issues with styled-jsx and other peer deps # (prevents symlink issues with styled-jsx and other peer deps).
RUN pnpm install --frozen-lockfile --shamefully-hoist #
# pnpm 11 hard-errors on packages with install scripts unless explicitly
# approved. `sharp` and `unrs-resolver` both ship platform-specific
# prebuilt binaries via @img/sharp-* and napi-postinstall, so the install
# scripts are verification-only — skipping them is safe at runtime.
# `strictDepBuilds=false` downgrades the hard error to a warning while
# keeping the install reproducible against the frozen lockfile.
RUN pnpm install \
--frozen-lockfile \
--shamefully-hoist \
--config.strictDepBuilds=false
# Copy panel source code # Copy panel source code
COPY panel/ ./ COPY panel/ ./
+26 -8
View File
@@ -40,12 +40,30 @@ low=$(printf '%s' "$cmd" | tr "[:upper:]" "[:lower:]")
if echo "$low" | grep -qE '(^|[[:space:];&|])git[[:space:]]+(fetch|pull|push|clone|remote|ls-remote|checkout|commit|merge|rebase|reset|cherry-pick|revert|tag[[:space:]]+-d|update-ref|reflog[[:space:]]+delete)'; then if echo "$low" | grep -qE '(^|[[:space:];&|])git[[:space:]]+(fetch|pull|push|clone|remote|ls-remote|checkout|commit|merge|rebase|reset|cherry-pick|revert|tag[[:space:]]+-d|update-ref|reflog[[:space:]]+delete)'; then
cat <<'EOF' >&2 cat <<'EOF' >&2
Denied: shell git for network / auth / branch-mutating ops is blocked. Denied: shell git for network / auth / branch-mutating ops is blocked.
Use the roboco-git MCP tools instead:
- roboco_git_status / _log / _diff / _branch_list (read-only local) Read-only inspection (any role):
- roboco_git_commit / _push / _create_pr (write ops) - roboco-git-readonly MCP: roboco_git_status / _log / _diff / _branch_list
They route through the orchestrator which injects the GitHub PAT and
tracks commits against the task. Raw `git fetch` etc. don't have auth Write paths — there is NO direct shell-git or "roboco_git_commit" tool.
and will fail with "could not read Username for 'https://github.com'". Use the verb that matches your role; the choreographer handles git for you:
- developer / documenter: roboco-do `commit(message, files)`
→ auto-prefixes [task-id], pushes to your branch, opens a PR via
the choreographer when the task transitions out of in_progress.
Your branch is auto-created when you call i_will_work_on().
- cell_pm / main_pm: roboco-flow `complete(task_id, notes)`
→ cell_pm merges the leaf PR; main_pm opens the master PR and
escalates to CEO. PMs never run git directly — they delegate
code work to devs and complete to merge.
- any role: branches are NOT something you set up. They are created
on claim/i_will_work_on. If you don't see your branch, check that
you're actually claimed on the task.
Raw `git fetch` etc. don't have auth (the PAT is injected only inside
the MCP layer) and will fail with "could not read Username for
'https://github.com'".
EOF EOF
exit 2 exit 2
fi fi
@@ -57,7 +75,7 @@ fi
# post-clone so the file is uninteresting, but a leaked PAT is unrecoverable # post-clone so the file is uninteresting, but a leaked PAT is unrecoverable
# so belt + suspenders applies. # so belt + suspenders applies.
if echo "$low" | grep -qE '(\.git/config|\.gitconfig|\.git-credentials|\.netrc|\.ssh/|id_rsa|id_ed25519|id_ecdsa|known_hosts)'; then if echo "$low" | grep -qE '(\.git/config|\.gitconfig|\.git-credentials|\.netrc|\.ssh/|id_rsa|id_ed25519|id_ecdsa|known_hosts)'; then
echo "Denied: command references a credential file or SSH key. Use roboco_git_* MCP tools — the PAT is injected subprocess-side and never lands in these files." >&2 echo "Denied: command references a credential file or SSH key. Don't read git credentials — the PAT is injected subprocess-side by the MCP layer (commit / complete verbs) and never lands in these files." >&2
exit 2 exit 2
fi fi
@@ -68,7 +86,7 @@ if echo "$low" | grep -qE '/proc/(self|[0-9]+|\$\$|\$\{.*\})/(environ|cmdline|cw
fi fi
if echo "$low" | grep -qE '(^|[[:space:];&|])(curl|wget|http|https)[[:space:]][^|]*(github\.com|api\.github\.com)'; then if echo "$low" | grep -qE '(^|[[:space:];&|])(curl|wget|http|https)[[:space:]][^|]*(github\.com|api\.github\.com)'; then
echo "Denied: direct GitHub HTTP calls bypass the PAT handler. Use roboco_git_* MCP tools." >&2 echo "Denied: direct GitHub HTTP calls bypass the PAT handler. Use the role-appropriate MCP verb: roboco-do commit (devs/docs), roboco-flow complete (PMs), or roboco-git-readonly status/log/diff/branch_list (any role)." >&2
exit 2 exit 2
fi fi
+100 -52
View File
@@ -2,78 +2,126 @@
## Overview ## Overview
Agents have role-specific tool permissions enforced via Claude Code settings. Agents call gateway verbs through three MCP servers, scoped per role:
Native tools are blocked; use `roboco_*` MCP tools instead.
| MCP server | Provides |
|------------|----------|
| `roboco-flow` | Lifecycle verbs (give_me_work, i_will_work_on, open_pr, complete, …) |
| `roboco-do` | Content/write verbs (commit, note, say, dm, notify, evidence) |
| `roboco-git-readonly` | Read-only git inspection (status, log, diff, branch_list) |
Native shell git is blocked by the bash-guard hook for everyone. There is
**no** `roboco_git_commit / _push / _create_pr / _merge_pr / _checkout`
tool — write operations happen through the lifecycle verbs and the
choreographer handles git as a side-effect.
The canonical source of role → verb mapping is
`roboco/services/gateway/role_config.py`. The tables below summarise it.
## Developer ## Developer
**Allowed:** **Flow verbs (roboco-flow):**
- `roboco_task_*` - task lifecycle `give_me_work`, `i_will_work_on`, `open_pr`, `i_am_done`,
- `roboco_git_*` - all git operations `i_am_blocked`, `unclaim`, `resume`, `i_am_idle`
- `roboco_test_*` - run tests, lint, format
- `roboco_journal_*` - journaling
- `roboco_kb_*`, `roboco_rag_*` - knowledge base
- `Read(*)` - read any file
- `Write/Edit` - workspace only
**Blocked:** **Content verbs (roboco-do):**
- `Bash(git:*)` - use roboco_git_* instead `commit`, `note`, `say`, `dm`, `evidence`
- `Write/Edit` outside workspace
**Workspace:** `/data/workspaces/{project}/{team}/{agent-id}/` **Read-only git (roboco-git-readonly):** all 4 (`status`, `log`, `diff`,
`branch_list`)
**Workspace writes:** `Write` / `Edit` in
`/data/workspaces/{project}/{team}/{agent-id}/` only.
## QA ## QA
**Allowed:** **Flow verbs:**
- `roboco_git_status`, `roboco_git_log`, `roboco_git_diff` - read-only `give_me_work`, `claim_review`, `pass`, `fail`, `unclaim`, `resume`,
- `roboco_test_*` - run tests `i_am_idle`
- `roboco_task_qa_pass`, `roboco_task_qa_fail`
- `Read(*)` - read any file
**Blocked:** **Content verbs:**
- `roboco_git_commit`, `roboco_git_push` - QA doesn't write code `note`, `say`, `dm`, `evidence` (no `commit` QA does not write code)
- All `Write/Edit` - review only
**Read-only git:** all 4
**Workspace writes:** none — QA reviews only.
## Documenter ## Documenter
**Allowed:** **Flow verbs:**
- `roboco_docs_*` - documentation tools `give_me_work`, `claim_doc_task`, `i_documented`, `unclaim`, `resume`,
- `roboco_git_*` - all git operations `i_am_idle`
- `Write/Edit` in `/app/docs/**` only
**Blocked:** **Content verbs:**
- `Write/Edit` outside docs directory `commit`, `note`, `say`, `dm`, `evidence`
## PM (Cell PM, Main PM) **Read-only git:** all 4
**Allowed:** **Workspace writes:** docs files inside the agent's own workspace
- `roboco_git_*` - all git operations (`/data/workspaces/{project}/{team}/{agent-id}/`).
- `roboco_docs_*` - documentation
- `roboco_task_*` - full task management
- `roboco_notify_send` - send notifications
**Blocked:** ## Cell PM
- `Bash(git:*)` - use roboco_git_*
**Flow verbs:**
`give_me_work`, `i_will_plan`, `delegate`, `submit_up`, `triage`,
`unblock`, `complete`, `escalate_up`, `unclaim`, `resume`, `i_am_idle`
**Content verbs:**
`note`, `say`, `dm`, `notify`, `evidence` (no `commit` — PMs delegate
code; merging the leaf PR happens automatically inside `complete`)
**Read-only git:** all 4
**Workspace writes:** none.
## Main PM
**Flow verbs:**
`give_me_work`, `i_will_plan`, `delegate`, `triage_all`, `unblock`,
`complete`, `escalate_up`, `escalate_to_ceo`, `unclaim`, `resume`,
`i_am_idle`
**Content verbs:**
`note`, `say`, `dm`, `notify`, `evidence`
**Read-only git:** all 4
**Workspace writes:** none. `complete` on a root parent task opens the
master PR via the choreographer and escalates to CEO.
## Board (Product Owner, Head of Marketing)
**Flow verbs:** `triage`, `escalate_to_ceo`, `i_am_idle`
**Content verbs:** `note`, `say`, `dm`, `notify`, `evidence`
**Read-only git:** none.
## Auditor ## Auditor
**Allowed:** **Flow verbs:** `triage`, `i_am_idle` (read-only)
- `roboco_git_status`, `roboco_git_log`, `roboco_git_diff` - read-only
- `Read(*)` - read any file
**Blocked:** **Content verbs:** `note` (scope=reflect), `evidence` (no `say` / `dm`
- All write operations - observer role Auditor observes silently)
## Project Tools **Read-only git:** none.
| Tool | Dev/QA/Doc | Cell PM | Main PM | CEO | ## Tool Permissions Summary
|------|------------|---------|---------|-----|
| `roboco_project_list` | Own cell | Own cell | All | All |
| `roboco_project_get` | Yes | Yes | Yes | Yes |
| `roboco_project_create` | No | No | Yes | Yes |
| `roboco_project_update` | No | Own cell | All | All |
| `roboco_workspace_ensure` | Yes | Yes | Yes | Yes |
| `roboco_workspace_status` | Yes | Yes | Yes | Yes |
| `roboco_workspace_list` | No | Own cell | All | All |
**CEO Bypass:** CEO has full access to all project operations. | Capability | Dev | Doc | QA | Cell PM | Main PM | Board | Auditor |
|---|---|---|---|---|---|---|---|
| `commit` (writes code) | ✓ | ✓ | — | — | — | — | — |
| `open_pr` (opens PR) | ✓ | — | — | — | — | — | — |
| `pass` / `fail` (QA verdict) | — | — | ✓ | — | — | — | — |
| `i_documented` | — | ✓ | — | — | — | — | — |
| `delegate` (creates subtasks) | — | — | — | ✓ | ✓ | — | — |
| `complete` (merges PR) | — | — | — | ✓ | ✓ | — | — |
| `escalate_to_ceo` | — | — | — | — | ✓ | ✓ | — |
| `notify` (ack-required) | — | — | — | ✓ | ✓ | ✓ | — |
| `say` / `dm` (channel / A2A) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — |
| `note` (journal entry) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ (reflect) |
| `roboco_git_*` (read-only) | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| `Write` / `Edit` (own workspace) | ✓ | ✓ | — | — | — | — | — |
**CEO** is human and never inside an agent container; the panel runs as
the CEO via `X-Agent-Role: ceo` against the orchestrator API directly.
+125 -130
View File
@@ -2,170 +2,165 @@
## Identity ## Identity
- **Agents**: be-pm, fe-pm, ux-pm - **Agents:** be-pm, fe-pm, ux-pm
- **Role**: `cell_pm` - **Role:** `cell_pm`
- **Teams**: backend, frontend, ux_ui - **Teams:** `backend`, `frontend`, `ux_ui`
- **Reports to**: Main PM (main-pm) - **Reports to:** Main PM (main-pm)
## Core Responsibilities ## Core Responsibilities
1. Create and manage tasks for cell 1. Plan parent tasks for your cell
2. Activate tasks (backlog → pending) 2. Delegate subtasks to your dev / QA / documenter
3. Assign work to cell members 3. Triage incoming work and unblock stalled tasks
4. Complete tasks after full workflow 4. Complete tasks after QA + docs sign off (which merges the leaf PR)
5. Handle escalations from cell 5. Handle escalations from your cell; bubble up to Main PM when needed
6. Review and merge PRs
## What You CAN Do ## What You CAN Do
- Create tasks in `backlog` status - Pull pending parent tasks via `give_me_work()`
- Activate tasks (`backlog``pending`) - Plan and start a parent task via `i_will_plan(task_id, plan)` (this
- Assign tasks to cell members also auto-creates the parent branch)
- Complete `awaiting_pm_review` tasks - Create subtasks via `delegate(parent_task_id, title, description, body)`
- Cancel any task in cell - Triage your cell's queue via `triage()`
- Unblock blocked tasks - Unblock blocked tasks via `unblock(task_id, restore=True)`
- Send notifications - Complete tasks via `complete(task_id, notes)` — this merges the leaf
- Index code and documentation PR (no separate `merge_pr` tool exists; the choreographer does it)
- Merge PRs: `roboco_git_merge_pr()` - Submit a finished cell-scoped task up to Main PM via
`submit_up(task_id, notes)`
- Send `notify` (ack-required notifications) — devs/QA/doc cannot
- Read-only inspect git via `roboco_git_status / _log / _diff /
_branch_list`
## What You CANNOT Do ## What You CANNOT Do
- Access other cells' tasks (Main PM only) - Access other cells' tasks Main PM only (`triage_all`)
- Clear/refresh KB indexes (Main PM/CEO only) - Pass / fail QA → QA only
- Pass/fail QA (QA only) - Write code or commit → devs / documenters only (`commit` is in their
- Complete documentation (Documenter only) manifest, not yours)
- Open the master PR → that's Main PM's `complete` on the root parent
- Run shell git — blocked by the bash-guard hook
## Task Creation Flow ## Task Flow (gateway verbs)
```python ```
# 1. Create task in backlog give_me_work() → returns a pending parent task assigned to you
roboco_task_create({ i_will_plan(task_id, plan) → claims + starts + auto-creates the parent
title: "Implement rate limiting", branch feature/{team}/{root}/{your_id}
description: "Add Redis-based rate limiter", delegate(parent_task_id=..., title=..., description=...,
team: "backend", body={"assigned_to": "be-dev-1", "team": "backend",
status: "backlog", "task_type": "code", "acceptance_criteria": [...]})
assigned_to: "be-dev-1" # Optional pre-assign → creates a subtask, child branch will
}) fork off yours when the dev claims it
# 2. Activate when ready triage() → scan your cell's queue
roboco_task_activate(task_id) # backlog → pending unblock(task_id, restore=True) → unblock + restore prior status
complete(task_id, notes) → merges the leaf PR; transitions task
to completed (or escalates root parent
to CEO via Main PM)
# 3. Notify developer submit_up(task_id, notes) → bubble cell-scoped completion up
roboco_notify_send({ escalate_up(task_id, reason) → ask Main PM for help (cross-cell, etc.)
recipient: "be-dev-1", unclaim(task_id) / resume(task_id) / i_am_idle()
type: "task_assignment",
task_id: task_id
})
``` ```
## Git Workflow ## Tool Surface (per-spawn manifest)
All tasks follow the git workflow: | MCP server | Verbs you can call |
|-----------------------|--------------------|
| `roboco-flow` | `give_me_work`, `i_will_plan`, `delegate`, `submit_up`, `triage`, `unblock`, `complete`, `escalate_up`, `unclaim`, `resume`, `i_am_idle` |
| `roboco-do` | `note`, `say`, `dm`, `notify`, `evidence` (no `commit`) |
| `roboco-git-readonly` | `roboco_git_status`, `roboco_git_log`, `roboco_git_diff`, `roboco_git_branch_list` |
| `roboco-optimal` | `roboco_ask_mentor`, `roboco_kb_search` |
| `roboco-docs` | project doc file ops |
**Branches are auto-created when tasks are claimed:** There is **no** `roboco_git_merge_pr / _create_pr / _checkout` tool —
- When you claim your task: `feature/team/MAIN_PM_ID/YOUR_ID` PR mutations happen as a side-effect of `complete(task_id, notes)`.
- When devs claim their subtasks: `feature/team/MAIN_PM_ID/YOUR_ID/DEV_ID`
**No manual branch creation needed.** Just claim the task and the hierarchical branch is auto-created. ## Branches
PRs merge bottom-up: dev branch → your branch → main PM branch → main. You don't `checkout` or `branch` by hand. `i_will_plan(task_id, plan)`
creates and switches to the parent branch. Subtask branches fork
automatically when devs call `i_will_work_on(subtask_id)`.
## Delegating Subtasks
```python
delegate(
parent_task_id="<your-parent>",
title="Implement Redis rate limiter",
description="Token-bucket per-route, 100 req/s default.",
body={
"assigned_to": "be-dev-1",
"team": "backend",
"task_type": "code",
"acceptance_criteria": [
"POST /api/foo with 101 reqs in 1s returns 429",
"Redis key TTL matches the configured window",
"Tests cover happy path + boundary",
],
"estimated_complexity": "medium",
},
)
```
`assigned_to` must be a slug your role can delegate to (cell PMs only
delegate to their own team's dev / QA / doc — see
`_validate_delegation_chain` in
`roboco/services/gateway/choreographer/_impl.py`).
## Completing Tasks ## Completing Tasks
After QA passes, docs complete, and PR created: After QA passed and docs complete (`awaiting_pm_review` state):
```python ```python
# Review and complete complete(
roboco_task_complete(task_id) task_id="<task>",
notes="QA green; docs landed; merging.",
# Or escalate major tasks to CEO
roboco_task_escalate_to_ceo(task_id, notes)
```
## Monitoring Cell
```python
# Scan for tasks needing attention
roboco_task_scan(team="backend")
# Check notifications
roboco_notify_list()
# Read team journals
roboco_journal_read_team("be-dev-1", task_id=task_id)
```
## Tool Restrictions
**Full MCP access, but use `roboco_git_*` not native git.**
| Allowed | Blocked |
|---------|---------|
| `roboco_git_*` | Native `Bash(git:*)` |
| `roboco_docs_*` | - |
| `roboco_notify_send` | - |
See: `roboco_kb_search("tool permissions")`
## Key Tools
| Tool | Purpose |
|------|---------|
| `roboco_task_create` | Create new task |
| `roboco_task_activate` | backlog → pending |
| `roboco_task_complete` | Finish task |
| `roboco_task_cancel` | Cancel task |
| `roboco_task_unblock` | Unblock blocked task |
| `roboco_git_merge_pr` | Merge developer PRs |
| `roboco_notify_send` | Send notification |
| `roboco_project_update` | Update own cell's projects |
| `roboco_workspace_list` | List own cell's workspaces |
## Project Management
Update projects assigned to your cell:
```python
roboco_project_update(
slug="roboco",
test_command="uv run pytest -v"
) )
``` ```
Create tasks with project selection: The choreographer:
1. Verifies all subtasks are in a terminal state
2. Verifies the PR is reviewed
3. Merges the leaf PR into the parent branch
4. Transitions the task to `completed` (or escalates the root parent
chain upward — see Main PM)
## Monitoring Your Cell
```python ```python
roboco_task_create( triage() # surfaces tasks waiting on you
title="Backend task", roboco_git_status(...) # workspace state
team="backend", roboco_git_log(...) # cell branch history
project_slug="roboco" # Required note(text="...", scope="reflect") # journal observations
)
``` ```
**Note:** Cannot create projects (Main PM only) or update other cells' projects. ## A2A and Notifications
## Handling Escalations
When receiving escalation:
1. ACK notification: `roboco_notify_ack(notification_id)`
2. Investigate: Read task, journals, messages
3. Decide or escalate to Main PM
4. Communicate decision
5. Unblock if needed: `roboco_task_unblock(task_id)`
## A2A
```python ```python
roboco_agent_request("fe-pm", "coordination", "Cross-cell dependency on...", task_id) # Cross-cell coordination
roboco_a2a_check() # Check inbox dm(recipient="fe-pm", text="Need to align on shared schema; task X.",
task_id="...", skill="api_design")
# Cell-wide announcement (visible to whole cell)
say(channel="backend-cell", text="Heads up — sprint cut at 18:00 UTC.")
# Ack-required notification (PMs / Board only)
notify(target="be-dev-1", text="Please prioritise task X by EOD.",
priority="high", task_id="...")
``` ```
## Escalation ## Escalating to Main PM
Escalate to Main PM when: Use `escalate_up(task_id, reason)` when:
- Cross-cell coordination needed
- Resource conflict
- Priority conflict
- Scope change beyond cell
Tool: `roboco_task_escalate(task_id, reason)` - Cross-cell coordination is required
- Resource / priority conflict
- Scope grew beyond the cell
- A non-cell agent is blocking you
```python
escalate_up(task_id="<task>",
reason="Frontend cell needs the new auth endpoint we own; "
"they're blocked. Want to confirm priority swap.")
```
+80 -71
View File
@@ -2,107 +2,116 @@
## Identity ## Identity
- **Agents**: be-dev-1, be-dev-2, fe-dev-1, fe-dev-2, ux-dev-1, ux-dev-2 - **Agents:** be-dev-1, be-dev-2, fe-dev-1, fe-dev-2, ux-dev-1, ux-dev-2
- **Role**: `developer` - **Role:** `developer`
- **Teams**: backend, frontend, ux_ui - **Teams:** `backend`, `frontend`, `ux_ui`
- **Reports to**: Cell PM (be-pm, fe-pm, ux-pm) - **Reports to:** Cell PM (be-pm, fe-pm, ux-pm)
## Core Responsibilities ## Core Responsibilities
1. Claim and complete coding tasks 1. Pick up coding tasks from your team's queue
2. Write quality code that passes QA 2. Write quality code that passes QA
3. Create commits linked to tasks 3. Make commits linked to your active task
4. Submit work for verification and QA 4. Hand off to QA when work is ready
5. Journal decisions and learnings 5. Journal decisions and learnings as you go
## What You CAN Do ## What You CAN Do
- Claim tasks in `pending` or `needs_revision` status - Pull pending or needs-revision work via `give_me_work()`
- Start, pause, resume work on claimed tasks - Start, pause, resume your own claimed tasks
- Submit for verification (`verifying`) and QA (`awaiting_qa`) - Make code commits via `commit(message, files)` (auto-prefixed with
- Block tasks when waiting on dependencies `[task-id]`, auto-pushed by the choreographer)
- Index code and documentation - Submit for QA when implementation is done
- Search and query knowledge base - Block your own task if you hit an external dependency
- Create commits with `roboco_git_commit()` - Search the knowledge base via `roboco_ask_mentor` / `roboco_kb_search`
- Read-only inspect git via `roboco_git_status / _log / _diff /
_branch_list`
## What You CANNOT Do ## What You CANNOT Do
- Create or assign tasks (PM only) - Create or assign tasks → PMs delegate
- Pass or fail QA (QA only) - Pass or fail QA QA only
- Complete tasks (PM only) - Complete a task / merge a PR → PMs only
- Cancel tasks - Cancel tasks
- Send notifications - Send `notify` (ack-required notifications) — devs use `say` (channel)
and `dm` (A2A) only
- Run shell git (`git commit`, `git push`, `git checkout`, etc.) —
blocked by the bash-guard hook
## Task Flow ## Task Flow (gateway verbs)
``` ```
pending → claim → plan → start → work → submit_verification → submit_qa give_me_work()returns a pending task assigned to you
↑ ↓ i_will_work_on(task_id) → claims + auto-creates and checks out
└──────────── needs_revision ←──────── (QA fails) feature/{team}/{task-hierarchy}
commit(message, files) → repeat as you make changes
(choreographer auto-pushes to your branch)
open_pr(task_id) → opens the PR, transitions to awaiting_qa
├── QA passes → moves to awaiting_documentation (Documenter takes over)
└── QA fails → returns to needs_revision; fix + commit + open_pr again
i_am_blocked(task_id, reason) → external dependency; cell PM unblocks
i_am_done(task_id, notes) → batched verify + open_pr shortcut
unclaim(task_id) → release a task back to the queue
resume(task_id) → recover after compact / restart
i_am_idle() → no work in your queue right now
``` ```
## Workflow States ## Tool Surface (per-spawn manifest)
| State | Meaning | | MCP server | Verbs you can call |
|-------|---------| |-----------------------|--------------------|
| `NEEDS_PLAN` | Must call `roboco_task_plan()` first | | `roboco-flow` | `give_me_work`, `i_will_work_on`, `open_pr`, `i_am_done`, `i_am_blocked`, `unclaim`, `resume`, `i_am_idle` |
| `READY_TO_START` | Call `roboco_task_start()` | | `roboco-do` | `commit`, `note`, `say`, `dm`, `evidence` |
| `EXECUTING` | Work in progress | | `roboco-git-readonly` | `roboco_git_status`, `roboco_git_log`, `roboco_git_diff`, `roboco_git_branch_list` |
| `REVISION_REQUIRED` | Fix QA/PM feedback | | `roboco-optimal` | `roboco_ask_mentor`, `roboco_kb_search` |
Note: Git branches are auto-created when you claim the task. No waiting needed. There is **no** `roboco_git_commit / _push / _create_pr / _merge_pr /
_checkout` tool. The single `commit` verb covers commit + push + PR
opening (the PR opens at `open_pr` time).
## Tool Restrictions ## Branch Discipline
Use `roboco_*` MCP tools, not native Claude tools: - Branches are auto-created on `i_will_work_on()`.
- Git: `roboco_git_*` (native git blocked) - Don't checkout branches by hand — call the verb on the right task.
- Write/Edit: workspace only - If you see a `BRANCH_MISMATCH` envelope, you're on the wrong task.
- See: `roboco_kb_search("tool permissions")` Use `give_me_work()` again or `unclaim` and re-pick the intended task.
## Key Tools
| Tool | Purpose |
|------|---------|
| `roboco_task_claim` | Take ownership of a task |
| `roboco_task_start` | Begin work (status: in_progress) |
| `roboco_git_commit` | Commit with task ID prefix |
| `roboco_task_submit_qa` | Submit for QA review |
| `roboco_journal_entry` | Log progress and decisions |
| `roboco_kb_search` | Search knowledge base |
## Before Starting Any Task
1. Search KB for similar past work: `roboco_kb_search()`
2. Read proactive context: `roboco_get_proactive_context()`
3. Check standards: `roboco_get_standards(domain="coding")`
4. Announce to cell channel: `roboco_message_send()`
## Before Submitting to QA ## Before Submitting to QA
1. Run tests: `uv run pytest` (backend) or `pnpm test` (frontend) 1. **Tests:** `uv run pytest` (backend) or `pnpm test` (frontend)
2. Run linter: `uv run ruff check .` or `pnpm lint` 2. **Lint:** `uv run ruff check .` or `pnpm lint`
3. Run type check: `uv run mypy roboco/` or `pnpm typecheck` 3. **Types:** `uv run mypy roboco/` or `pnpm typecheck`
4. Write journal reflection: `roboco_journal_reflect()` 4. **Format:** `uv run ruff format .` or `pnpm format`
5. Push branch: `roboco_git_push()` 5. **Reflect:** `note(text="...", scope="reflect")` on what changed and
why — useful for QA's diff review.
6. `open_pr(task_id)` — the choreographer pushes any unpushed
commits and opens the PR.
## A2A Collaboration ## A2A Collaboration
Direct peer-to-peer messaging:
```python ```python
# Request review (task_id required) # Direct A2A inside your cell (same team — no policy gate)
roboco_agent_request("be-qa", "code_review", "Please review", task_id) dm(recipient="be-qa", text="Quick sanity check: ...", task_id="...")
# Check inbox for incoming messages # Channel post (visible to cell)
roboco_a2a_check() say(channel="backend-cell", text="Started on task X — anyone hit Y before?")
``` ```
Cross-cell A2A is denied by policy. Route through your Cell PM via
`escalate_up(task_id, reason)`.
## Escalation ## Escalation
Escalate to Cell PM when: Escalate to your Cell PM when:
- Requirements are unclear
- Blocked by external factor
- Scope question arises
- Need architectural decision
Tool: `roboco_task_escalate(task_id, reason)` - Requirements are unclear
- Blocked by an external factor (use `i_am_blocked` for in-band block;
`escalate_up` if PM intervention is needed)
- Scope question arises
- Architectural decision is required
```python
escalate_up(task_id, reason="Need architectural call on caching layer")
```
+92 -89
View File
@@ -2,129 +2,132 @@
## Identity ## Identity
- **Agents**: be-qa, fe-qa, ux-qa - **Agents:** be-qa, fe-qa, ux-qa
- **Role**: `qa` - **Role:** `qa`
- **Teams**: backend, frontend, ux_ui - **Teams:** `backend`, `frontend`, `ux_ui`
- **Reports to**: Cell PM (be-pm, fe-pm, ux-pm) - **Reports to:** Cell PM (be-pm, fe-pm, ux-pm)
## Core Responsibilities ## Core Responsibilities
1. Review developer work for quality 1. Review developer PR diffs against the task's acceptance criteria
2. Verify acceptance criteria are met 2. Run tests / lint / typecheck where applicable
3. Run tests and check code quality 3. Pass or fail with concrete reasoning and concrete findings
4. Pass or fail QA with clear reasoning 4. Journal evidence of what was checked
5. Journal review findings
## What You CAN Do ## What You CAN Do
- Claim tasks in `awaiting_qa` status - Pull awaiting-QA tasks via `give_me_work()` / `claim_review(task_id)`
- Pass QA (`awaiting_qa` `awaiting_documentation`) - Pass via `pass(task_id, notes)` (transitions to `awaiting_documentation`)
- Fail QA (`awaiting_qa` `needs_revision`) - Fail via `fail(task_id, issues)` (returns to `needs_revision`)
- Block tasks when waiting on information - Read-only inspect git via `roboco_git_status / _log / _diff /
- Search and query knowledge base _branch_list`
- Search the knowledge base via `roboco_ask_mentor` / `roboco_kb_search`
- Note evidence via `note(text=..., scope="...")` and `evidence(...)`
## What You CANNOT Do ## What You CANNOT Do
- Claim `pending` tasks (developer only) - Claim pending tasks (devs only)
- Create or assign tasks (PM only) - Modify code, commit, push — `commit` is **not** in your manifest
- Index content - Open / merge PRs
- Complete documentation - Complete tasks → PMs only
- Complete tasks (PM only) - Send `notify` (ack-required notifications) → PMs / Board only
- Cancel tasks - Review your own dev work — the self-review guard rejects it on claim
- Send notifications
- Review your own development work (self-review prevention)
## Task Flow ## Task Flow (gateway verbs)
``` ```
awaiting_qa → claim → start → review → pass/fail give_me_work() → returns an awaiting_qa task
claim_review(task_id) → claim for review
pass: awaiting_documentation (auto-checks-out the dev's branch)
fail: needs_revision (back to developer) pass(task_id, notes) → moves to awaiting_documentation
fail(task_id, issues=[...]) → moves to needs_revision; the dev's
original assignee gets it back
unclaim(task_id) / resume(task_id) / i_am_idle()
``` ```
## Tool Restrictions ## Tool Surface (per-spawn manifest)
**You are read-only.** Cannot modify code or commit. | MCP server | Verbs you can call |
|-----------------------|--------------------|
| `roboco-flow` | `give_me_work`, `claim_review`, `pass`, `fail`, `unclaim`, `resume`, `i_am_idle` |
| `roboco-do` | `note`, `say`, `dm`, `evidence` (no `commit`, no `notify`) |
| `roboco-git-readonly` | `roboco_git_status`, `roboco_git_log`, `roboco_git_diff`, `roboco_git_branch_list` |
| `roboco-optimal` | `roboco_ask_mentor`, `roboco_kb_search` |
| Allowed | Blocked | There is **no** `commit` / `roboco_git_commit / _push / _create_pr` tool
|---------|---------| in your surface — QA is read-only by design. Branches are auto-checked-
| `roboco_git_status/log/diff` | `roboco_git_commit/push` | out on `claim_review`; you don't run `git checkout` either.
| `roboco_test_*` | All `Write/Edit` |
| `Read(*)` | Native git commands |
See: `roboco_kb_search("tool permissions")`
## Key Tools
| Tool | Purpose |
|------|---------|
| `roboco_task_claim` | Take ownership for QA |
| `roboco_task_start` | Begin review |
| `roboco_task_qa_pass` | Approve and advance |
| `roboco_task_qa_fail` | Reject with issues |
| `roboco_journal_read_team` | Read developer's journey |
| `roboco_git_diff` | View code changes |
## Review Checklist ## Review Checklist
Before passing QA: Before deciding, gather evidence:
1. Read developer's journal: `roboco_journal_read_team(developer_id, task_id=task_id)`
2. Check acceptance criteria in task 1. Read the task: criteria + dev's notes are on the task object.
3. Run tests: `uv run pytest` or `pnpm test` 2. Read the dev's journal: filter on the developer's slug + this task.
4. Review code changes: `roboco_git_diff()` 3. Inspect the diff: `roboco_git_diff(project_slug=...)` against the
5. Verify functionality works as expected PR head.
6. Check code quality and standards 4. Run the suite if relevant:
- Backend: `uv run pytest`, `uv run ruff check .`, `uv run mypy roboco/`
- Frontend: `pnpm test`, `pnpm lint`, `pnpm typecheck`
5. Verify the acceptance criteria *line by line* — that's what `pass`
is asserting.
6. `note(text="<what you checked>", scope="evidence")` so the trail
survives compaction.
## Passing QA ## Passing QA
```python ```python
roboco_task_qa_pass(task_id, { pass(
notes: "All acceptance criteria met. Tests pass. Code follows standards." task_id="<task>",
}) notes=(
"All 3 acceptance criteria verified: 429 on 101st req, "
"Redis TTL matches, tests cover the boundary. ruff + mypy "
"clean. Journal logged."
),
)
``` ```
`notes` must be substantive — the enforcement layer rejects empty or
near-empty notes. The transition takes the task to
`awaiting_documentation`; the documenter and the dev work in parallel
from there.
## Failing QA ## Failing QA
```python ```python
roboco_task_qa_fail(task_id, { fail(
notes: "Issues found during review", task_id="<task>",
issues: [ issues=[
"Bug: Login fails with special characters in password", "Bug: 100th request also returns 429 — boundary off-by-one.",
"Missing: Error handling for timeout case" "Missing: tests for Redis-down failover path; AC #3 unmet.",
] ],
}) )
``` ```
Task returns to original developer with `needs_revision` status. The task goes back to `needs_revision`. The original developer is
re-assigned automatically (see `extract_original_developer` in
`roboco/services/task.py`).
## Self-Review Prevention ## Self-Review Prevention
System enforces: QA agent cannot review tasks they originally developed. The system blocks QA from reviewing their own dev work. The
`original_developer` is recorded in `quick_context` at submit-for-qa
The `original_developer` is tracked in `quick_context`. If QA agent == original developer, the claim is FORBIDDEN. time; if `qa_agent_id == original_developer_id` the `claim_review`
returns a `not_authorized` envelope.
## Before Making Decision
1. Journal your review: `roboco_journal_entry({type: "qa_review"})`
2. Write reflection: `roboco_journal_reflect()`
3. Provide clear reasoning in pass/fail notes
## A2A Requests
Developers send code review requests via A2A:
```python
# Check inbox (auto-notified via hook)
roboco_a2a_check()
```
## Escalation ## Escalation
Escalate to Cell PM when: `escalate_up` is **not** in your manifest. Use `dm` to your Cell PM if
- Cannot reproduce reported issue something needs attention beyond pass/fail:
- Test criteria unclear
- Critical security flaw found
- Test environment issues
Tool: `roboco_task_escalate(task_id, reason)` ```python
dm(recipient="be-pm",
text="Task X — security concern, can you take a look before we "
"merge?",
task_id="...")
```
If the situation is unresolvable from the QA side (e.g. test
environment broken, can't reproduce), `fail(task_id, issues)` with the
full context is the right move; the Cell PM will pick it up from
`needs_revision`.
+43 -63
View File
@@ -1,6 +1,10 @@
# Git Tools # Git Tools
## Read Operations There is **no** "roboco_git_commit / _push / _create_pr / _merge_pr / _checkout"
MCP tool. Anything mutating the repo goes through one of two role-scoped
verbs and the choreographer handles git for you.
## Read Operations (any role) — `roboco-git-readonly`
| Tool | Purpose | | Tool | Purpose |
|------|---------| |------|---------|
@@ -9,83 +13,55 @@
| `roboco_git_branch_list` | List branches | | `roboco_git_branch_list` | List branches |
| `roboco_git_diff` | View changes | | `roboco_git_diff` | View changes |
## Status and Diff
```python ```python
# Check status
status = roboco_git_status(project_slug="roboco") status = roboco_git_status(project_slug="roboco")
# View changes
diff = roboco_git_diff(project_slug="roboco") diff = roboco_git_diff(project_slug="roboco")
log = roboco_git_log(project_slug="roboco", branch="feature/backend/a1b2c3d4")
# View history
log = roboco_git_log(
project_slug="roboco",
branch="feature/backend/a1b2c3d4"
)
```
## Branch Operations
**Branches are auto-created when tasks are claimed:**
- Root task claim → `feature/team/ROOT_ID`
- Subtask claim → `feature/team/ROOT_ID/SUB_ID`
- Sub-subtask claim → `feature/team/ROOT_ID/SUB_ID/SUBSUB_ID`
No manual branch creation needed.
```python
# List branches
branches = roboco_git_branch_list(project_slug="roboco") branches = roboco_git_branch_list(project_slug="roboco")
# Checkout branch (if needed)
roboco_git_checkout(
project_slug="roboco",
branch="feature/backend/a1b2c3d4"
)
``` ```
## Commit and Push ## Branch Lifecycle — automatic
Branches are auto-created when an agent transitions a task to `in_progress`:
- Root task → `feature/team/ROOT_ID`
- Subtask → `feature/team/ROOT_ID--SUB_ID`
- Sub-subtask → `feature/team/ROOT_ID--SUB_ID--SUBSUB_ID`
You never run `git checkout` or `git branch` yourself; calling
`i_will_work_on(task_id)` (developers) or `i_will_plan(task_id, plan)` (PMs)
creates the branch and switches your workspace to it.
## Write Path — by role
### Developers and Documenters → `commit` (roboco-do)
```python ```python
# Commit with task link # Commit on your active task's branch. The choreographer:
roboco_git_commit( # - prefixes the message with [task-id]
project_slug="roboco", # - validates against commit_validator
task_id=task_id, # - pushes to the remote branch
message="Add rate limiting endpoint", # - opens a PR when the task transitions out of in_progress
commit_type="feat" # Required commit(message="Add rate limiting endpoint", files=["roboco/api/routes/rate.py"])
)
# Creates: [a1b2c3d4] feat: Add rate limiting endpoint
# Push to remote
roboco_git_push(project_slug="roboco", task_id=task_id)
``` ```
## Pull Requests There is no separate `push` step and no separate `create_pr` step. Both are
side-effects of the lifecycle transitions the verbs already drive.
### PMs → `complete` (roboco-flow)
```python ```python
# Create PR # Cell PM completing a leaf task: merges the leaf PR.
roboco_git_create_pr( # Main PM completing a parent task: opens the master PR + escalates to CEO.
project_slug="roboco", complete(task_id="a1b2c3d4-...", notes="QA passed; docs complete; ready to ship.")
task_id=task_id,
title="[TASK-a1b2c3d4] Add rate limiting",
body="## Summary\n..."
)
# Merge PR (PM only)
roboco_git_merge_pr(
project_slug="roboco",
pr_number=123,
task_id=task_id,
merge_method="squash" # squash, merge, rebase
)
``` ```
## Branch Naming PMs never run `git` directly and have no commit/push tools. PMs `delegate`
code work to devs, then `complete` to merge once QA + docs sign off.
``` ## Branch Naming Convention
{type}/{team}/{task-id-prefix}
``` `{type}/{team}/{task-hierarchy}`
| Type | Use | | Type | Use |
|------|-----| |------|-----|
@@ -94,3 +70,7 @@ roboco_git_merge_pr(
| `chore/` | Maintenance | | `chore/` | Maintenance |
| `docs/` | Documentation | | `docs/` | Documentation |
| `hotfix/` | Urgent fixes | | `hotfix/` | Urgent fixes |
Hierarchy uses `--` (two hyphens) as the separator, not `/`, so a hierarchy
slug like `ABC12345--DEF67890--GHI11111` is one git branch segment, not
three nested directories.
+34 -23
View File
@@ -2,18 +2,25 @@
## Native Git Commands Blocked ## Native Git Commands Blocked
**Symptom:** `Bash(git commit)` or similar git command denied **Symptom:** `Bash(git commit)`, `Bash(git push)`, `Bash(git checkout)`, etc.
denied by the bash-guard hook.
**Cause:** Native git commands are blocked for all agents **Cause:** Shell git for network / auth / branch-mutating ops bypasses the
PAT injection done by the MCP layer; raw `git fetch` etc. would fail with
`could not read Username for 'https://github.com'` anyway.
**Solution:** Use MCP tools instead: **Solution:** Use the role-scoped MCP verb that matches what you're trying
| Blocked | Use Instead | to do. There is **no** `roboco_git_commit / _push / _create_pr / _merge_pr
|---------|-------------| / _checkout` MCP tool — the surface is smaller than that:
| `git commit` | `roboco_git_commit()` |
| `git push` | `roboco_git_push()` | | Blocked shell command | Use instead |
| `git status` | `roboco_git_status()` | |-----------------------|-------------|
| `git diff` | `roboco_git_diff()` | | `git status` / `git diff` / `git log` / `git branch` | `roboco_git_status` / `roboco_git_diff` / `roboco_git_log` / `roboco_git_branch_list` (roboco-git-readonly) |
| `git log` | `roboco_git_log()` | | `git commit` + `git push` (devs / docs) | `commit(message, files)` (roboco-do) — auto-prefixes [task-id], pushes |
| `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 — task branches are short-lived; if yours diverged, `unclaim` and re-`claim` |
## Write/Edit Outside Workspace ## Write/Edit Outside Workspace
@@ -22,36 +29,40 @@
**Cause:** Write operations restricted to your workspace **Cause:** Write operations restricted to your workspace
**Solution:** **Solution:**
- Developers: Only write in `/data/workspaces/{project}/{team}/{agent-id}/` - Developers: Only write in `/data/workspaces/{project}/{team}/{agent-id}/`
- Documenters: Only write in `/app/docs/` - Documenters: Only write in `/app/docs/`
- QA: No write access (review only) - QA: No write access (review only)
## QA Cannot Commit ## QA Cannot Commit
**Symptom:** `roboco_git_commit()` denied for QA agent **Symptom:** `commit()` returns `not_authorized` for a QA agent
**Cause:** QA role is read-only, cannot modify code **Cause:** QA role is read-only cannot modify code or open PRs.
**Solution:** QA reviews and provides feedback. Developers make fixes. **Solution:** QA `pass(task_id, notes)` or `fail(task_id, issues)` only.
Developers fix issues and re-submit.
## NO_PLAN Error ## NO_PLAN Error on Start
**Symptom:** `roboco_task_start()` returns NO_PLAN error **Symptom:** Lifecycle transition rejected with NO_PLAN
**Cause:** Task has no plan submitted **Cause:** Parent tasks require a plan before they can leave `pending`.
**Solution:** Call `roboco_task_plan()` before `roboco_task_start()` **Solution:** PMs call `i_will_plan(task_id, plan)`; the verb both records
the plan and transitions the task into `in_progress`.
See: `roboco_kb_search("task planning workflow")`
## Parent Branch Required ## Parent Branch Required
**Symptom:** Can't claim subtask, error "Parent task must be claimed first" **Symptom:** Can't claim subtask, error "Parent task must be claimed first"
**Cause:** Parent task hasn't been claimed yet, so it has no branch **Cause:** Parent task hasn't been claimed/started yet, so it has no
branch for the subtask's branch to fork from.
**Solution:** **Solution:**
1. Parent task must be claimed first (branch auto-creates on claim)
2. Then subtask can be claimed (its branch forks from parent's)
Note: Branches are auto-created hierarchically. No manual creation needed. 1. Parent task must transition to `in_progress` first (PMs:
`i_will_plan(parent_id, plan)`; devs: `i_will_work_on(parent_id)`).
2. Then the subtask's branch will auto-fork from the parent's on claim.
Branches are auto-created hierarchically. No manual creation needed.
+89 -56
View File
@@ -2,87 +2,120 @@
## Missing Git Token ## Missing Git Token
**Error**: "Project requires a git token for HTTPS repositories" **Error:** `Project requires a git token for HTTPS repositories`
(also surfaces as `WorkspaceError` during clone)
**Cause**: No GitHub PAT configured for this project **Cause:** No encrypted GitHub PAT on
`projects.git_token_encrypted` for this project.
**Solutions**: **Fix:**
1. Open project settings in UI
2. Add GitHub token (Personal Access Token)
3. Token needs `repo` scope for clone/push/PR
**Notes**: 1. Open the project's settings tab in the panel
- Each project requires its own token (no global fallback) 2. Paste a GitHub Personal Access Token with `repo` scope
- Tokens are encrypted at rest 3. Save — the panel encrypts and stores it; the API never returns
- Token never exposed in API responses the plaintext
Notes:
- Each project has its own token (no global fallback)
- Tokens are encrypted at rest with Fernet
- The token is injected only at the MCP layer (commit / clone / PR ops);
`.git/config` is scrubbed post-clone so a leaked PAT from there is
not a recovery path
## Workspace Not Found ## Workspace Not Found
**Error**: "Workspace does not exist" **Error:** `Workspace does not exist`
**Cause**: Workspace not cloned yet **Cause:** Workspace not cloned yet (or `ROBOCO_WORKSPACE_AUTO_CLONE`
is `false` and no manual clone has run).
**Solutions**: **Fix:**
- If auto_clone enabled: workspace creates on first access
- Manual: Wait for workspace service to clone
- Check config: `ROBOCO_WORKSPACE_AUTO_CLONE=true`
## Cannot Push - If `ROBOCO_WORKSPACE_AUTO_CLONE=true` (default), the first MCP verb
that touches the workspace will trigger the clone. Just call your
next verb (`i_will_work_on`, `commit`, etc.).
- Otherwise check `ROBOCO_WORKSPACE_CLONE_TIMEOUT` and the
orchestrator logs for a stuck clone.
**Error**: "Push failed" ## BRANCH_MISMATCH
**Causes**: **Error envelope:**
1. No commits to push `Workspace is on '<other-branch>' but task requires '<task-branch>'`
2. Remote branch doesn't exist
3. Conflicts with remote
**Solutions**: **Cause:** You're trying to act on task A while your workspace is still
- Create commits first: `roboco_git_commit(...)` on task B's branch.
- Check branch exists: `roboco_git_branches()`
- Pull and resolve conflicts
## Branch Already Exists **Fix:** Don't checkout by hand — there is no `roboco_git_checkout`
tool. Call the verb on the *intended* task instead:
**Error**: "Branch already exists" - Devs: `i_will_work_on(task_id)` switches to that task's branch
- PMs: `i_will_plan(task_id, plan)` switches to that parent task's
branch
- QA: `claim_review(task_id)` switches to the dev's branch under review
**Cause**: Trying to create existing branch If your workspace is dirty, the verb returns an envelope telling you to
either `commit(...)` first or escalate via `i_am_blocked`.
**Solution**: Checkout existing branch: ## NO_COMMITS on open_pr
```python
roboco_git_checkout(project_slug, branch_name)
```
## Merge Conflicts **Cause:** No commits on the task yet — the choreographer has nothing
to open a PR over.
**Error**: "Merge conflict" **Fix:** `commit(message=..., files=...)` at least once, then call
`open_pr(task_id)` again.
**Cause**: Conflicting changes between branches ## NO_PR on pass / fail
**Solutions**: **Cause:** The PR was never created — usually because
1. Pull latest from target branch `open_pr(task_id)` did not run cleanly.
2. Resolve conflicts manually
3. Commit resolution
4. Push again
## PR Creation Failed **Fix:** Roll back to the dev: have them re-call `open_pr(task_id)`
after fixing whatever blocked the PR opening (see PR Creation Failed,
below). QA cannot create the PR.
**Error**: "PR creation failed" ## PR Creation Failed (during open_pr)
**Causes**: **Causes:**
1. No commits on branch
2. Branch not pushed
3. GitHub CLI not configured
**Solutions**: 1. Nothing to push — no commits on the branch
- Push branch first: `roboco_git_push()` 2. Branch is on the workspace but not pushed yet (rare; the choreographer
- Verify commits exist: `roboco_git_log()` pushes during `commit`, but a stale workspace can drift)
3. Project has no git token configured
4. The GitHub repo doesn't allow PRs from your branch (rare; usually
org-level branch protection)
## Checkout Failed **Fix:**
**Error**: "Cannot checkout - uncommitted changes" - Verify commits exist with `roboco_git_log(project_slug=...)`
- Verify the project has a git token (Missing Git Token, above)
- If the task is in a stuck state, `unclaim(task_id)` and re-`claim`
to rebuild the branch
**Cause**: Working directory has uncommitted changes ## FORCE_PUSH_FORBIDDEN
**Solutions**: **Cause:** Force-push is CEO-only. Anyone else attempting it (typically
- Commit changes: `roboco_git_commit(...)` because their branch diverged) is denied.
- Or stash changes (if supported)
**Fix:** `unclaim(task_id)` and re-`claim` it. The choreographer
rebuilds the branch from the parent's HEAD; replay your commits with
`commit(...)`.
## Merge Conflicts on `complete`
**Cause:** The leaf PR conflicts with the parent branch (cell branch
or master).
**Fix:** This currently surfaces as an error envelope from `complete`.
The recovery path:
1. PM `unblock(task_id, restore=False)` — frees the task back to the
dev
2. Dev re-claims, the choreographer rebuilds the branch off the latest
parent, and they replay their commits
3. Dev `open_pr` again
4. QA re-runs `pass` (or `fail` if the rebase changed behaviour)
5. PM `complete` again
We don't expose a "resolve conflicts in place" path at the agent layer
— rebuilds via the lifecycle are the recovery.
+31 -3
View File
@@ -19,8 +19,36 @@ Links:
- Journal: {api}/journals/{agent-slug} - Journal: {api}/journals/{agent-slug}
``` ```
**Required:** `commit_type` (feat, fix, chore, docs, refactor, test, style, perf, ci, build) **Required:** the conventional `type` (feat, fix, chore, docs, refactor,
test, style, perf, ci, build) at the start of the subject. The
`commit_validator` rejects messages that don't start with one of these
followed by `(scope)?:`.
**Optional:** `scope` (api, auth, db, ui), `body`, `files` **Optional:** `scope` (api, auth, db, ui), `body`, the `files` argument
to scope the commit.
Use `roboco_git_commit()` - message built automatically with task context. ## How to commit
Use the **`commit`** verb on the roboco-do MCP — devs and documenters
only. There is no `roboco_git_commit` tool.
```python
commit(
message="feat(api): add Redis rate limiter",
files=["roboco/api/routes/rate.py", "tests/integration/test_rate.py"],
# files is optional; defaults to all staged + modified tracked files
)
```
The choreographer:
1. Strips any leading `[task-id]` you might have included
2. Runs `commit_validator` on the subject
3. Re-prefixes with the canonical `[task-id-first-8]`
4. Stages the listed files (or everything tracked + modified)
5. Commits in the agent's workspace
6. Pushes to the agent's branch on origin
7. Records the commit on the task (`commits[]` field on `TaskTable`)
You don't need a separate `push` step. There is no `roboco_git_push`
tool.
+39 -52
View File
@@ -2,56 +2,44 @@
## Commit Format ## Commit Format
All commits are automatically prefixed with task ID: All commits are automatically prefixed with the task ID by the choreographer:
``` ```
[{task-id-prefix}] {message} [{task-id-prefix}] {message}
``` ```
Example: Example: `[a1b2c3d4] Add rate limiting endpoint`
```
[a1b2c3d4] Add rate limiting endpoint You write the message — the prefix is added for you. Don't include
``` `[task-id]` yourself; it gets stripped and re-applied.
## Who Can Commit
`commit` is in the **roboco-do** MCP and is mounted only for **developers**
and **documenters**. PMs delegate code work and call `complete` to merge.
There is **no** `roboco_git_commit / _push / _create_pr` MCP tool. The
single `commit` verb covers commit + push + PR-trigger via the
choreographer.
## Creating Commits ## Creating Commits
```python ```python
roboco_git_commit( commit(
project_slug="roboco",
task_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
message="Add rate limiting endpoint", message="Add rate limiting endpoint",
commit_type="feat" # Required files=["roboco/api/routes/rate.py"], # optional; defaults to all staged
) )
``` ```
This automatically: This automatically:
1. Prefixes commit with task ID (first 8 chars)
2. Records commit in task's commit history
3. Links to work session
## Commit Message Types 1. Prefixes the commit with `[task-id-first-8-chars]`
2. Validates the message via `commit_validator`
| Type | Description | 3. Stages the listed files (or everything tracked + modified if omitted)
|------|-------------| 4. Pushes to the agent's auto-created branch
| `feat` | New feature | 5. Records the commit on the task (`commits[]` field on `TaskTable`)
| `fix` | Bug fix | 6. Opens a PR through the choreographer when the task transitions out of
| `docs` | Documentation | `in_progress` (no separate `create_pr` call required)
| `style` | Formatting |
| `refactor` | Code restructure |
| `test` | Tests |
| `chore` | Maintenance |
| `perf` | Performance |
## Full Commit Format
```
{type}({scope}): {description}
{body}
Task: {task-id}
Co-authored-by: {agent-name}
```
## Before Committing ## Before Committing
@@ -60,23 +48,22 @@ Co-authored-by: {agent-name}
3. Run type check: `uv run mypy roboco/` or `pnpm typecheck` 3. Run type check: `uv run mypy roboco/` or `pnpm typecheck`
4. Format code: `uv run ruff format .` or `pnpm format` 4. Format code: `uv run ruff format .` or `pnpm format`
## Push Commits ## After Committing
You don't push or create a PR yourself. The choreographer pushed the
commit during `commit()`, and the PR is opened/merged as part of the
lifecycle transitions:
- `open_pr(task_id)` — opens the PR (devs)
- `pass(task_id)` (QA) → `i_documented(task_id)` (doc) → `complete(task_id)`
(cell PM merges the leaf PR; main PM opens the master PR)
## Viewing Commits and History
```python ```python
roboco_git_push(project_slug="roboco", task_id="a1b2c3d4...") # Read-only inspection (any role) — roboco-git-readonly MCP
``` status = roboco_git_status(project_slug="roboco")
log = roboco_git_log(project_slug="roboco", branch="feature/backend/a1b2c3d4--def67890")
Push before: diff = roboco_git_diff(project_slug="roboco")
- Submitting for QA branches = roboco_git_branch_list(project_slug="roboco")
- Creating PR
- Ending work session
## Viewing Commits
```python
# View commit history
roboco_git_log(project_slug="roboco", branch="feature/backend/a1b2c3d4")
# View changes
roboco_git_diff(project_slug="roboco")
``` ```
+31 -6
View File
@@ -1,10 +1,35 @@
# Git PR Types # Git PR Types
| `is_root_pr` | Target | Reviewer | Content | | `is_root_pr` | Target | Reviewer / Merger | Content |
|--------------|--------|----------|---------| |--------------|--------|-------------------|---------|
| `True` | main | CEO | Full task tree, all commits, all agent links | | `True` | `master` | CEO approves; Main PM opens + merges | Full task tree, all commits, all agent links |
| `False` | parent branch | PM | Simple summary, task commits only | | `False` | parent branch | Cell PM merges | Task commits only, scoped to the cell |
**Auto-checkout:** `roboco_task_start()` checks out branch automatically. Blocks if uncommitted changes exist. ## How PRs Are Created
**PR creation:** Use `roboco_git_create_pr()`. Title/body auto-generated from templates. There is **no** `roboco_git_create_pr` MCP tool. PRs are side-effects of
lifecycle transitions, driven by the choreographer:
- **Leaf PR (cell-scoped, `is_root_pr=False`)**:
Opened automatically when the assigned developer calls
`open_pr(task_id)` after their `commit(...)` calls. Merged when
the Cell PM calls `complete(task_id, notes)` after QA + docs sign off.
- **Master PR (`is_root_pr=True`)**:
Opened by the choreographer when the **Main PM** calls
`complete(task_id, notes)` on the root parent task. Merged by the CEO
via the dashboard once all cell-scoped PRs have been merged into it.
Title and body are generated from the task templates in
`roboco/templates/git/pr_*.py`. Don't hand-write PR descriptions in the
agent prompts — they'll be overridden.
## Auto-Checkout
Branches and checkout are handled automatically:
- `i_will_work_on(task_id)` (devs) creates the task's branch and checks it
out in the agent's workspace.
- `i_will_plan(task_id, plan)` (PMs) does the same for parent tasks.
- Workspace dirty? The verb returns an error envelope; clean up first
with `commit(...)` or escalate via `i_am_blocked(task_id, reason)`.
+69 -57
View File
@@ -1,81 +1,93 @@
# Pull Request Creation # Pull Request Creation
## When to Create PR ## When PRs Are Created
Create PR in `awaiting_documentation` phase (parallel with documenter). PRs are opened **before** QA review, not during `awaiting_documentation`.
The choreographer creates the PR as a side-effect of the developer's
`open_pr(task_id)` transition (`verifying → awaiting_qa`).
## Creating a PR This is by design: QA reviews the real PR diff on GitHub, and the
downstream PM/CEO approval chain operates on a PR that already exists.
You do **not** call any tool to create a PR. There is no
`roboco_git_create_pr` MCP tool.
## How the dev triggers it
```python ```python
roboco_git_create_pr( # 1. Make commits as you work (auto-pushes, no separate push step)
project_slug="roboco", commit(message="feat(api): add Redis rate limiter",
task_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", files=["roboco/api/routes/rate.py", "tests/integration/test_rate.py"])
title="[TASK-a1b2c3d4] Add rate limiting",
body="## Summary\n- Implemented sliding window...\n\n## Test Plan\n..." # 2. Once acceptance criteria are implemented + tested, hand off to QA.
) # The choreographer opens the PR here, sets pr_number/pr_url on the
# task, and transitions verifying → awaiting_qa.
open_pr(task_id="<task>")
``` ```
This automatically: The transition enforces (`enforcement/task_lifecycle.py`):
1. Creates PR via GitHub CLI (`gh pr create`)
2. Targets project's default branch
3. Sets `pr_created=True` on task
4. Records PR number and URL
## PR Title Format - `self_verified=True` — set when you call `i_am_done()` or
`verify(task_id)` first
- `commits` non-empty — at least one commit on the task
- `progress_updates` non-empty — at least one note on what changed
- `pr_number` is set automatically by the choreographer; you don't pass it
``` If any precondition is missing, the verb returns an envelope explaining
[TASK-{id-prefix}] {description} what's missing and how to remediate.
```
Example: `[TASK-a1b2c3d4] Add rate limiting endpoint` ## PR Title and Body
## PR Body Template Generated from templates in `roboco/templates/git/pr_internal.py` and
`roboco/templates/git/pr_root.py`. You don't write the body by hand —
it's filled with task title, acceptance criteria, the dev's notes, and
the standard traceability links.
```markdown Title format: `[TASK-{root-id:8}:{task-id:8}] {task-title}`.
## Summary
- What was implemented
- Key changes
## Test Plan ## Parallel Documenter Phase
- How to test the changes
- Test coverage
Task: {task-id} After QA passes, the task transitions to `awaiting_documentation` and
``` runs documenter + dev in parallel:
## Parallel Execution | Agent | Action | Flag set |
|-------|--------|----------|
| Documenter | Writes docs files, then `i_documented(task_id, notes, files)` | `docs_complete=True` |
| Developer | (already done by the time we get here) | `pr_created=True` |
In `awaiting_documentation`: Task transitions to `awaiting_pm_review` when both are true.
| Agent | Action | Flag | ## PM Merges via `complete`
|-------|--------|------|
| Developer | Creates PR | `pr_created=True` |
| Documenter | Writes docs | `docs_complete=True` |
Task advances to `awaiting_pm_review` when BOTH are done. After `awaiting_pm_review`, the Cell PM calls `complete(task_id, notes)`.
The choreographer:
1. Verifies all subtasks are in a terminal state
2. Verifies the PR is reviewable
3. Merges the leaf PR into the parent branch (squash by default)
4. Transitions the task to `completed`
For the root parent, **Main PM**'s `complete` opens the master PR and
escalates to CEO via `escalate_to_ceo` semantics.
There is no `roboco_git_merge_pr` MCP tool.
## Prerequisites ## Prerequisites
- **Git token configured**: Project must have a GitHub PAT set - **Git token:** the project must have an encrypted GitHub PAT set on
- Token must have `repo` scope for PR creation `projects.git_token_encrypted`. Without it, the workspace clone — and
- If missing, error: "Project has no git token configured" therefore everything downstream — fails with `WorkspaceError`.
- **Token scope:** `repo` (for branch push, PR create, PR merge).
- **Default branch:** `projects.default_branch` is the merge target for
the master PR (typically `master`).
## Before Creating PR ## Troubleshooting
1. Push all commits: `roboco_git_push()` - `NO_COMMITS` on `open_pr` → call `commit(...)` first; nothing to
2. Verify tests pass open a PR over.
3. Ensure code quality checks pass - `NO_PR` on `pass`/`fail` → the choreographer didn't open a PR; check
4. Branch is up to date with target the workspace state with `roboco_git_status` and re-call
`open_pr` once the workspace is clean.
## PM Merges PR - `FORCE_PUSH_FORBIDDEN` → only the CEO may force-push. If your branch
diverged, `unclaim` and re-`claim` the task; the choreographer
After completing task: rebuilds the branch.
```python
roboco_git_merge_pr(
project_slug="roboco",
pr_number=123,
merge_method="squash" # or "merge", "rebase"
)
```
Only PM can merge PRs.
+86 -55
View File
@@ -1,93 +1,124 @@
# QA Review Workflow # QA Review Workflow
## When QA Starts ## Preconditions
Task must be in `awaiting_qa` status. - Task is in `awaiting_qa` status
- The developer's PR is open (the choreographer opened it during their
`open_pr(task_id)` call)
- You are not the original developer of the task (self-review guard)
## QA Review Steps ## Steps
```python ```python
# 1. Claim the task # 1. Pick up an awaiting-QA task
roboco_task_claim(task_id) give_me_work()
# 2. Start review # 2. Claim it for review (auto-checks-out the dev's branch in your
roboco_task_start(task_id) # workspace; auto-records original_developer for the self-review
# guard at pass/fail time)
claim_review(task_id="<task>")
# 3. Announce to cell # 3. Announce to your cell channel (optional, but helpful when QA pulls
roboco_message_send({ # are slow)
channel: "backend-cell", say(channel="backend-cell",
content: "Starting QA review of [task title]", text="Starting QA review of <task title>",
task_id: task_id task_id="<task>")
})
# 4. Read developer's journey (REQUIRED) # 4. Inspect the diff
roboco_journal_read_team(original_developer, task_id=task_id) roboco_git_diff(project_slug="roboco")
roboco_git_log(project_slug="roboco", branch="<dev's branch>")
# 5. Checkout branch and review # 5. Run the relevant suite
roboco_git_checkout(project_slug, branch_name) # Backend: uv run pytest && uv run ruff check . && uv run mypy roboco/
roboco_git_diff(project_slug) # Frontend: pnpm test && pnpm lint && pnpm typecheck
# 6. Run tests # 6. Capture evidence (survives compaction; PMs can audit later)
# Backend: uv run pytest note(text="Verified AC #1 (429 on 101st req), #2 (TTL match), #3 "
# Frontend: pnpm test "(boundary tests). pytest 1635 passed; ruff clean; mypy clean.",
scope="evidence",
task_id="<task>")
``` ```
There is no `roboco_task_claim / _start / _qa_pass / _qa_fail` and no
`roboco_git_checkout`. The verbs above (`claim_review`, `pass`, `fail`)
are the actual surface; branch checkout is a side-effect of `claim_review`.
## Review Checklist ## Review Checklist
Before making decision: Before deciding:
- [ ] Read developer's handoff notes
- [ ] Check all acceptance criteria - [ ] Read the dev's notes and journal entries on the task
- [ ] Run tests (must pass) - [ ] Walk every acceptance criterion against the diff
- [ ] Verify functionality - [ ] Tests pass on the dev's branch
- [ ] Check code quality - [ ] Lint / typecheck clean
- [ ] Review against standards - [ ] No layer-separation regressions (routes/ vs services/ etc.)
- [ ] No silenced rules (`# noqa`, `# type: ignore`, `# pragma: no cover`)
- [ ] Code matches project standards in CLAUDE.md
## Passing QA ## Passing QA
```python ```python
roboco_task_qa_pass(task_id, { pass(
notes: "All acceptance criteria met. Tests pass. Code follows standards." task_id="<task>",
}) notes=(
"All 3 acceptance criteria verified against the diff. "
"pytest 1635 passed; ruff and mypy clean. "
"PR #123."
),
)
``` ```
Result: Task advances to `awaiting_documentation` Result:
- Task advances to `awaiting_documentation`
- Documenter and the original dev work in parallel from here
- The PR stays open; it will be merged later by the Cell PM via
`complete(task_id, ...)`
## Failing QA ## Failing QA
```python ```python
roboco_task_qa_fail(task_id, { fail(
notes: "Issues found during review", task_id="<task>",
issues: [ issues=[
"Bug: X doesn't work", "Bug: 100th request also returns 429 — boundary off-by-one.",
"Missing: Y not implemented" "Missing: tests for Redis-down failover path; AC #3 unmet.",
] ],
}) )
``` ```
Result: Result:
- Task returns to `needs_revision` - Task returns to `needs_revision`
- Assigned back to original developer - Re-assigned to the original developer (recorded at submit-for-qa time)
- Developer receives notification - Developer receives a notification
## Before Decision ## Reflect (recommended)
After pass or fail, journal the review for future QA agents to learn from:
Write reflection (REQUIRED):
```python ```python
roboco_journal_reflect({ note(
task_id: task_id, text=(
what_done: "Reviewed X, Y, Z", "Reviewed task <id>. Pattern: rate-limiter boundary tests "
what_learned: "Discovered patterns...", "should always assert the off-by-one — caught it in this "
what_struggled: "Edge cases unclear" "review and last week's. Worth a regression checklist item."
}) ),
scope="reflect",
task_id="<task>",
)
``` ```
## Self-Review Prevention ## Self-Review Prevention
QA CANNOT review tasks they originally developed. The system blocks QA from reviewing their own dev work. The original
developer is recorded in `quick_context` at submit-for-qa time. If
`qa_agent_id == original_developer_id`, **all** QA actions on the task
return `not_authorized`:
System tracks `original_developer` in `quick_context`. If QA == original_developer: - `claim_review` — FORBIDDEN
- **Claim**: FORBIDDEN - `pass` — FORBIDDEN (defence-in-depth even if claim somehow succeeded)
- **Pass**: FORBIDDEN - `fail` FORBIDDEN (same)
- **Fail**: FORBIDDEN
This applies to ALL QA actions on the task, not just claiming. The system enforces this at both the API and MCP tool level. Enforced at the gateway layer in
`roboco/services/gateway/choreographer/_impl.py`.
+6
View File
@@ -59,5 +59,11 @@
"tailwindcss": "^4", "tailwindcss": "^4",
"tw-animate-css": "^1.4.0", "tw-animate-css": "^1.4.0",
"typescript": "^5" "typescript": "^5"
},
"pnpm": {
"onlyBuiltDependencies": [
"sharp",
"unrs-resolver"
]
} }
} }
+3
View File
@@ -0,0 +1,3 @@
allowBuilds:
sharp: true
unrs-resolver: true
+8 -5
View File
@@ -904,17 +904,20 @@ async def submit_for_qa(
status_code=status.HTTP_400_BAD_REQUEST, status_code=status.HTTP_400_BAD_REQUEST,
detail=( detail=(
"NO_COMMITS: Cannot submit for QA without at least one " "NO_COMMITS: Cannot submit for QA without at least one "
"commit on this task. Use roboco_git_commit() before " "commit on this task. Use the roboco-do `commit(message, "
"i_am_done() via gateway, or POST /api/tasks/{id}/submit-qa." "files)` verb before `i_am_done()` via gateway, or POST "
"/api/tasks/{id}/submit-qa."
), ),
) )
if task.pr_number is None: if task.pr_number is None:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, status_code=status.HTTP_400_BAD_REQUEST,
detail=( detail=(
"NO_PR: Cannot submit for QA without a PR. Run " "NO_PR: Cannot submit for QA without a PR. The PR is "
"roboco_git_push() then roboco_git_create_pr() so QA can " "opened automatically by the choreographer when you call "
"review the diff on GitHub." "`submit_for_qa(task_id)` (gateway flow verb) — make sure "
"you have at least one `commit(...)` on this task first "
"so the choreographer has something to push."
), ),
) )
if not task.progress_updates: if not task.progress_updates:
+9 -2
View File
@@ -643,8 +643,15 @@ async def enrich_task_with_context(
task_dict = task_response.model_dump() task_dict = task_response.model_dump()
if include_work_session and hasattr(task_response, "id"): if include_work_session and hasattr(task_response, "id"):
query = select(WorkSessionTable).where( # A task can have multiple work sessions over its lifetime
WorkSessionTable.task_id == task_response.id # (one per claim/unclaim cycle). Pick the most recent so we
# don't crash with MultipleResultsFound on tasks that have
# been re-claimed.
query = (
select(WorkSessionTable)
.where(WorkSessionTable.task_id == task_response.id)
.order_by(WorkSessionTable.created_at.desc())
.limit(1)
) )
result = await db.execute(query) result = await db.execute(query)
work_session = result.scalar_one_or_none() work_session = result.scalar_one_or_none()
+3 -1
View File
@@ -378,7 +378,9 @@ def validate_git_requirements(
message=( message=(
"Blocked: PR not yet created. " "Blocked: PR not yet created. "
"In awaiting_documentation, Documenter and Developer work in " "In awaiting_documentation, Documenter and Developer work in "
"parallel. Wait for Developer to call roboco_git_create_pr()." "parallel. Wait for the Developer's submit_for_qa(task_id) "
"call to complete — the choreographer opens the PR as part "
"of that transition."
), ),
) )
+8 -4
View File
@@ -532,8 +532,11 @@ class GitService(BaseService):
if current_branch and current_branch != task_branch: if current_branch and current_branch != task_branch:
raise ValidationError( raise ValidationError(
f"BRANCH_MISMATCH: Workspace is on '{current_branch}' but " f"BRANCH_MISMATCH: Workspace is on '{current_branch}' but "
f"task requires '{task_branch}'. Use roboco_git_checkout(" f"task requires '{task_branch}'. Branches are auto-checked-"
f"branch=task_branch) first." f"out when you call `i_will_work_on(task_id)` (devs) or "
f"`i_will_plan(task_id, plan)` (PMs) — call your role's "
f"verb on the right task instead of switching branches by "
f"hand."
) )
async def _link_commit_to_task( async def _link_commit_to_task(
@@ -933,8 +936,9 @@ class GitService(BaseService):
action="force_push", action="force_push",
reason=( reason=(
"FORCE_PUSH_FORBIDDEN: Force-push is CEO-only. If your " "FORCE_PUSH_FORBIDDEN: Force-push is CEO-only. If your "
"branch diverged, roboco_git_checkout a fresh branch " "branch diverged, `unclaim` the task and re-`claim` it — "
"and replay your commits." "the choreographer will rebuild the branch and you can "
"replay your commits via `commit(...)`."
), ),
) )
+2 -1
View File
@@ -2698,7 +2698,8 @@ class TaskService(BaseService):
""" """
Mark that developer has created a PR for the task. Mark that developer has created a PR for the task.
Called when developer uses roboco_git_create_pr(). This method: Called by the choreographer when the developer's submit_for_qa()
flow opens the PR. This method:
1. Sets pr_created=True, pr_number, pr_url on the task 1. Sets pr_created=True, pr_number, pr_url on the task
2. Checks if docs_complete is also True 2. Checks if docs_complete is also True
3. If both complete, transitions to awaiting_pm_review 3. If both complete, transitions to awaiting_pm_review
Generated
+415 -376
View File
File diff suppressed because it is too large Load Diff