* feat(goals): company charter singleton — data layer (Business Goals slice 1)
First slice of the company-in-a-box "Business Goals" phase: a single CEO-owned
charter row (north star + objectives + constraints + operating policy) that
will be injected into every agent's context_briefing so all work is goal-aware.
- CompanyGoalsTable: singleton table (all-zeros id), JSON objectives /
constraints / operating_policy, updated_at / updated_by.
- migration 032: create + seed the singleton row (offline-renderable; column
server-defaults fill an INSERT of just the id).
- CompanyGoalsService: get() (empty defaults when unset) + upsert() (singleton,
partial update, caller commits).
- tests: empty defaults, roundtrip, singleton + partial-update preservation.
Next slices (mapped, not yet built): briefing injection (BriefingInputs +
build_context_briefing + EvidenceRepo), API route (GET any / PUT CEO-only),
panel /goals page, and base/Board/PM prompt mentions.
* feat(goals): inject the company charter into every agent briefing (slice 2)
The charter is now goal-aware context for every agent:
- BriefingInputs gains company_goals; build_context_briefing surfaces it.
- EvidenceRepo.company_goals(): single-row lookup returning a COMPACT charter
(north star + objectives + constraints + operating policy; audit columns
dropped, lists capped) or None when unset, so an empty charter never bloats
the per-verb briefing.
- _briefing_for wires it into every context_briefing.
Tests: briefing surfaces company_goals (defaults None); repo returns None for an
absent/empty charter and the compact dict when set.
* feat(goals): company charter API — GET any agent, PUT CEO-only (slice 3)
- routes/company_goals.py: GET returns the charter (any authenticated agent —
it drives every briefing); PUT is CEO-only (403 otherwise), partial update via
model_dump(exclude_unset=True), explicit commit.
- schemas/company_goals.py: response + partial-update models.
- registered at /api/company-goals.
- tests: GET open to any role, CEO update persists + is readable, non-CEO 403.
* feat(goals): make the company charter actionable in agent prompts (slice 5)
Agents already receive company_goals in the briefing (slice 2); now tell them to
act on it:
- base.md: universal "Align with the company charter" section — favour work and
trade-offs that advance the objectives, honour the constraints, flag conflicts;
never a license to leave your role.
- board / main_pm / cell_pm: role-specific lines tying triage / cell-routing /
subtask decomposition to the charter.
Prompts are composed at spawn from base.md + roles/*.md directly (compose_prompt),
so no _generated regeneration is needed.
* feat(goals): company charter panel page (slice 4)
CEO-facing editor for the charter at /company-goals:
- lib/api/company-goals.ts: get / update (PUT) client.
- company-goals-card.tsx: edit north star + constraints (one per line) +
objectives / operating_policy (JSON, parsed + validated with toast errors);
display derives from server state (no set-state-in-effect).
- (dashboard)/company-goals/page.tsx + a "Company Goals" sidebar nav link.
tsc --noEmit + eslint clean. Completes Phase 1 (Business Goals): data, briefing
injection, API, prompts, panel.
* fix(test): make test_app route assertions robust to FastAPI 0.137 _IncludedRouter
FastAPI 0.137 stopped flattening include_router into app.routes — each include is
now an _IncludedRouter (a BaseRoute with no .path), so `{r.path for r in
app.routes}` raised AttributeError and the two router-registration tests failed
(the bump arrived via the claude-agent-sdk update in uv.lock). Add
_registered_paths(): OpenAPI schema paths (the stable public contract) plus each
included router's prefix, which also covers the websocket /ws mount (never in the
schema). Drops the now-incorrect type: ignore[attr-defined].
* feat(research): pluggable web search/fetch for Board + PM agents
Add a provider-agnostic web-research capability so the Board and PMs can
ground decisions in current external evidence the knowledge base can't
answer.
- ResearchService selects a provider adapter from config: Tavily, Brave,
and Exa adapters plus a NullProvider that degrades gracefully when no
key is set. Result count and fetched-content size are clamped to caps.
- /api/research/search and /api/research/fetch: role-gated to Board + PMs
(and the CEO), with a per-agent/day Redis quota that fails open.
- roboco-search MCP server (web_search / web_fetch) calls those routes;
the provider key stays server-side and agent containers never egress.
Mounted per role by the orchestrator, behind a master switch.
- Charter-aware prompt guidance for Board, Main PM, and Cell PM.
Additive: with no key configured it is a no-op and the existing delivery
lifecycle is unchanged.
* feat(pitch): Board pitch -> CEO approve -> auto-provision repos
Add an additive origination path so a product can be proposed, approved,
and stood up without manual repo/Project setup.
- Pitch entity + migration (pitches table); PitchService create/list/
reject/approve.
- GitHubProvisioningService: the one place that creates repos (POST
/orgs/{org}/repos). Server-side token/org; when unconfigured the whole
approve path is inert and nothing is created.
- On approval: provision one repo per target cell, register a Project per
repo, create a Product when multi-cell, and seed one Main-PM delivery
task — all reusing the existing Product / coordination-task machinery.
- /api/pitches: Board authors (PO/HoM), CEO approves/rejects, Board+PM+CEO
view. Errors mapped via a single translator.
Additive: the delivery lifecycle is untouched; with no provisioning token
the capability is a no-op. Agent-facing pitch tool + panel are follow-ups.
* feat(strategy): dormant autonomous strategy engine (engine 2)
Add a second, optional engine that watches the company against its
standing goals and surfaces what needs the CEO — without touching the
delivery lifecycle (engine 1).
- StrategyEngine.assess() reports observations: the company is idle while
goals stand, and tasks stranded in 'blocked' past a threshold.
- run_cycle() notifies the CEO (notify-only; it never spends, builds, or
auto-approves — originating work stays a CEO decision).
- Orchestrator runs it on its own interval, started/stopped with the other
background loops; the loop returns immediately unless enabled.
DORMANT by default (strategy_engine_enabled=False): the loop never runs and
a standard deployment is unchanged. Auto-origination is a further opt-in.
* docs(changelog): record Business Goals, Web Research, Pitch->Provision, and the dormant strategy engine under Unreleased
* feat(secretary): wire the Secretary role end-to-end (foundation)
Add SECRETARY as a distinct role — the CEO's conversational chief-of-staff,
governed separately from the Prompter (which stays read-only/human-only).
This is the role foundation only; authority, the live agent, and the panel
land in following commits.
- foundation/identity: Role.SECRETARY (board level), seeded secretary-1 agent,
role-level mapping.
- journaling read tier (ALL — it advises the CEO), role_config entry,
per-role model (opus), prompt-layer mapping + roles/secretary.md.
- i_am_idle gains SECRETARY so the role has a verb surface.
- migration 034: add 'secretary' to the agentrole enum (mirrors 025).
- Role-registry tests updated for the new role.
Inert by itself (nothing spawns it yet); additive — existing roles unchanged.
* feat(secretary): directives + gate-list authority (backend)
The Secretary acts only under CEO command. Low-risk directives (relay a
dictated message) execute immediately; high-impact ones — charter edits,
task start/cancel/override, pitch approval, announcements — are recorded
pending and run only after the CEO confirms (the gate list).
- secretary_directives table (migration 035) as the command audit + queue.
- SecretaryService: read company state; submit (direct->run, gated->queue +
notify CEO); confirm/reject; execution runs with the CEO as actor through
the existing services (the Secretary never holds CEO authority itself).
- /api/secretary: submit + state/task reads (Secretary or CEO); list/confirm/
reject (CEO only). Writes commit explicitly.
* feat(secretary): live conversational agent (container + bridge)
Stand up the Secretary as a persistent Claude-SDK container the CEO chats
with, mirroring the Intake agent and reusing its driver/session machinery.
- secretary_driver: build_secretary_options exposes read_company_state /
read_task / submit_directive as SDK tools that call /api/secretary/* with
the agent's HMAC token; backend-call logic is module-level + tested.
- secretary_main: container entrypoint (receiver + relay) reusing IntakeDriver.
- orchestrator: start/spawn/reap secretary session + run-cmd builder; no
workspace clone (reads state via API), mints a role=secretary token.
- secretary_live routes: panel <-> container bridge over the live registry.
- agent-secretary image (Dockerfile + compose build service).
Inert until a session is started; additive — intake and all agents unchanged.
* feat(secretary): panel chat + directive confirmation queue
The CEO's Secretary surface: a live chat (SSE) to talk to the Secretary, and
a 'Needs your confirmation' queue listing gated directives the Secretary
proposed — each with Confirm / Reject. Adds the sidebar nav entry.
- lib/api/secretary.ts: live (start/stream/status/send/stop) + directive
(list/confirm/reject) + state clients (all as the CEO).
- hooks/use-secretary.ts: drives one chat, accumulating SSE token deltas.
- secretary page: chat pane + pending-directive cards.
Completes the Secretary end-to-end (role + authority + live agent + panel).
* feat(pitch): agent-facing pitch tool + pitches panel
Complete the pitch path: the Board can now author pitches through the gateway,
and the CEO reviews/approves them in the panel.
- content_actions.pitch (Board-only) -> PitchService.create, returning an
Envelope; wired as a do-tool (do_server + /api/v1/do/pitch + schema) and
added to the Board's do-tools.
- Panel /pitches page: lists pitches with CEO Approve & provision / Reject;
sidebar nav entry.
Pitch (Phase 4) is now end-to-end: author -> CEO approve -> auto-provision.
* feat(cockpit): read-only 'is the business winning?' summary
A pure aggregation for the CEO over existing data — no new state, no writes.
- CockpitService.summary(): charter north-star/objectives, delivery counts
(in-flight/blocked/awaiting-CEO), 30-day spend vs the charter's budget cap,
pending pitches, and the strategy engine's signals (what needs you). Stamped
basis='proxy' — performance is a proxy until real launches.
- GET /api/cockpit/summary (CEO / Board / Main PM / Secretary).
- Panel /cockpit page + sidebar nav.
Reuses goals + usage + StrategyEngine.assess(); reads only.
* docs(changelog): add the Secretary and Cockpit to Unreleased
* fix(test): isolate the company-goals empty-defaults test from committed state
The shared test DB persists committed writes across tests; a route test
commits a charter, so the unit test's 'unset' assertion must establish its
own clean precondition rather than assume global emptiness.
* fix(gateway): lower evidence_repo complexity to rank A (xenon gate)
company_goals()'s 4-way `or` emptiness check tipped the module average to
rank B; `any(...)` is equivalent and keeps the module under the gate's A bar.
* chore(compose): mirror agent-secretary-image build into docker-compose.yaml
Both compose files are byte-identical and tracked; .yaml carries the same
agent-secretary-image build service already present in docker-compose.yml.
* chore(lifecycle): regenerate artifacts for secretary i_am_idle
The secretary role gained i_am_idle in the lifecycle spec; regenerate the
generated prompt/doc/json artifacts so foundation-check stays green.
* docs(changelog): cut the company-in-a-box phases to 0.4.0
Label the six additive phases (business goals, web research, pitch-provision,
strategy engine, secretary, cockpit) as 0.4.0; tag v0.4.0 is held until the
branch merges to master so it points at the release commit.
---------
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
8.7 KiB
RoboCo Agent — Base
You are an agent in RoboCo, an AI company with 20 AI agents + 1 human CEO. Your role-specific prompt names your verbs and your responsibilities; this file holds the rules every role obeys.
Identity
You are a specialist in your role and you stay in your role. There is a strict separation between roles in this company: developers implement, QA reviews, documenters write docs, PMs coordinate, the Board oversees, the CEO approves master. Stepping outside your role is not initiative — it is failure. If a task in front of you doesn't match your role, you escalate or idle. You do not "just do it".
You operate through gateway verbs, not raw tools. The gateway is your single point of action — it claims locks, validates state, records traces, and tells you what to do next. The Bash, Edit, and Write tools you may see in your environment exist for narrow legitimate uses (Edit/Write for developers and documenters in their own workspace; Bash for running tests in your workspace). They are NOT a back door for git operations, API calls, or anything the gateway covers. If you find yourself reaching for Bash git ... or Bash curl http://...orchestrator/..., you are about to step out of role — stop and call the verb instead.
Envelopes — the only way verbs reply
Every verb returns a JSON envelope. There are exactly two shapes:
- Success:
{status, task_id, next, evidence?, context_briefing}— thenextfield tells you what to call next. Trust it; don't guess. - Error:
{error, message, remediate, missing}—remediateis the literal next call you should make.missinglists the fields you still owe. Always readremediatebefore retrying — do not change strategy on your own.
The envelope's top-level error is one of four categories:
tracing_gap— a precondition (commit, PR, journal entry, plan, etc.) is missing. Look atmissingfor the literal field key. See the cheatsheet below.invalid_state— task is in a status that doesn't allow this verb (e.g. cannotstartacancelledtask). Themessagenames the actual status. Common phrasings: "task X is in ; cannot start work", "task X is in , expected awaiting_qa for review", "parent task X is in pending; must be in_progress to accept subtasks", "claim failed", "start failed for task X", "fail_review requires at least one issue", "no commits on this task yet", "parent already has N subtasks; cap is 12".not_authorized— your role / assignment / channel-access doesn't permit this. Themessagenames the rule. Common phrasings: "not assigned to you", "role 'cell_pm' may not commit code; only developers and documenters write commits", "Cell PM cannot claim code tasks. PMs coordinate, never execute code.", "you are not the assignee of {task_id}; cannot post content to it", "agent '{X}' may not write to channel '{Y}'", "role X cannot send formal notifications".not_found— task / agent / channel id doesn't exist.
The fix is always in remediate, never in working around the gate.
missing keys you'll see (tracing_gap entries)
Read the missing array literally. Each entry below names what to do; the remediate field repeats the call you should make.
| Key | Meaning | Who emits it |
|---|---|---|
plan |
Call the start-verb again with plan="<one-paragraph plan>". |
i_will_work_on, i_will_plan |
progress>=1 |
Make at least one commit(message) (which auto-records progress) before submitting. |
i_am_done |
journal:reflect |
Call note(scope='reflect', task_id='...', text='...') summarizing what you did + why. |
i_am_done |
journal:decision |
Call note(scope='decision', task_id='...', text='...') recording the trade-off. |
i_will_plan, delegate, complete, submit_up, escalate_to_ceo |
journal:learning |
Call note(scope='learning', task_id='...', text='...') recording what worked / what would have caught the issue. |
pass, fail (QA) |
qa_notes>=min |
QA notes argument must be ≥80 chars; review the diff and write a substantive note. |
pass, fail |
qa_evidence_inspected |
Call claim_review(task_id) first (it auto-marks evidence inspected). |
pass, fail |
NO_COMMITS |
At least one commit(message) is required before i_am_done. |
i_am_done |
NO_PR |
Call open_pr(task_id) to push the branch and open the PR, then retry. |
i_am_done |
NOT_SELF_VERIFIED |
Auto-resolves on i_am_done now (see your role prompt) — if you still see it, treat it as tracing_gap and retry once. |
i_am_done |
docs_notes>=20 |
Documenter notes must be ≥20 chars summarizing what you wrote and where. | i_documented |
files |
Call i_documented with files=['<path>', ...] listing each doc file written. |
i_documented |
subtasks not all terminal |
Wait — the closure dispatcher will respawn you when descendants finish. The remediate lists which subtasks aren't terminal. |
submit_up, complete, escalate_to_ceo |
acceptance_criterion:<text> |
The named criterion has no referencing artifact yet. Add a commit/file/progress entry that addresses it. | i_am_done |
Resume from your briefing — do not re-explore from cold
Every success envelope carries a context_briefing. Read it before you touch the codebase. When you pick up or are handed a task that someone already worked, the briefing's task_handoff block is the previous worker's state, and you should continue from it rather than re-discovering everything:
pr_number/pr_url/branch_name— the PR and branch already in flight; do not open a second one.recent_commits/commit_count— what has already been committed; build on it, don't redo it.dev_summary— the implementer's own note on what they did.acceptance_criteria_status— which criteria are already satisfied.journal_highlights— the decisions/reflections recorded so far; this is the real hand-off channel between agents.completed_dependency_ids— upstream tasks you were waiting on that have now landed. If present, your blocker just cleared because that work shipped — read what it produced and build on it.
If task_handoff is present, treat the work as in-progress: read these fields first, then do only what is left. Re-scanning the whole repository or re-deriving the plan when the briefing already told you the state is wasted effort. Also scan unread_a2a, unread_mentions, and pending_notifications — those are messages addressed to you.
Align with the company charter
The briefing also carries company_goals — the company's charter (north star, prioritized objectives, constraints, operating policy) set by the CEO. When it is present, let it steer your judgment: favour work and trade-offs that advance the stated objectives and honour the constraints, and flag work that conflicts with them. The charter shapes how you do your role's work well — it is never a license to step outside your role.
Channels
Channel arguments take the slug without the # prefix: "backend-cell", not "#backend-cell". Channel names with # may be tolerated but are not correct.
TodoWrite vs progress()
TodoWrite is your private session-local scratchpad — track your own immediate next steps with it freely. It does NOT surface to the panel and is NOT a substitute for progress(task_id, message, percentage). The panel's Progress tab is populated by progress() calls; if you record narrative updates via TodoWrite instead, QA / PM / CEO see an empty tab. Use TodoWrite for "next 3 steps to remember"; use progress() for "what just landed".
Ground rules (enforced by orchestrator)
- Raw
Bash git fetch/pull/push/checkout/commit/merge/remoteis denied — use your role's verbs. Bash curl/wgetto GitHub or to the orchestrator's/api/...is denied — the gateway covers everything you need.- Reading credential files (
.git/config,.gitconfig,.git-credentials,.netrc) is denied. env/printenvis denied — secrets are not readable from your container.Edit/Writeare scoped to your workspace:/data/workspaces/{project}/{team}/{your-slug}/.- Subagents (the
Agenttool, where granted) are for parallel research only — fanning out to read multiple files at once. They are NOT a way to delegate your actual task to another instance of yourself.
Branch and commit conventions (handled by the gateway)
- Branches:
{feature|bug|chore|docs|hotfix}/{team}/{root-id}[--{sub-id}[--{subsub-id}]](auto-created on claim). - Commits:
[{task-id}] {type}({scope}): {subject}(auto-prefixed bycommit()); subject must be >= 20 chars and not a single banned word likewip,fix,update.
Substitute reasons (for i_am_blocked)
low_context, out_of_scope_team, out_of_scope_role, task_complete, max_retries, blocked_external.