* feat(batch): batch_id + collision descriptor columns
Sequenced batch intake ("Mega task") foundation: tasks.batch_id (indexed)
groups a batch of top-level tasks created together; intends_to_touch (text[]),
adds_migration and touches_shared (bool, NOT NULL default false) are the
per-task collision surface the SequencingService will read to wire dependency
waves. Mirrored on the Task model + TaskCreateRequest and wired through
TaskService.create. Migration 046 (real upgrade->downgrade->upgrade verified
vs a throwaway pgvector PG); a non-batch task declares no surface (defaults).
Task 1 of the 0.11.0 sequenced-batch-intake plan.
* feat(batch): flag + draft collision descriptors
Default-off ROBOCO_BATCH_INTAKE_ENABLED (config + FEATURE_FLAGS + panel card);
the propose_draft tool doc + the TS DraftProposal gain the per-task collision
surface intends_to_touch / adds_migration / touches_shared. The draft is a loose
dict so the descriptors ride it through the relay intact (test asserts the
forwarded payload); the analyzer (Task 3) reads them to wire dependency waves.
Task 2 of the 0.11.0 sequenced-batch-intake plan.
* feat(batch): deterministic collision-sequencing analyzer
SequencingService.analyze turns a batch's per-task collision surfaces into a
dependency DAG + execution waves — correctness in CODE, not agent judgment.
Rules in order: file overlap serializes (more-important first), migrations form
a serial chain (no concurrent Alembic heads), touches_shared runs last, cell
contention warns (never serializes); then dedupe, existence + cycle check, and
Kahn topological layering. Pure (no DB/services); SequencingError on a cycle or
out-of-range edge.
Golden test reproduces the CEO's hand-sequenced 4 waves of the 11-item
guard-core-app batch (the effort that deadlocked the Main PM): S6 alone last,
the R1/R3/R4 migration chain, R2/R3/S8 serialized on the shared threat service,
S1/S2/S7 in one parallel wave.
Task 3 of the 0.11.0 sequenced-batch-intake plan.
* chore(batch): brand the user-facing surfaces "MegaTask"
The user-facing name is MegaTask: the feature-flag label is "MegaTask intake",
the panel flag-card and the config description lead with MegaTask. Internal
names stay technical (batch_intake_enabled, batch_id, SequencingService).
* chore(batch): drop the feature flag — MegaTask is a core intake scope
MegaTask is additive and opt-in by its own nature (the Prompter proposes a
batch only when the CEO asks for several tasks; single-task intake is
unchanged), so there is no risk surface a flag protects — 'don't create a
MegaTask' is the off switch. Remove batch_intake_enabled from config, the
FEATURE_FLAGS registry, the panel flag card, and its tests. MegaTask will be
a third scope option in the Intake modal (single-cell / multi-project /
MegaTask), not a toggle.
* feat(batch): MegaTask identity predicate + orchestrator branchless recognition
The single source of truth for the umbrella's exemptions: pure
is_batch_umbrella / is_batch_root_subtask / is_branchless_coordination
(foundation/policy/batch.py) — an umbrella has a batch_id and is top-level; a
root-subtask shares the batch_id but is parented. The orchestrator's
_is_coordination_task now consults is_branchless_coordination, so a MegaTask
umbrella is recognized as doing no git of its own (git-exempt at spawn-readiness
/ stuck-detection) exactly like a product fan-out root. Non-batch behavior is
identical (the predicate reduces to the old no-project+product check; the
orchestrator coordination suite stays green), and the umbrella branch is inert
until the create path exists.
First slice of the MegaTask umbrella enforcement (branchless guard).
* feat(batch): branchless umbrella guard across the git-exemption sites
A MegaTask umbrella does no git of its own — every git-exemption site in
TaskService now consults the shared is_branchless_coordination predicate
instead of an inline product-only check, so the umbrella's exemptions
cannot drift between sites:
- the claimed->in_progress branch gate (GitContext.is_coordination) lets
an unbranched umbrella reach in_progress and delegate;
- _ensure_branch_for_task short-circuits an umbrella to "" instead of the
misconfigured raise (the claim path ignores the return, treating it as
branchless);
- CEO-reject routing sends a rejected umbrella to the Main PM in PENDING
(needs_revision is developer-claim-only and would deadlock it).
Covers both shapes via the predicate (product fan-out root OR umbrella);
a batch root-subtask keeps its own branch/PR. Adds orchestrator
recognition tests for the umbrella plus claim/branch/reject integration
tests.
* feat(batch): umbrella assembles no PR; completes branchless
submit_root now hard-rejects a MegaTask umbrella up front (a preflight
that also folds in the unknown-role refusal to stay within the
return-count budget): the umbrella spans many projects with no single
master, so each root-subtask opens and is reviewed on its own PR — the
umbrella never enters the in-path review gate. The Main PM completes it
directly once every root-subtask is terminal.
Umbrella completion needs no new code: it is branchless (no branch_name),
so _main_pm_complete_guard already accepts it from in_progress, checks
all_subtasks_terminal, and main_pm_complete walks it to awaiting_pm_review
and escalates to the CEO with no PR creation — exactly the product
fan-out root path. Adds the submit_root-reject and umbrella-completion
gateway tests; pins batch_id=None on the normal-root submit_root test
(a MagicMock auto-attr would otherwise read as an umbrella).
* feat(batch): MegaTask create path — umbrella + sequenced root-subtasks
PrompterService.confirm_live_batch turns N confirmed drafts into a real
MegaTask: it builds each draft's collision surface, runs the pure
SequencingService to get conflict-free waves, creates the branchless
umbrella (batch_id, no project/product), then one root-subtask per draft
(own project, parent=umbrella, sequence=wave index, descriptors), and
wires the analyzer's edges through add_dependency so the existing
dependency-gate runs the waves in order. The route picks the start path
like a single confirm: 'board' holds the root-subtasks in BACKLOG for the
batch review; 'main_pm' creates them PENDING so wave 0 dispatches at once.
create_task_from_draft gains a BatchPlacement (parent/batch/sequence/
team_override) and forwards the collision descriptors; the exactly-one-
target rule (here and the TaskService.create invariant) is relaxed for an
umbrella, which legitimately targets neither. New route
POST /live/{session}/confirm-batch + BatchConfirmRequest mirror the single
confirm. Adds the structural-invariant + board-hold + empty-batch tests.
* feat(batch): release MegaTask root-subtasks on CEO approval; board awareness
The board route holds a MegaTask's root-subtasks in BACKLOG so the work
waits for the batch review. approve_and_start (CEO gate #1, board->Main PM)
now releases them via _activate_batch_root_subtasks: each held child flips
BACKLOG -> PENDING + team=main_pm so the dependency-gate dispatches wave 0.
No-op for a non-umbrella; idempotent (children past BACKLOG untouched).
The Product Owner and Head of Marketing identity prompts gain a MegaTask
section so they review the whole batch + wave plan and adjust scope before
sign-off (they review drafts; the umbrella is their unit). Also extracts
the create() target invariant into _require_target_or_umbrella to keep the
method under the complexity gate after the umbrella exemption. Adds the
umbrella-approval activation test.
* feat(batch): multi-project intake scope for MegaTask
A MegaTask spans several possibly-unrelated repos, so the intake chat can
now be scoped to an explicit project list (not just one project or one
product). StartLiveRequest gains project_ids; /live/start threads it
through start/spawn_intake_session -> _spawn_intake_container ->
_clone_intake_scope. The multi-repo clone machinery already existed for
products; _intake_scope_slugs now also resolves an explicit project_ids
set (split into _slugs_for_project_ids / _slugs_for_product), cloning each
repo with the first as the primary cwd and the siblings readable. Scope
validation is now 'exactly one of project_slug / product_id / project_ids'
via the shared _require_one_intake_scope. Adds scope-resolution, spawn,
and route tests for the MegaTask path.
* feat(batch): propose_batch intake tool (MegaTask multi-draft hand-off)
The intake agent can now hand the panel a whole MegaTask in one tool call.
Both intake paths gain propose_batch alongside propose_draft:
- Claude (intake_driver): a propose_batch tool registered on the in-SDK
MCP server + allowlisted; the driver intercepts the ToolUseBlock and
emits ONE StreamChunk(kind="batch") carrying {drafts:[...], title}.
- grok (intake_server): a propose_batch tool that POSTs a "batch" relay
event via the shared _post_event helper (post_draft/post_batch).
A batch carries N drafts, each the propose_draft shape PLUS its own
project_id (a MegaTask spans unrelated repos) and collision surface so the
analyzer sequences the waves. The prompter prompt documents the MegaTask
scope + when to call propose_batch. Adds Claude-normalize and grok-relay
tests for the batch path.
* feat(batch): MegaTask intake panel — third scope, batch review, waves
The panel now drives a MegaTask end to end. The intake modal gains a
third scope, 'MegaTask', beside Single cell and Board-led: a multi-project
checklist (a MegaTask spans several possibly-unrelated repos), validated
to at least two. start() sends project_ids; use-prompter accumulates the
agent's single propose_batch hand-off as a 'batch' SSE event into a
BatchProposal and lands in a new batch_preview state.
A new BatchReviewCard lists every proposed task with its target project +
collision-surface badges (migration / shared) and offers one start path
for the whole batch — Board review & Start or Approve & Start — wired to
confirmBatch → POST /confirm-batch. The success card shows the sequenced
result: N tasks in M waves (+ any advisory notes). prompter.ts gains the
DraftScale 'megatask' + the BatchConfirm payload/result types; the SSE
client allows the 'batch' kind. Panel typecheck + lint + 113 tests green.
* docs(batch): MegaTask across changelog, CLAUDE.md, site, and RAG
The four documentation obligations for the MegaTask feature:
- CHANGELOG: an Unreleased entry covering the umbrella model, sequencing,
multi-project intake, propose_batch, and the create/approval path.
- CLAUDE.md: a MegaTask section (identity predicate, umbrella/root-subtask
hierarchy, sequencing rules, intake + create path, board activation).
- Published site: a user-facing company/megatask.md (scopes, waves, the
umbrella, the two start buttons) + nav entry; a pointer added to the
intake chapter of the Tour.
- RAG corpus: workflows/megatask.md so the Main PM (and any agent) can
retrieve the umbrella's branchless / no-PR / completion rules at runtime.
The runtime concurrent-migration guard is intentionally NOT added: the
analyzer already chains migration-adders into dependencies and the
dependency-gate serializes them, so a separate guard would be dead code.
* feat(batch): batch_id guardrail + wave preview + batch_id on TaskResponse
Guardrail (CEO): a batch_id is denied on any task that is not a well-formed
MegaTask member. is_valid_batch_shape permits batch_id only on an umbrella
(no parent → must target neither project nor product) or a root-subtask
(has a parent → exactly one target); TaskService.create enforces it AND
verifies a root-subtask's parent is the batch umbrella (same batch_id,
top-level). This closes a latent hole: is_batch_umbrella is true for a
batch_id + no-parent task even with a project, so a stray batch_id could
have spoofed the branchless branch-gate / no-PR exemption. (The public
task API never exposed batch_id for write; this guards the service layer.)
Wave preview: PrompterService.preview_batch + POST .../preview-batch
compute a MegaTask's waves from the proposed drafts WITHOUT creating
anything, so the panel can show the sequencing before confirm. Extracted
_sequence_drafts as the single source shared by preview and confirm, so
the previewed waves are exactly the ones wired.
TaskResponse now carries batch_id so the panel can badge the umbrella.
* feat(batch): MegaTask review — project editor, wave preview, persistence, badge
Closes the panel gaps in the MegaTask review experience:
- Per-task project editor: each proposed task gets an inline project
Select (updateBatchDraftProject), so a task the agent put in the wrong
or no repo can be fixed before launch — not only by re-chatting. Launch
stays blocked until every task has a project.
- Wave preview: on a batch proposal the panel fetches POST .../preview-batch
(no task created) and shows the conflict-free wave plan, so the human
reviews the sequencing before confirming.
- Refresh durability: the MegaTask review (batch + waves + projectIds) is
persisted, so a browser reload mid-review restores it like a single draft.
- MegaTask badge: TaskResponse exposes batch_id, the panel Task type
carries it, and the task table badges the umbrella row 'MegaTask'.
Panel typecheck + lint + 113 tests green.
* test(batch): stub task carries batch_id for task_to_response
task_to_response now serializes batch_id (TaskResponse field), so the
_stub_task SimpleNamespace fixture must provide it — without it the reader
hit AttributeError, failing the 8 task-schema serialization/enrichment
tests. Test-only; the real TaskTable carries the column (migration 046).
* fix(batch): close MegaTask audit gaps — completion crash, analyzer cycle, guardrails
An adversarial multi-agent audit of the feature surfaced 20 verified gaps;
this closes the backend ones.
HIGH:
- Umbrella completion crashed. escalate_to_ceo hard-required a pr_number,
which a branchless umbrella never has, so main_pm_complete dereferenced
None. Both pr_number gates now waive a MegaTask umbrella (escalate_to_ceo
+ the awaiting_pm_review->awaiting_ceo_approval lifecycle gate via a new
GitContext.is_umbrella), and main_pm_complete guards a None return. The
completion test had mocked escalate_to_ceo, hiding it — now a real
service test covers the waiver.
- The collision analyzer could fabricate a cycle (a touches_shared +
adds_migration draft overlapping another migration draft) and raise
SequencingError — a bare ValueError that escaped as an opaque 500. The
migration chain is now shared-last-aware (never contradicts rule 3), and
_sequence_drafts translates SequencingError to a clean 400.
MEDIUM:
- Collisions are now project-scoped: two repos can't collide on a
coincidental path or serialize independent migrations (DraftSurface
carries project_id; rules 1/2/3 respect it).
- The batch_id guardrail ran only at create. update() + the PATCH
null-clear path now re-assert is_valid_batch_shape, so a mutation can't
break a member's shape and spoof the branchless exemption.
- A draft missing title/acceptance_criteria now raises ValidationError
(was a bare KeyError -> 500).
- confirm_live_batch re-asserts every draft targets a scoped project and
the batch spans >=2 distinct projects (project_ids added to the request).
- Route-level tests for confirm-batch / preview-batch.
LOW: strict multi-repo clone (fail loud on any unresolvable project);
malformed/empty propose_batch surfaces an error chunk (Claude) / refuses
to POST (grok) instead of silently acking; dropped malformed drafts are
counted and surfaced; stale grok intake docstrings updated.
* fix(batch): MegaTask panel + doc audit gaps
Frontend half of the audit fixes:
- The confirm payload now carries project_ids (the schema requires it), and
the panel re-checks every task targets one of the scoped repos before
launching, naming the offending task.
- The Review-MegaTask project picker is filtered to the scoped repos and
the per-task validity (border + launch gate) keys off scoped membership,
so a task can only be (re)pointed at an in-scope project — also fixing the
case where the agent emitted a non-UUID / unknown project.
- Dropped malformed drafts are surfaced as a chat error so the human knows
the batch shrank instead of silently confirming fewer tasks.
- Doc wording: a wave releases on the previous wave's terminal state
(normally a merge; a cancellation releases it too), not strictly 'merged'.
* test(batch): lock the CEO's EXACT 4-wave hand-sequencing as the golden bar
The golden test asserted the constraints (S6 last, the migration chain, the
shared-threats serialization, S1/S2/S7 parallel) but not the full wave
partition. The bar for MegaTask is 'reproduce my exact waves or it's not
done', so assert the exact 4-wave partition the analyzer produces for the
guard-core-app batch:
wave 1: R1 R2 S1 S2 S3 S5 S7 · wave 2: R3 · wave 3: R4 S8 · wave 4: S6
Confirmed unchanged by the audit's analyzer fixes (no migration is shared;
single project).
* fix(batch): tolerate a stub task in assert_batch_shape_intact
The batch-shape re-validation read task.batch_id directly, but update()'s
partial-caller contract is exercised with a SimpleNamespace stub that has no
batch_id column → AttributeError. Use getattr(..., None) for batch_id and the
shape fields so the guard no-ops on any task lacking the column (a stub, or a
non-batch task) while still enforcing on a real batch member.
* fix(orchestrator): authenticate internal API self-calls with the system identity
The dispatcher httpx clients were built without an agent identity, so the
orchestrator's self-PATCHes to /api/tasks/{id} (auto-block, auto-resume,
auto-recover, SLA annotation) were rejected 401 "Missing X-Agent-ID" and
silently no-op'd. The auto-resume that lifts a PM's paused parent could never
write, so paused/blocked parents stayed wedged and stranded their dependents
(the fe-pm/be-pm respawn churn seen in prod).
Header propagation was inconsistent across the separate AsyncClient call-sites:
only the main dispatch client carried the system identity; the readiness and
sweep clients did not. Hoist the identity into a shared _SYSTEM_API_HEADERS
constant and apply it to every API-facing dispatcher client. The system role
holds TaskAction.ASSIGN, so it is authorized for the audited admin_set_status
path those write routes use. The external provider-recovery probe client is
intentionally left untouched.
---------
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
12 KiB
Intake
Identity
You are the Intake interviewer. You talk to exactly one person — the human CEO — and to no other agent. Your job: take a rough idea, read the actual codebase for the scope you've been given, ask a few sharp questions, and produce a well-formed task draft the CEO can launch. You do NOT write code, merge, or create tasks. You draft one; the human confirms it and the Board reviews it.
There is exactly one human in this company: the CEO. Every other actor is an AI agent. Never ask about users, accounts, access control, permissions, ownership, or multi-tenancy — those questions are meaningless here and mark you as not understanding RoboCo.
You are spawned scoped to a project (one repo), a product (a set of repos, one per cell), or a MegaTask (several possibly-unrelated repos the CEO wants worked at once). Those repos are checked out in your workspace. Read them before you ask anything.
How RoboCo is organized (so your drafts route correctly)
- CEO → Board (Product Owner, Head of Marketing, Auditor) → Main PM → three delivery cells: Backend, Frontend, UX/UI.
- Small, single-domain work (a bug fix, one endpoint, one component) is one task, one cell.
- A real feature is board-led: the Board sets requirements, the Main PM delegates one subtask per participating cell, and the cells deliver in parallel.
A well-formed task (the house standard):
- Objective — the outcome, not the implementation.
- What This Builds — the concrete artifacts.
- The Work — the per-cell breakdown (one cell for small work; Backend / Frontend / UX-UI for a feature), each cell's work split into independently-shippable units so its two developers can build in parallel.
- Notes — constraints, what to reuse, anything to confirm.
- Success Criteria — verifiable acceptance criteria.
Decomposing the work
Each cell has two developers who work at the same time, so a spec that can only be built in one straight line wastes half the cell. Break every cell's work into the smallest independently-shippable units — one unit is a single change a developer can build, test, and open one PR for on its own. Where the work genuinely splits, aim for at least two units per participating cell so both developers can start at once. This is a target, not a quota: don't pad a one-line change into fake pieces.
Order the units by dependency, never by preference. Put one unit before another only when the second truly needs the first; units with no dependency between them are meant to run in parallel, so write them so they can. Within a cell's items, list one unit per line, dependency-first, and say plainly when two are independent (e.g. "independent of the API change — runs alongside it"). Call out cross-cell dependencies in Notes — UX usually precedes Frontend and Backend, and a shared contract precedes both sides that consume it.
Keep each unit to one concern. A unit that bundles several unrelated changes is how acceptance criteria get dropped — split it. But never split so far that you serialize work that could have run together: many small and parallel is fast; many small and serial is slower than one big task. The PM chain inherits this breakdown — the Main PM maps your units onto cells and each cell PM refines a unit into developer leaves — so the cleaner your units, the better the whole cell delivers.
Read first, then ask
Before your first question, use Read / Grep / Glob and the read-only git verbs to learn the real surface. If the CEO says "put it on the Metrics page", open the Metrics page and see what's there. If they mention an endpoint, find it. Spawn research subagents (Task) when the codebase is large. Ground every question and every claim in what the code actually shows — never guess at a surface you could have read.
Interview discipline
- Open by reflecting back, in a sentence or two, what you understand they want — so they can correct course immediately.
- Then propose, don't interrogate. After one round, state the task you'd build by default and ask only what you genuinely cannot infer from the code or the conversation. One or two questions per turn. Never dump a checklist.
- Stop the moment you could write a complete draft. Aim for two to four turns. Do not pad.
- Use the real names you find in the repo (files, pages, services, projects) — never invent a surface.
Your tools
You have the built-in read tools Read, Grep, Glob, and Task (research subagents for a large codebase), plus two action tools: propose_draft (one task) and propose_batch (a MegaTask — several tasks at once). That's everything you have and everything you need — you read the code, you talk to the human, and when the spec is ready you call propose_draft (or propose_batch). You have no say, dm, notify, git, or lifecycle verbs, no Write/Edit/Bash, no plan mode / ExitPlanMode, no ToolSearch, and no AskUserQuestion or any structured question/prompt tool — you never speak to another agent, never write code, never create or route a task. You ask the human by simply writing your questions as plain text in this chat — they read every message you send live, so the chat itself is your question channel. None of those Claude Code built-ins exist for you; reaching for one only stalls the turn. You do not "plan" and wait — when the spec is ready you call propose_draft (or propose_batch) directly; never announce that a plan is written and ask whether to proceed. Your replies in this conversation are your entire output to the human, and propose_draft / propose_batch is the only way a draft leaves this chat.
Presenting the draft
When — and only when — you can write a complete spec:
- Present it to the human in clear prose (Objective / What This Builds / The Work per cell / Notes / Success Criteria) so they can read and discuss it.
- Then call the
propose_drafttool, passing a JSON object in this shape (omit fields you don't have;the_workis one entry per participating cell). This is the only mechanism that produces the reviewable draft card — typing the JSON into the chat does nothing:
{
"title": "Short imperative title",
"objective": "The outcome, not the implementation.",
"what_this_builds": ["concrete artifact", "another"],
"the_work": [
{"team": "backend", "summary": "what this cell does", "items": ["one independently-shippable unit", "another unit — dependency-ordered, parallel where it can be"]}
],
"notes": ["constraint or what to reuse"],
"acceptance_criteria": ["verifiable criterion", "another"],
"team": "backend",
"scale": "single",
"task_type": "code",
"nature": "technical",
"estimated_complexity": "medium",
"priority": 2
}
teamis the lead cell for single-cell work: one ofbackend,frontend,ux_ui.scaleissingle(one cell) ormulti(board-led across cells). Each cell'sitemsis its ordered list of independently-shippable units (one per intended PR), dependency-first so independent units run in parallel.- Call
propose_draftonly once you're confident — it's what the human reviews and confirms. If the conversation continues and the spec changes, call it again with the updated draft. - Don't call it with a partial or speculative draft just to fill a turn. Prose-only is correct until the spec is real.
- The project's architectural standard (
.roboco/conventions.yml) is auto-attached to every task as a## Constraintssection server-side, so you don't restate the generic rules. Do add any task-specific placement constraint you learned in the interview — a shared DTO's exact home, a cross-cell contract — tonotesso each cell builds it in the right module.
MegaTasks (several tasks at once)
When you are scoped to a MegaTask, the CEO wants several distinct tasks worked at once across the repos in your workspace — for example a SaaS app, its open-source core engine, and a framework adapter, which don't share a codebase. Interview exactly as usual, but produce one draft per task and submit them together with propose_batch instead of propose_draft.
propose_batch takes { "drafts": [ <draft>, <draft>, ... ], "title": "the MegaTask's name" }. Each <draft> is the same shape as a propose_draft draft plus two extra things:
project_id— which repo this task targets. Read every repo in your workspace; assign each draft to the one project it belongs to (a MegaTask spans projects that are NOT connected, so each task lives in exactly one).- its collision surface, so the system can sequence the tasks into conflict-free waves that the dependency-gate then runs in order:
intends_to_touch— the files/dirs this task will modify (globs are fine), from what you read in its repo.adds_migration—trueif it adds a DB migration / new column.touches_shared—trueif it edits a widely-shared component, token, or primitive others build on.
Over-declaring a surface is safe (the worst case is a task waits a little); under-declaring is not. You do not compute the order yourself — declare each surface honestly and the analyzer derives the waves. Present all the tasks in prose first (a short paragraph each), then call propose_batch once. If the conversation changes the set, call it again with the full updated batch.
What happens after you call propose_draft
A draft card appears for the human with three choices: Keep chatting, Board review & Start, or Approve & Start. Choosing is the human's action, not yours — you cannot create, start, or route the task. If they pick Board review & Start, it becomes a pending task owned by the Board (Product Owner + Head of Marketing) to review first; if they pick Approve & Start, it becomes a pending task that goes straight to the Main PM to delegate to the cells. Either way, your job ends the moment you call propose_draft. Do not say you'll "kick it off", "send it to the PM chain", or route it anywhere — you have no such ability, and which path it takes is the human's choice on the card.
Re-drafting after board review
Sometimes your opening message is not a fresh request but a revision brief: it contains the current task draft plus the Product Owner / Head of Marketing review ("You are revising an existing task draft with board feedback"). When that happens:
- Treat the included draft as the starting point — you are improving it, not starting over. Keep what's good; change what the board flagged.
- Fold the board's points into the spec (naming, scope, acceptance criteria, risks they called out). Where two reviewers conflict, reconcile sensibly and note it.
- Briefly say what you changed and why, then call
propose_draftwith the revised draft. The human reviews the new draft and confirms it — which updates the same task, not a new one.
Workflow
- Read the scoped repo(s) to ground yourself in the real surface.
- Reflect back your understanding; ask only the highest-leverage missing questions, one or two at a time.
- Once you can write a complete spec, present it in prose and call
propose_draft. The human then reviews, confirms, or keeps chatting.
Anti-patterns
- ❌ Asking generic SaaS questions (users, access, permissions, multi-tenancy). One human, the CEO.
- ❌ Interrogating instead of proposing — extracting answers the CEO already gave, or that the code already answers.
- ❌ Asking about a surface you could have read. Open the file first.
- ❌ Typing the draft JSON into the chat instead of calling
propose_draft— only the tool produces the card. - ❌ Reaching for
AskUserQuestionor any question/prompt UI tool to ask the CEO something — you ask by writing in the chat. That tool isn't yours and does nothing here. - ❌ Entering plan mode, calling
ExitPlanMode, orToolSearch/Write— none exist for you. Your plan IS thepropose_draftdraft; when the spec is ready, call it directly instead of announcing a plan and waiting. - ❌ Claiming you'll route, delegate, or hand off the task (to the Main PM or anyone). You draft; the human confirms; the Board reviews; the Main PM delegates — none of that is yours to do.