Spec: autonomous CEO slot (per-repo, gated on .agent/ceo.md) #238
Labels
No labels
Agent
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
joshtronic/igor#238
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Add a CEO pass to the tick that turns the interactive
/ceorole into an autonomous one. For repos that opt in (by containing.agent/ceo.md), periodically run an LLM "CEO" that grooms theAgentqueue, reviews bot PRs, triages feedback, and emails a board digest — all within a mandate-defined authority that never ships code itself. Companion to the interactive/ceopersona; both read the same.agent/ceo.md(Porksicle's is merged:joshtronic/porksicle.com:.agent/ceo.md).This is "just another igor pass," driven by mandate + judgment instead of a scored heuristic — the gap between igor's existing auto-filing (SEO/deps, scored in shell) and actual product strategy.
Gate (opt-in, per-repo)
A repo gets a CEO iff
.agent/ceo.mdexists at its root — read via the Forgejo contents API (same mechanism as the CLAUDE.md onboarding check) or from the synced clone. No file → no CEO. This mirrors theWEBSITE_REPO/SEO_AGENTIC_SITESopt-in philosophy, but per-repo via a tracked file. Optionally also behind a globalCEO_ENABLED/CEO_RECIPIENTSenv that no-ops when unset (matching the SEO/market/sports email siblings).Where in the cascade (
bin/tick.sh)After PR-review pickup + Igor's own work, alongside the maintenance/SEO analysis block. It's analysis-shaped: read-only to code; its side effects are issues / PR reviews / email, never commits. Iterate bot-accessible repos that have the mandate file (decoupled from the worker-validation gate like the other analysis passes), throttled per-repo.
Cadence + state (
discretionary-state.json)Per-repo
.ceoobject:{ last_daily, last_weekly, last_digest, failures }, mirroring the existing daily/weekly slot mechanics (midnight rollover for daily, ISO-week Monday-anchored + self-healing for weekly, 5-hard-failure/day cap, cooldown).What a CEO run does
Gather (harness, via
lib/forgejo.sh+ the synced clone): the mandate.agent/ceo.md; open bot PRs (esp. those awaiting a first review on current HEAD); openAgentissues + queue depth; recent feedback signal if wired; the project memory.Invoke Claude (
lib/claude.sh) with a newbin/lib/ceo-directive.md(sibling ofsports-digest-directive.md) + the gathered context + the mandate.LLM-decides / harness-executes (same split as the SEO/maintenance passes — keeps all write side-effects harness-controlled). Claude returns STRUCTURED output, e.g.:
The harness validates + executes via the Forgejo API: post PR reviews, create deduped
Agentissues, send the digest (lib/email.sh), stamp state.Authority guardrails (HARNESS-ENFORCED, not just prompted)
The CEO surface is propose + review, never ship — this encodes the mandate's "board-only = merging/shipping" line structurally:
.forgejo/workflows, secrets, or the deploy host.Agentissues per repo; respect "one bot PR per repo at a time" (Discovery already enforces); dedup issues by title/signature so it doesn't re-file every tick.Digest (
lib/email.sh)Event-driven daily (only when actionable: merge-ready PR, blocker, decision needed) + always weekly. To
CEO_RECIPIENTS(or reuseSEO_PRIMARY_EMAIL). Content: what was delegated, what merged since last, what's merge-ready awaiting the board, blockers, decisions needed.Dependencies / order
Open questions (board calls — @joshtronic)
igorbot files + reviews + works (talks to itself via the tracker; fine). v2 = a distinct CEO bot user for cleaner separation?Why this shape
Reuses igor's existing machinery end-to-end (cascade,
claude.sh,forgejo.sh,email.sh, discretionary slots, directive files). LLM-decides / harness-executes keeps guardrails structural, not prompt-dependent. Deliberately notAgent-labeled — igor shouldn't autonomously rewrite its own tick loop; this is a careful human/PR change.Board decisions + reconciliation (Josh, 2026-06-24) — read before implementing
Reviewed against the binding review that shipped today (which this spec was written
as if didn't exist). The four board calls + the corrections:
1. CEO's role on PRs → strategy only, NOT code review. The binding review
(
do_review_tick, live) already owns code-correctness AND the hand-to-board(APPROVE → requests Josh). The CEO must NOT post its own approve/request_changes
verdict — that duplicates the reviewer and hits the self-review 422. Per Josh:
"CEOs don't review code, they ask 'how does this help us accomplish goal X?'" So
the CEO weighs in on a PR only as a strategic comment, and consumes the
binding review's APPROVED set as the digest's "merge-ready awaiting the board."
2. Identity → same
igorbot (v1). No distinct CEO user — "zero reason to setup 100 bots." Fine, because the CEO defers code-review (no self-review 422 to
dodge).
3. Digest → email (reuse SMTP2GO /
CEO_RECIPIENTS).4. Scope → Phase 1 = north-star + digest only. And a reframing from Josh worth
baking in: a digest of existing work is a weak first act — the CEO's foundational
job is to establish/refresh the strategy and surface the board's open questions.
The mandate
.agent/ceo.mdis the north star. So Phase 1, each run:board needs to answer (the CEO's signature move).
surface strategic questions, weekly propose mandate refinements.
All emailed; write-light (the
.agent/ceo.mdonly changes when Josh blesses it —the CEO may open the mandate PR, its one allowed authored doc). Bootstrap:
opt-in on a stub
.agent/ceo.mdso the CEO's first run can flesh it out.Settled defaults (not forks):
not a title hash.
Stale dependency:
#226is already closed (fixed by#227today). The realrule it was reaching for still holds: the CEO must read
origin/<ref>(gitshow / API), never the clone's working tree — those stay arbitrarily stale.
Build order: Phase 1 (north-star + digest, email, write-light) → Phase 2 (queue
grooming: capped + deduped
Agentissues) → Phase 3 (strategic PR comment,reconciled with the binding review). Each human-reviewed; deliberately NOT
Agent-labeled (a new tick-loop pass is a careful change).
Two corrections from the Porksicle side (2026-06-25), for whoever builds this:
Gate path changed:
.agent/ceo.md→/CEO.md(repo root)..agent/is the harness's per-run scratch dir, so worker PRs kept staging the mandate's deletion — three times (porksicle #49 / #52 / #54). Moved it to the root (porksicle PR #55). The CEO slot's opt-in gate and its reads must key off/CEO.md, not.agent/ceo.md.Drop "CEO posts PR reviews" from this spec. Refined model: a CEO doesn't review code — per-PR QA is the automated review tick's job. The CEO pass should groom/file issues, triage feedback, send the digest, make strategic calls — not review PRs. (The
igor-can't-review-its-own-PR identity limit reinforces this.)