Skip to content

Integrate roadmap stack into main (Pillars 1-7 + follow-ups, v0.14.0) - #14

Merged
scr1p7k177y merged 14 commits into
mainfrom
feat/dispatch-exploration
Jun 10, 2026
Merged

scr1p7k177y merged 14 commits into
mainfrom
feat/dispatch-exploration

Conversation

@scr1p7k177y

Copy link
Copy Markdown
Member

Integrate the roadmap stack into main (Pillars 1–7 + follow-ups + nicety)

Why this PR exists: PRs #2–#13 were a stacked chain — each one's base was the
previous feature branch, not main. Merging them therefore updated those feature
branches, not main; only PR #1 (base: main) ever landed. As a result main was
left at v0.2.0 with just the autonomy core, while the full roadmap work
accumulated linearly on the top-of-stack branch feat/dispatch-exploration
(v0.14.0). This PR brings those 14 commits into main in one clean merge
(verified conflict-free).

What lands (already reviewed + CI-green individually as #2–#13)

Verification

Merging this makes main = v0.14.0 with the roadmap fully closed. Tag v0.14.0 after.

One execute() interface so any runtime can be an agent. mcp-tool runs a task
by calling a tool on another MCP server (the differentiator); shell runs an
allowlist-gated command. Runner resolves an executor per agent from
settings.executors (default llm = unchanged). Budget/approval/veto/eval wrap
all runtimes uniformly. 72 tests. Bump 0.3.0 + CHANGELOG + ROADMAP.
/code-review on the executor branch found: mcp-tool leaked the spawned
server (no error/close/timeout handler, never killed when the runner's
outer race fired) and the shell allowlist was basename-only (bypassable
by /tmp/evil/node). Add error/close/timeout handling + stderr drain +
guaranteed cleanup to mcp-tool; require full-path allowlisting for
path-qualified shell commands. +2 tests (bypass refused, bad mcp cmd
fails fast).
…ut cap)

Second /code-review found residual shell.js issues: full-path allowlist
used strict string equality (rejected C:/x/node.exe vs C:\x\node.exe and
case variants on Windows), the spawn 'error' path leaked the timeout timer,
and stdout/stderr buffers were unbounded. Add platform-correct samePath()
matching, single-settle guard that always clears the timer, a 5 MiB output
cap, and a 4 KiB stderr ring. mcp-tool fixes verified clean; config wiring
verified threaded from server/daemon/heartbeat. +1 test (75 total).
Tasks gain depends_on + parent_id. New lib/scheduler.js (pure): readyOrder()
runs only dep-satisfied tasks (priority then age); findDeadlocks() catches
unknown deps and cycles via Kahn. Heartbeat is now topological — blocks
deadlocks with a reason instead of starving, then re-scans readiness after
every run so a whole chain drains in one cycle.

/code-review caught the gate being bypassable: depends_on was enforced only
in the heartbeat, so ceo_run_task/execute:true could run an unmet-dep task.
Now enforced in runner.runTask (single chokepoint, returns 'waiting'). Also
surfaced deps in the backlog projection. v0.4.0, +15 tests (90 total).
config/org.yaml models the company as a reporting tree; lib/org.js (pure)
resolves agent->role, walks the reporting line, collects role subtrees, and
rolls budget up so an agent's spend counts against its role AND every ancestor
(department envelope bounds its members; root bounds the org). Runner enforces
the role envelope before dispatch (department breach blocks the task, no global
pause). ceo_org tool renders the chart + live spend (16 tools). Executor
resolution gains a per-role fallback.

/code-review fixes: clarified the >/>= operator split (mirrors budget.js) and
made runner/heartbeat tests hermetic via empty-org isolation in the workspace
helper, decoupling them from the production org.yaml caps. v0.5.0, +11 tests
(101 total).
Append-only events table (autoincrement id = total order). lib/events.js:
emit/list/snapshot, a pure reduce() that folds the task lifecycle into derived
state (replayable from the log alone), and a cursor-based drain()+subscribe()
for reactive processing. Task lifecycle events emitted from tasks.js (the single
mutation chokepoint); heartbeat emits cycle.ran and drains events each cycle into
an append-only audit feed (reports/events-feed.md) — the loop is event-driven,
not just cron. ceo_audit tool (17th) replays the log and reports fidelity vs live.

/code-review caught a replay-fidelity gap: create() upserts status but only
emitted on first insert, so a status change via create() was invisible to the
log. Now emits task.status on an upsert that changes status; reducer handles it.
+regression test. v0.6.0, +9 tests (110 total).
An agent's answer may carry a fenced ceauto directive ({subtasks, escalate};
lib/delegation.js); the llm executor surfaces it. On a done task the runner spawns
child tasks within the acting role's can_delegate_to authority (parented for the
DAG scheduler) or escalates up the reporting line, all logged to the event bus.
tasks.depth() + max_delegation_depth/max_subtasks_per_task bound runaway fan-out.

/code-review fixes: (1) isolated processDelegation in its own try/catch so a
child-spawn failure can't re-dispatch the done task and double-spawn; (2) hardened
org.canDelegate so a modelled role can't delegate to an unknown/hallucinated agent.
+regression tests (no re-dispatch on delegation error; unknown-agent denied).
v0.7.0, +14 tests (124 total).
lib/learning.js on the existing evals + memory FTS (no new tables): a
high-scoring completion distills a reusable playbook that's injected as context
before similar work; a quality/failure block distills a lesson recalled before
similar work; per-(agent,model) success+cost stats recommend the cheapest model
that works. Runner injects recalled context + records playbooks/lessons (all
best-effort). ceo_insights tool (18th) surfaces the dispatch policy.

/code-review fixes: (1) dispatchStats JOIN multiplied rows on retries/re-evals,
skewing the recommendation — now pre-aggregates ledger+evals to one row per task
before joining; (2) handleInsights null-guards toFixed and derives the agent list
from real history (no hardcoded omissions). +regression test (retries don't
inflate stats). v0.8.0, +10 tests (134 total).
webhook/http-webhook + claude-code executors on a shared hardened spawn
helper; file-watch/inbound-webhook/@mention sources (default-off, secret-
required) feeding the queue; ceo_sources tool (19th). /code-review hardening:
SSRF redirect block, port-aware + roster-validated allowlists, timing-safe
secret, payload-override guard, stdin EOF/SIGKILL, debounce, bounded event scan.
Local 127.0.0.1 dashboard (lib/dashboard.js + bin/ceauto-dashboard.js) projecting
tasks/approvals/org/metrics/events from SQLite. Policy-as-code (config/policy.yaml)
ordered rules → require_approval + quorum, legacy fallback. Multi-approver quorum
in approvals (N distinct approvers, one reject vetoes). /code-review hardening:
attribute-safe esc() (quote XSS), slimmed event payload, shared approverCount,
explicit-verdict-only policy rules, no-op resolve on resolved approvals.
dispatch.auto_route (default-off) routes each task to the cheapest
(model, provider) that has historically cleared the bar for the agent;
falls back to the configured model when off or under-sampled. Partial
routes are ignored to avoid a cross-provider mismatch. v0.11.0.
A task can run an ordered list of executors: chain (pipeline, result =
last step) or map (fan, result = reduced doc). Usage summed across steps;
bounded to 10 steps, no nesting. Runner scales the budget gate by step
count so the cost is gated, not just one step. v0.12.0.
task.plan decomposes a task into a subtask DAG instead of executing it:
the runner appends a planning instruction, forces the llm executor, and
the agent ceauto directive is spawned as children via the existing
delegation path. processDelegation maps sibling-title depends_on to new
child ids (self-ref dropped, first duplicate wins). v0.13.0.
With dispatch.explore_epsilon > 0 (default 0) auto-routing occasionally re-samples
an abandoned/under-sampled model so a recovered or cheaper one can be rediscovered,
logged as a dispatch.explored event. recommendDispatch gains epsilon + injectable rng.
@scr1p7k177y
scr1p7k177y merged commit a0ee686 into main Jun 10, 2026
3 checks passed
@scr1p7k177y
scr1p7k177y deleted the feat/dispatch-exploration branch June 10, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant