You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/forge plan contract — Candyland quest & campaign execution flows
This is the .plan build contract for /forge (slug: candyland-quest-campaign).
It is the build-phase source of truth: the tech-lead partitions it into fork-safe
tasks, coders build them concurrently, integration + /gh-self-review converge, and
it delivers one PR per impacted repo. Mirrors GitHub issue benitogf/detritus#97.
This is a handoff backlog for moving Detritus/Candyland toward an intent-driven
development model. It is deliberately self-contained so a fresh agent can pick it up
without needing the conversation that produced it.
Intent
Evolve Candyland from one-shot multi-agent runs into an intent-driven execution
sidecar (Run → Quest → Campaign), with Detritus owning its lifecycle and serving as
the knowledge/command surface its agents compose. Candyland is the execution +
observability surface; Detritus owns doctrine, install/lifecycle, and thin commands.
Acceptance / completion gate
The build is complete when, per core/completion (inherited via roles/tech-lead
and core/build — not restated):
Every - [ ] acceptance item below that is in scope is satisfied and checked.
go test ./... is green in both repos; go vet and GOOS=windows go build ./...
pass in candyland; the candyland stub-based e2e (scripts/e2e.mjs) and validators pass.
The Composition Constraint holds at runtime: a spawned agent can kb_get doctrine and open a PR against a non-public repo in a real stub-driven run (0.2a + 0.9).
A clean /gh-self-review over the full diff, no new deferral markers.
The two repo PRs are coordinated at merge per Delivery Shape (no window where /candyland spawns a deleted subcommand).
Out of scope & blockers (core/completion dispositions)
OUT OF SCOPE — do NOT build: Phase 4 centralized learning / the hill-climbing
meta-loop. Phase 4 is only local-trace-shape readiness (stable IDs, parent-child
links, exportable JSONL). Building a central store/analytics is a deferral, not
in-scope work.
GATE — build order, not a separate PR: the Phase 3 campaign intent-review build is
blocked until the core/intent-review doctrine doc exists (authoring that doc is an
in-scope Phase 3 task — do it first). The 0.2 HTTP-comms work is gated on the
CLI-version spike (in-scope, first candyland commit); if the CLI floor is unmet, comms-mcp stays a process and 0.2 is skipped without blocking the rest.
Separate doctrine change (own commit):/janitor plan-gating (Phase 2) alters
in-session behavior; keep it an isolated, clearly-labelled commit in the detritus PR.
Fork-safe partitioning guidance (for the greenfield phases)
Phase 0/1 items are concrete (file:line). The greenfield phases are specified at goal
level; the tech-lead should partition them along these file-disjoint seams so
coders don't collide, and gate each with the named verification oracle (all stub-based,
no live model — no API budget):
Phase 2 (Quest): (a) Quest model + storage [run/types.go-analog, conductor];
(b) quest REST endpoints (Phase 7) [httpapi]; (c) quest tick loop [conductor];
(d) /quest command [detritus]; (e) quest dashboard view [src/ UI]. Seams a→b→c are
ordered; d and e fork off once the API shape is fixed. Oracle: a scripted-stub tick test asserting discover→triage→run→review→PR
transitions and stop/pause state, on the existing writeFakeClaude harness.
Phase 3 (Campaign): (a) core/intent-review doctrine doc [detritus, FIRST];
(b) Campaign model + storage; (c) campaign REST endpoints; (d) supervisor/intent-lead
flow + the two gates; (e) /campaign command; (f) campaign UI. b/c/e/f are
file-disjoint; d depends on a+b. Oracle: a stub campaign asserting Intent-Brief gate, impl-plan gate, and the
per-commitment intent-review verdict schema {satisfied,partial,missed} + cited
evidence; assert missed blocks the repo PR and partial annotates only.
Phase 6 (UI hierarchy): UI-only (src/), disjoint from backend; partition by
view (history/filters, run/task, quest, campaign pivots). Oracle: the existing UI
validators + a render/smoke check per view.
Phase 7 (APIs): co-built with the Phase 2/3 models that back them; Oracle:
per-endpoint handler tests.
Delivery Shape Of This Work
The entire issue ships as exactly one PR per repo — one in detritus, one in
candyland (the two are distinct repos with no shared history, so a PR cannot span
both). Phasing is by commits within each PR, not by multiple PRs over time. The
phase numbers and "Suggested First Implementation Order" below define commit
order, not separate deliverables.
The two PRs are coordinated at merge: the candyland PR adds the new REST/HTTP
surface and removes control-mcp; the detritus PR switches to driving candyland
over that surface. Merge the consumer-ready side such that /candyland never has a
window where it spawns a deleted subcommand (detritus adopting the existing REST +
ensure-up can land first; candyland's deletion follows or lands together). This is a
merge-ordering note, not a phasing-into-many-PRs requirement.
Within each PR, order commits by the phase sequence so the diff is reviewable
commit-by-commit even though it lands as one PR.
Settled Decisions (so an autonomous run needs no clarification)
These resolve the load-bearing ambiguities a coder would otherwise invent. Each
supersedes any looser phrasing in its phase.
Intent-review method (Phase 3). The intent reviewer kb_gets a new doctrine
doc (core/intent-review); it does not inline a rubric. Method: extract each commitment from the Intent Brief (one checkable assertion each); for each, emit a
verdict in {satisfied, partial, missed} with cited evidence (diff/PR/test) —
never a vibe check. Gate: a missed blocks that repo's PR; a partial annotates the
PR and routes to the review router but does not block. Defer Phase 3 build until
this doc exists.
Budget / concurrency (Autonomy section). Env-tunable, mirroring resilience.go:81-92: CANDYLAND_QUEST_TOKEN_CAP, CANDYLAND_CAMPAIGN_TOKEN_CAP, CANDYLAND_CONCURRENCY (default = the current parallel-coder cap). Cost estimate = agents × attemptTimeout × model-rate, computed inline; drop the cobus reference.
Cap-hit disposition = degrade-to-serial, then deliver-partial — never pause
(a pre-PR pause is a no-PR terminal state under /smith). Anchor token defaults on the
existing candyland TokensBudget/per-token constants.
Autonomy level at launch. The launching /quest///campaign command passes an
explicit level. Campaigns default to L2/L3 (end-to-end delivery is their
contract); never L1 (report-only would strand a campaign with no PR and no in-loop
opt-up moment). Quests default per their intent.
deliver field. Mirrors the per-repo PRs[] shape, not a scalar branch:<name>
(which can't carry N per-repo branch names): deliver ∈ {pr, branch} + derived
per-repo branch campaign/<campaignID>. Resume = fetch + checkout existing campaign/<id> if present, else create.
Phases slice. Exactly ["Build","Integrate","Review","PR"]. Land 0.7 + 0.8 in
one change. Update the Go literal indices (executor_claude.go:292=1, helpers.go:52==1 → 0; len-N math self-adjusts) and the duplicated UI
array src/meta/run.js:7 (consumed by RunWorkspace/RunSwitcher/AuditPanel/Dashboard/
Tasks) in lockstep; convert offsets to named constants.
0.2 per-agent MCP identity. Use a per-agent URL /mcp/comms/<agentID> (survives
header-stripping proxies; header is the weaker fallback). Assert a minimum claude
CLI version at sidecar startup (the installer floats latest; type:http support is
a CLI property pinned nowhere). Run the spike as the first commit; keep 0.2 separable
so comms-mcp can remain a process if the CLI floor is unmet.
Windows-only items (0.4 exe-swap, 0.5 tree-kill; 0.3 home-dir partly). On this
WSL/Linux host they are static-verified + cross-compiled only (GOOS=windows
build + vet); runtime verification is deferred to a Windows host and the run must not claim they "work." Kill mechanism = a Windows Job Object
(JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE), not "job-object OR taskkill /T". Exe-swap
mirrors detritus's own self-update rename-aside (update.go:244-263).
Product Intent
Detritus is the knowledge and command surface. It owns doctrine,
install/update/lifecycle guidance, skills, and thin commands that route work.
Detritus skills should be composable by default and should avoid duplicate
workflow implementations. When two commands need the same behavior, define the
shared doctrine once and have commands compose or delegate to it.
Candyland is the execution and observability surface. It owns long-lived agent
processes, task graphs, run records, traces, dashboard views, and local records
that can be centralized later with low friction.
Do not add heavy observability to in-session commands like /forge, /smith, or /vibe. Those are transitional/control surfaces. The durable loop runtime should
live in Candyland, where each agent has its own session and the records are
granular enough to improve the platform later.
Component Tree
The intended model is hierarchical. Each level owns data at its own abstraction
level and aggregates child records without flattening away the detail.
Detritus command / skill surface
-> Candyland sidecar API
-> Campaign
-> Quest(s), when a workstream is persistent or exploratory
-> Work item / finding
-> Run
-> Agent task
-> Agent events, tool calls, tests, review findings
-> Direct run(s), when a campaign has finite scoped delivery work
-> Quest
-> Work item / finding
-> Run
-> Agent task
-> Agent events, tool calls, tests, review findings
-> Run
-> Agent task
-> Agent events, tool calls, tests, review findings
Definitions:
Run is the atomic Candyland execution unit. It is the current flow: a
tech-lead/coder/reviewer agent graph takes a scoped instruction and delivers a
PR or a precise failure.
Quest is an iterative loop container. It may be open-ended or finite. It can
discover/triage findings, execute a provided task list, check compliance, audit
a PR or repo against a document, or run any other repeated work pattern. A
quest repeatedly launches runs, so one quest can produce many PRs.
Campaign is a program-level execution container. Its input can be a broad
goal or a detailed plan; what makes it a campaign is that Candyland owns the
end-to-end execution cycle, including brief/plan validation, decomposition,
child quests/runs, review, and delivery.
Work item / finding is the bridge between discovery and execution: a
quest or campaign decides it is worth doing, then launches a run to do it.
Agent task is the partitioned work inside a run.
Observability follows the same tree:
A run records detailed agent/task/tool/test/review traces.
A quest records its objective, findings, work-item decisions, child runs, PRs,
blockers, and tick history.
A campaign records original intent, Intent Brief, domain scope, open
questions/escalations, child quests/runs, review routing, PRs, and final
intent-review outcome.
Future centralization can consume these records, but everyday users do not
need to edit or understand the trace store.
Operating Principles To Facilitate
Candyland should facilitate intent-driven development without trying to encode
an organization's human process as product roles. The product model should stay
general and execution-focused:
Users may provide high-level intent, a partial brief, or a detailed plan.
The agent system turns intent into concrete briefs, work items, execution
plans, and delivery artifacts.
Once a run, quest, or campaign has started, Candyland should not enter a
user-feedback question loop. Agent roles must decide, answer, escalate within
the agent hierarchy, and handle all handleable work to completion.
Handoffs are artifact-driven: original intent, issue links, PR links, and run
traces are the map. Avoid manual explanation as the primary context carrier.
Final review checks the shipped result against original intent, not only
against the generated task list.
Escalation is routine and early: unresolved definition questions and mid-build
scope divergence should be routed promptly to the pertinent agent role instead
of hidden until delivery.
Candyland can recommend review routing based on touched areas, but it should
not model human domain experts as agents or require machine-readable org
ownership rules.
Composition Constraint (compose doctrine, do not re-implement in Go)
The Product Intent says: define shared doctrine once and have commands compose or
delegate. Nearly everything quests/campaigns need already exists as Detritus
doctrine. Quest/campaign agents must kb_get these docs at the relevant role;
Candyland Go owns only the genuinely new orchestration substrate (data models,
APIs, process supervision, trace store). If quest/campaign re-encode loop cadence,
fork-gating, the review rubric, or completion logic in Go, the system drifts and
the plan violates its own principle.
Campaign Intent Brief / brief-plan validation / intent lead
core/planning (.plan/<slug>.md contract + readiness/consistency checks) + core/dream (executive intake, architect owns decisions, no user loop)
Run partition / build unit / delivery / per-run tech lead
roles/tech-lead + core/build + core/coder
core/coordination is already dual-driver: "Realization B is built in the
candyland repo (its own PR); detritus ships the protocol + Realization A; candyland
consumes the same contract." Hold this line.
Before building Phases 2-3, encode this constraint into the quest/campaign
role prompts: each role kb_gets its doctrine rather than carrying an
inlined rubric.
HARD PREREQUISITE — this principle is unbuildable on the current substrate.
Today a spawned agent's --mcp-config carries only candyland-comms
(resilience.go:137-140); the detritus MCP is not wired in, so kb_get / kb_search are unreachable and no agent can load doctrine. The composition model is
dead on day one until the substrate item below lands. It is a firm requirement
that every candyland-spawned agent can reach the detritus MCP and the same
authenticated gh used in the VSCode sessions. See 0.2a.
Delivery & PR Policy (who opens PRs)
PR delivery is owned by the top-level container, never by the run itself. A
run takes a delivery directive from its parent:
Standalone run → opens its own PR in its repo. (deliver: pr)
Standalone quest → may open many PRs over time — typically one per
accepted work item / child run. The quest aggregates them.
Campaign → child quests and runs open NO PRs. Each child integrates its
work into a per-repo campaign branch (deliver: branch, commit-only, no PR).
The campaign opens one PR per repo involved, after final intent review.
Campaigns may span multiple repos, but each repo gets a single campaign PR so
agents and human reviewers track the program coherently.
This implies a differentiated campaign-child flow: a run under a campaign uses
the same partition/build/integrate/review machinery but its delivery step targets
the campaign's per-repo branch instead of gh pr create. Make deliver an
explicit field on the run spec, set by the parent container; the run flow branches
only at the final delivery step.
Delivery is the agents' responsibility, and handling blockers is part of it. A
blocker never abandons delivery: the agent hierarchy resolves it, takes one of the core/completion dispositions, or escalates upward (quest lead → campaign tech lead
→ intent lead) until the work is delivered. Stopping the whole campaign because one
work item hit a blocker is not an option — only a genuinely unresolvable hard blocker
pauses, with a visible reason, and the per-repo campaign branch persists as durable
working state so the campaign resumes from where it stopped (never silently
abandoned). Because children never open PRs, there are also no half-open PRs to
reconcile mid-campaign — the per-repo PR opens once delivery is actually done.
Add deliver to the run spec: pr (default for standalone) or branch:<name> (commit-only, no PR) for campaign children.
Quest delivery: one PR per accepted work item (or safe group), aggregated.
Campaign delivery: per-repo campaign branch + one PR per repo at the gate.
Encode blocker handling as a delivery obligation: agents resolve/escalate
within the hierarchy per core/completion; the campaign branch persists
across a pause so a resumed campaign continues delivering.
Autonomy Levels & Budget Ceilings
Staged autonomy and explicit spend limits keep program-scale execution safe and
affordable (L1/L2/L3 rollout and per-loop budgets are standard loop-engineering
practice). A campaign can spawn intent-lead + research + mapper + campaign-TL + quest-leads +
run-TLs + builders + reviewers — each a claude process. Unbounded, this is a real
cost-explosion / HTTP 429 risk.
Autonomy level per quest/campaign: L1 report-only (discover + triage,
no edits/PRs), L2 assisted (build but gate PR/delivery), L3 unattended
(full loop to PR). Default conservative; the user opts up.
Budget ceiling: a token/spend cap per quest and per campaign. When the
cap is hit, pause with a visible reason rather than thrash.
Pre-launch cost estimate: rough projected spend from scope + fleet size
shown before an L3 launch (cobus loop-cost analogue).
Concurrency cap: bound simultaneous claude agents across a
quest/campaign (rate-limit / cost). Tie into the parallelize-only-when-safe
fork-gate from core/todo-audit.
Naming Decisions
Use quest for an iterative loop. A quest can be open-ended or finite and can
produce many PRs over time.
Use campaign for a program-level development cycle. A campaign may start
from a broad goal or a detailed plan; it drives validation, decomposition,
implementation, review, and delivery.
Prefer single-word Detritus commands. Do not require users to compose commands
like /candyland janitor or /plan a /janitor.
Candidate command surface:
/quest launches or manages a Candyland quest.
/campaign launches or manages a Candyland campaign.
/candyland remains the generic sidecar/control command while the new
surfaces mature.
Commands/docs for /plan, /vibe, /smith, /forge, /janitor, /gh, /code, /todo, testing, style, and maintainer workflows.
Candyland install/update/registration support.
The future role for Detritus is to ensure the Candyland sidecar is installed
and running, then call Candyland-owned APIs as a client. Detritus should not
host a separate REST API for quests, campaigns, or runs.
Candyland currently provides:
One-shot multi-agent build runs that produce a PR.
A conductor, ooo bus, task graph, per-agent stream output, run history, and
dashboard.
A launch_run/run_status/stop_run control MCP in the current release.
Per-task and per-agent records that are already close to the trace data needed
for future platform improvement, though currently local-only and run-scoped.
Main gap: Candyland has runs, but not first-class persistent quests or
program-level campaigns.
Phase 0 - Candyland Sidecar Hardening
Build these first (as the leading commits — see Delivery Shape). Most work is in
the Candyland repo; Detritus owns install/lifecycle/registration changes.
Target Process Model
When a Candyland run is active there should be exactly:
One Candyland app process hosting the ooo bus, UI, REST API, and HTTP MCP
surfaces.
One claude process per active agent.
There should be no long-lived per-session control-mcp process and no per-agent
stdio comms-mcp process. git, gh, and version probes are transient and must
spawn windowless on Windows.
Settled decisions:
Delete control-mcp entirely. No per-session MCP process for the editor to
sidecar trigger. The Detritus command/skill drives Candyland by ensuring the
sidecar is up and calling Candyland REST.
Convert comms-mcp from a per-agent stdio process to an HTTP MCP endpoint on
the Candyland app. The bridge is still needed because agents speak MCP tools,
but it must not be a separate process.
Detritus owns Candyland lifecycle: install, update, register, start, and
health-check.
Data lives at ~/.candyland/, never inside a project.
Installation/management must be pure Go in Detritus. No dangling shell
scripts.
Candyland UI is observe-only, with a single developer lens. No run creation
wizard and no mode split.
Candyland does no routing. Vibe/smith/quest/campaign routing happens before
delegation; Mode is removed end-to-end.
0.1 Remove control-mcp; Detritus Drives Sidecar Lifecycle And Run Trigger
Delete Candyland control-mcp as a stdio subcommand.
Delete runControlMCP in Candyland main.go.
Delete the MCP tool layer in Candyland internal/control/control.go
(RegisterTools, launch/status/stop MCP tools).
Remove the per-session MCP registration from Detritus setup: registerCandylandJSON, candyland.go, setup.go, and related tests.
Move resilient ensure-up into Detritus Go code: health-check Candyland,
start the Detritus-managed binary if down, poll until ready, and fail with
clear feedback if startup fails.
Keep Candyland REST run creation/begin as the way Detritus triggers
Candyland. Detritus is only the client/launcher; Candyland owns the API.
Keep POST /api/runs plus /begin as the trigger path.
Update the Detritus /candyland skill/command so invocation is:
ensure Candyland is up -> create and begin the run -> point the user at
the dashboard.
Remove now-dead Candyland code: internal/control/spawn_unix.go, internal/control/spawn_windows.go, detachSysProc, and CANDYLAND_ADDR plumbing.
Cutover sequencing (atomic): deleting control-mcp removes launch_run/run_status/stop_run, which /candyland uses today. The
Detritus REST client + removal from all host MCP configs + the setup_test.go
update must land together — a partial update breaks /candyland.
Liveness probe:GET /api/system shells out 3 uncached subprocesses
per call (claude/git/gh --version, system.go → depVersion). Do not
use it as the hot ensure-up health check; add a cheap dedicated liveness
endpoint (or cache the version probes — see 0.5).
0.2 Convert comms-mcp To An HTTP MCP Endpoint On The App
PRECONDITION SPIKE (do before committing to 0.2): the transport is easy
(go-sdk ships Streamable-HTTP; the ooo/mux server can host it). The hard part
is per-agent identity — today it's a per-process env var
(CANDYLAND_AGENT_ID, baked in at spawn, coordinator.go:76-86). A single
shared HTTP endpoint can't tell agents apart, and --mcp-config headers are
static per file. So you need a per-agent URL (e.g. /mcp/comms/<id>) or a
per-agent config. Verify the pinned claude CLI actually supports a type:http
mcp-config entry with per-agent identity before building — the Go SDK supporting
it is necessary but not sufficient.
Convert comms-mcp into an HTTP MCP endpoint hosted by the Candyland app.
Host comms_send, comms_inbox, brief_get, graph_read, and graph_propose on the Candyland app, calling the in-process ooo bus
directly where possible.
Give each agent MCP identity through URL/header rather than process env.
Use a per-agent URL such as /mcp/comms/<agentID> or a request header for
identity.
Update agent MCP config generation to target the HTTP endpoint.
Change c.busMCPConfig / resilience.go so each agent's --mcp-config
points at the HTTP endpoint instead of spawning candyland comms-mcp.
Delete the old comms-mcp stdio subcommand once unused.
Verify a real run with two agents has exactly two claude processes plus
one app process, and no comms-mcp children.
Keep the test stub that fetches its brief over HTTP working.
0.2a Agent Capability Substrate (detritus MCP + gh for every spawned agent)
Firm requirement: every candyland-spawned agent (tech lead, coders, reviewers,
and the future quest/campaign roles) must have, at spawn:
The detritus MCP — kb_get / kb_search / code_* / skill_* reachable, so
roles load doctrine instead of carrying inlined rubrics (the Composition
Constraint). This is the substrate the whole quest/campaign model assumes.
The authenticated gh used in the VSCode sessions — so any agent can read
private repos and open PRs, end-to-end, without re-auth.
Wire the detritus MCP into the generated --mcp-config for every spawned
agent, alongsidecandyland-comms. Do it the way that does not
reintroduce a per-agent process (the thing 0.2 removes): prefer a long-lived
detritus HTTP MCP the agents connect to, or have the candyland app proxy kb_*/code_*/skill_* over its own HTTP MCP — not a per-agent stdio detritus
spawn. Reconcile with 0.2's transport decision so both MCPs ride the same model.
If a long-lived/proxied detritus MCP is not feasible for some tool, fall back to
orchestrator-resolved doctrine injected into a new bus.Brief field — but the
live MCP is the requirement; injection is the degraded path, not the goal.
gh auth propagation is owned by detritus at sidecar launch: when detritus
ensures-up / starts the sidecar, pass through the gh credential context (env / GH_*/GITHUB_TOKEN, GH_CONFIG_DIR/~/.config/gh, HOME/USERPROFILE) so
the sidecar and every agent it spawns inherit it. See 0.9 for the diagnosis.
Verify end-to-end: a spawned agent calls kb_get successfully AND opens a PR
against a non-public repo, in one real run.
0.3 Fixed Home Data Directory
Store Candyland data under ~/.candyland/ by default.
Default dataPath to ~/.candyland/db using os.UserHomeDir.
Keep --dataPath override.
Create the data directory on startup.
Verify Windows resolves ~/.candyland/ under the user profile.
Add db/ to Detritus .gitignore.
Remove any stray db/ already created in the Detritus repo.
Add best-effort migration from legacy project-local ./db/data.
If legacy ./db/data exists in the launch cwd, move it to ~/.candyland/db on startup. If no DB exists or migration fails, log and
continue with a fresh DB. Never fail startup/update over this.
0.4 Pure-Go Install And Sidecar Management In Detritus
Remove Candyland install scripts; Detritus Go owns install/update/start.
Move Candyland install/update/register into Detritus Go code: download the
release binary, place it, and register it.
Delete Candyland install.sh and install.ps1.
Update any README/docs that reference Candyland install scripts.
Detritus manages Candyland start/stop/health as part of lifecycle
ownership.
🔴 Windows running-exe swap: Windows can't overwrite a running .exe
(observed: candyland --update fails with "rename … Access is denied" while
the sidecar runs). Detritus-owned update must stop the sidecar first, or use
the rename-aside-and-swap pattern Detritus already uses for its own
self-update.
0.5 Windows: No Flashing Console Windows On Any Spawn
Ensure all Windows process spawns are windowless.
Route internal/httpapi/system.go version probes
(claude/git/gh --version, run on every /api/system poll) through
the windowless process config.
Route internal/conductor/git.go git commands through the same helper.
Audit all other exec.Command sites.
Share one configureProc helper across packages.
Remember items 0.1 and 0.2 remove the largest window sources:
per-session control-mcp and per-agent comms-mcp.
Broaden git/gh:internal/conductor/git.go spawns the actual git/gh commands (not just version probes) via plain exec.CommandContext — route
these through the windowless helper too, not only the --version calls.
🔴 Deep Windows process-tree kill:proc_windows.go kills only the direct
child; Unix kills the whole process group (syscall.Kill(-pid), proc_unix.go). With long-lived quest/campaign agents + pause/stop/resume, stop/cancel will orphan claude's grandchildren on Windows. Needs a
Windows job-object or taskkill /T. Gets worse at quest/campaign scale.
0.6 Remove "Launch From Your Editor" UI And Dead Backend Code
Remove UI run creation/planning wizard. Candyland observes and runs flows;
Detritus/user sessions trigger them.
Remove src/components/PlanningFlow.js and related UI.
Remove backend endpoints/handlers that only served UI-initiated run
creation or planning Q&A, including /api/runs/{id}/questions and wizard
plumbing. Keep only the Detritus-triggered REST path.
0.7 Remove Developer/Non-Developer Split And Mode End-To-End
Remove developer/non-developer mode split and Mode fields end-to-end.
Remove UI mode split: src/mode.js, src/components/ModeToggle.js, and
mode branches in App.js / panels.
Render everything through the developer lens.
Remove backend Mode: internal/run/types.go, internal/conductor/planner.go, conductor mode assignments, and Spec.Mode.
Remove the misleading "developer task" label seen when launching via /candyland.
Make the phase stepper match real behavior.
Remove the "Plan" step from Phases in internal/run/types.go, or rename
it to "Partition" if the split is worth surfacing. Recommendation from the
existing backlog: drop it.
Coordinate with review-loop work below. Settle final stepper as something
like ["Build", "Integrate", "Review", "PR"].
Fix index math in internal/conductor/helpers.go and executor_claude.go; they currently index Phases by offset such as len(run.Phases) - 2.
Sweep dead mode constants, props, styles, labels, and tests.
0.8 Enforce Real Review Loop With Separate Review Agents
Add a real review phase after integration: spawn separate reviewer agents,
fix findings, and re-review until clean or bounded failure.
Today review is mostly cosmetic: the flow is Plan -> Build -> Integrate ->
PR, and Review in Phases is not backed by reviewer agents.
Add a genuine review phase after integration.
Spawn separate review agent(s) over the integrated branch.
Collect findings.
Loop fix -> re-review until review comes back empty, with bounded
max-rounds mirroring maxReplans / maxAttempts.
Use Detritus review doctrine (review-rigor / /gh-self-review style)
rather than an ad-hoc inline rubric.
Make the UI Review phase reflect real review activity.
Verify on a real run that a reviewer agent is spawned, findings drive
fixes, and the run only opens the PR once review is clean.
0.9 Reuse Authenticated gh In Candyland Jobs
Firm requirement (see 0.2a): every Candyland-spawned agent uses the same
authenticated gh as the VSCode sessions and can open PRs in private repos.
Correct the diagnosis first. Agent (claude) spawns already inherit full os.Environ() (claudeEnv(), resilience.go:26-32,143), and the detached
sidecar launch leaves cmd.Env nil (control.go:92-94) so it inherits the
parent env too — detachSysProc only sets session/console flags and touches no env. The "detached path drops env/HOME" hypothesis is refuted by the
code; do not chase it.
Verify the real candidates instead: (a) the gh token's scope for the
target private repo; (b) on Windows, whether USERPROFILE/HOME in the
spawning context resolves to the profile gh auth login actually wrote to
(credential-manager / GH_CONFIG_DIR resolution).
Propagate at the launch boundary (the new owner is detritus): once detritus
owns ensure-up/start (0.1), it must pass the gh credential context through to
the sidecar at launch (GH_*/GITHUB_TOKEN, GH_CONFIG_DIR/~/.config/gh, HOME/USERPROFILE); agents then inherit it via os.Environ(). This is the
same propagation tracked in 0.2a — keep them consistent.
Verify end-to-end: a Candyland-spawned agent opens a PR against a non-public
repo in one real run.
0.10 Deterministic Replay / Test Harness
There is no deterministic way to regression-test multi-agent orchestration
without burning tokens. The HTTP brief-stub kept in 0.2 (a process that fetches
its brief over HTTP and stands in for claude) is the seed of one — formalize
it into a replay/regression harness so quest/campaign flows can be tested
without real model calls (no API budget; see local-only constraint).
0.11 Update README To Match Reality
Rewrite Candyland README after these changes land.
Describe Candyland as an observe-only sidecar to Detritus.
Document that runs are driven from the user session/Detritus, not from
in-UI planning.
Document one app process plus one claude process per active agent.
Remove references to deleted pieces: control-mcp, comms-mcp as a process, install.sh, install.ps1,
"Launch from your editor" UI, developer/non-developer modes, and the
"Plan" phase.
Use present tense. Docs should describe the codebase as it is, not narrate
the migration.
Check Detritus docs/README for stale Candyland mentions. Detritus README is
generated, so update source docs and regenerate.
Phase 1 - Preserve And Normalize Run Traces
Candyland already records much of what is needed inside each task run. Do not
invent a separate trace platform yet. First, normalize the local record shape so
it can later be centralized with low friction. Centralized learning is not part
of the near-term implementation.
Trace Contract By Level
Trace enough at each level to support local observability now and centralization
later without backfilling missing relationships.
Run trace:
Stable IDs: runID, parent questID and/or campaignID when present.
Review: implementation-plan review result, final intent-review result, and
campaign gate decisions.
Centralization constraint:
Store parent-child links and stable IDs from the start.
Keep traces local-first and exportable.
Redact or mark sensitive payloads before any future sync.
Do not build central storage, analytics, or platform-learning jobs yet.
Audit current run, agent, task, bus, and event schemas.
Define a stable local trace schema for each run:
intent, prompt/brief, folders/repos, agents, task graph, messages, tool
events, tests, review findings, retries, failures, PRs, timestamps, and
rough token/cost fields when available.
Ensure every agent event is tied to runID, agentID, taskID where
applicable, and a monotonic sequence.
Preserve original intent separately from generated plans/tasks so final
review can compare output against intent, not only against task completion.
Store PR/issue links as first-class trace artifacts.
Make local trace export possible, even if centralization is deferred.
Do not build a broad user-facing analytics/editing surface yet. Platform
improvement from trace data is a separate concern from everyday developer
use.
Phase 2 - Quest: Candyland Iterative Loop
A quest is a Candyland-native iterative loop. It is the generalized sidecar
homologue to /janitor, but it is not constrained to maintenance. A quest can
be open-ended or finite, and it may produce several PRs over time.
Quest Roles
Quest lead: owns the loop objective, iteration strategy, triage decisions, and
whether findings/tasks become work items. This is the technical overview role
for the quest level.
Discovery/planning agent(s): inspect the target scope, provided task list,
reference document, PR, or repo to identify the next work items.
Triage/review agent: checks whether a finding/task is safe, in-scope,
actionable, and worth launching as a run.
Run tech lead: the existing per-run tech lead that partitions an accepted work
item into agent tasks.
Builder/reviewer agents: the existing per-run implementation and review
agents.
The quest lead decides whether to launch one run at a time or several parallel
runs. It should parallelize only when findings are independent enough that the
resulting PRs will not collide.
Quest Inputs
Examples:
Keep flaky tests under control.
Audit auth/session handling.
Continuously reduce dead code.
Improve test isolation in a repo.
Keep a migration moving during downtime.
Execute this task list, one PR per task or per safe group of tasks.
Check this PR against a policy/specification document.
Check this repo against a compliance or architecture document.
Repeatedly audit one topic until no safe/actionable work remains.
Quest Lifecycle
Add a first-class Quest model separate from Run.
A quest owns many findings, work items, runs, PRs, and trace records.
It cascades into the existing run flow for each accepted work item/PR.
A quest begins with an intent-refinement phase equivalent to "plan a
janitor" so the loop has a crisp objective, scope, iteration strategy,
safety boundary, and verification command.
Formalize /janitor as plan-gated setup even for in-session use: it should
refine loop intent before execution instead of jumping straight to generic
scheduled audit. /janitor remains the in-session variant; /quest is
Candyland-native. NOTE:/janitor is currently the deliberately not plan-gated sibling of /smith (it jumps to the audit tick). Plan-gating it changes in-session
behavior and touches core/loop/janitor.md doctrine — track this as a
separate doctrine change, not bundled with the Candyland substrate work.
Quest agents must compose doctrine (see Composition Constraint): the tick
loop kb_gets core/loop + core/todo-audit (parallelize-only-when-safe) + core/completion; reviewers kb_getcore/review-rigor. Do not re-encode in Go.
Honor the Delivery & PR Policy: a standalone quest aggregates many PRs
(one per safe work item); a campaign-owned quest opens none (deliver: branch).
Apply Autonomy Levels & Budget Ceilings: quests carry an L1/L2/L3 level and
a spend cap; pause with a visible reason at the cap.
Remove or de-emphasize detailed scheduling options for quest setup. The
default goal is to minimize downtime between ticks and keep working until
stopped, blocked, or out of safe findings.
Add quest tick behavior:
discover or select the next work item, triage safe work, launch one or
more build/check runs, review, open PRs or record compliance results,
update quest state, immediately continue when safe.
Let the quest lead decide per tick whether accepted work items run
sequentially or in parallel, based on file/repo overlap, risk, and review
load.
Support multiple PRs per quest.
Add a stop/pause mechanism and visible reason for pause.
Add bounded retry/escalation behavior so a quest does not thrash on the
same blocked item forever.
Add quest dashboard views: objective, current tick, findings, active runs,
PRs, blockers, recent trace, and next action.
Detritus Surface
Add a single-word /quest command in Detritus.
/quest should read Detritus KB guidance, refine intent, ensure
Candyland is running, then call Candyland-owned quest APIs.
Update /janitor docs to either delegate to /quest or clearly describe
itself as the in-session/legacy variant.
Keep Candyland as the execution source of truth; Detritus should not
duplicate quest state in scratchpads except as a launch handoff.
Phase 3 - Campaign: Intent-Driven Development Flow
A campaign is a program-level intent-to-delivery execution cycle. It can start
from a high-level goal, a partially formed brief, or a detailed implementation
plan. The distinguishing feature is not the input shape; it is that Candyland
owns the full execution cycle after launch: validation, decomposition,
implementation, review, and delivery.
Once launched, a campaign should not ask the user clarifying questions. If the
input is under-specified, contradictory, or becomes invalid mid-build, the
campaign routes that issue through its internal roles. Only a true hard blocker
pauses execution.
Campaign Roles
Intent lead: owns restating the intent, normalizing broad goals or detailed
plans into the campaign record, collecting unresolved questions, and deciding
when the Intent Brief is ready for the campaign gate.
Research agent(s): inspect code, existing PRs/issues, docs, and relevant
external context where allowed.
Surface/domain mapper: marks backend, frontend, game logic, dashboard/UI,
deployment, design, hardware, or other areas as needed/not needed with
reasons. This is a product/technical mapping role, not a human ownership
model.
Campaign tech lead: owns the technical overview above quests/runs. It decides
what becomes a quest, what becomes a direct run, what can parallelize, and
what must wait.
Quest lead(s): own persistent/exploratory workstreams spawned by the campaign.
Run tech lead(s): own the existing per-run partition/build/integrate/review
flow.
Builder/reviewer agents: implement and review scoped run tasks.
Review router: suggests which human reviewers or review areas are needed based
on touched surfaces. It does not model those humans as agents.
Intent reviewer: checks final output against original intent, not just the
generated task list.
Campaign Communication Flow
Communication is hierarchical and agent-directed. Peer agents do not negotiate
scope directly, and no role asks the user for clarification during execution.
Campaign supervisor
-> Intent lead
-> Research agent(s)
-> Surface/domain mapper
-> Campaign tech lead
-> Quest lead(s)
-> Discovery agent(s)
-> Triage/review agent
-> Run tech lead(s)
-> Builder/reviewer agents
-> Direct run tech lead(s)
-> Builder/reviewer agents
-> Review router
-> Intent reviewer
Rules:
The campaign supervisor owns the campaign state and is the only role that
moves the campaign between stages.
The intent lead owns definition questions. It answers them from available
context, assumptions, research, and role feedback; it does not ask the user.
The campaign tech lead owns technical decomposition, dependency ordering, and
parallelization across child quests/runs.
Quest leads own persistent workstreams spawned by the campaign.
Run tech leads own per-run partition/build/integrate/review flow.
Builders and reviewers report blockers/findings upward to their run tech lead.
Quest-level issues route to the quest lead; campaign-level issues route to the
campaign tech lead or intent lead depending on whether they are technical or
definitional.
The review router suggests human review areas/reviewers for the resulting PRs
but does not contact the user or model humans as agents.
Campaign Lifecycle
Add a first-class Campaign model above Quest and Run.
Store the original campaign input as immutable campaign input, whether it
is a high-level goal, partial brief, or detailed plan.
Generate an Intent Brief with:
restated goal, scope by domain, resolved/escalated questions, draft task
list, dependencies, rough sizing, and review-routing suggestions.
Add a campaign gate after the Intent Brief: verify that the brief reflects
the campaign input before implementation planning proceeds.
Add a campaign gate after implementation planning: verify that the
proposed quests/runs would plausibly deliver the campaign input before
execution begins.
Allow the campaign to split into multiple features/tasks when the intent
is too broad.
Support early intent escalation when research or mapping agents cannot
resolve what the campaign input means. This escalates to the intent lead
or campaign supervisor, not to the user.
Support mid-build intent realignment when reality no longer fits the
original box: redefine, split, or add resources inside the campaign flow.
Convert the approved/settled brief into child quests and/or direct
Candyland runs. Persistent or exploratory streams become quests; finite
scoped delivery items can become direct runs.
Let the campaign tech lead decide what can execute in parallel across
child quests/runs, based on repo/file overlap, dependencies, risk, and
review load.
Preserve artifact-driven handoff: original intent, brief, issues, PR links,
and trace records.
Keep campaign delivery to one PR per repo involved. Campaigns may span
multiple repos, but each repo should have a single campaign PR so agents
and human reviewers can track the campaign coherently.
Suggest review routing for specialized or high-risk surfaces without
modeling domain reviewers as agents.
Add final intent review before campaign completion.
Specify the intent-review METHOD (the campaign's novel core — currently just
named).core/review-rigor covers code mechanics, not intent-satisfaction.
Define a concrete, reproducible method for "did we build what was meant":
e.g. the intent reviewer reads the immutable original input + Intent Brief, then
checks each brief commitment against the shipped diff/PRs and produces a
satisfied/partial/missed verdict per commitment with evidence — not a vibe check.
Without a method this gate is not reproducible.
Apply Autonomy Levels & Budget Ceilings: a campaign carries a global spend
cap across all child quests/runs and a pre-launch cost estimate; it pauses at the
cap with a visible reason rather than spawning unboundedly.
Delivery follows the Delivery & PR Policy: child quests/runs commit to a
per-repo campaign branch (no child PRs); the campaign opens one PR per repo at
the gate after intent review. Agents handle blockers to completion (resolve or
escalate within the hierarchy); a blocker does not abandon delivery, and the
per-repo branch persists across a pause for resume.
Detritus Surface
Add a single-word /campaign command in Detritus.
/campaign should launch the Candyland campaign flow directly from a
high-level instruction, partial brief, or detailed plan. It should ensure
Candyland is running and call Candyland-owned campaign APIs. It should not
require a prior /plan.
Keep /vibe distinct from /campaign. /vibe is an in-session flow
that does not use the Candyland multi-agent loop. /campaign is a
Candyland-run program-level execution flow. They may share doctrine, but
one should not be described as a simple legacy/delegating form of the
other.
Phase 4 - Centralization Readiness Only
Do not implement centralized learning data yet. This phase is only about making
local traces easy to centralize later with minimal migration friction.
Developers should not need to understand or edit platform traces to use
Detritus/Candyland.
Keep all run/quest/campaign records local-first.
Use stable IDs and parent-child links at every level.
Keep trace schemas versioned.
Keep export format explicit and boring, preferably JSON/JSONL.
Mark/redact sensitive payload fields before any future sync path exists.
Avoid building dashboards, analytics, or platform-improvement jobs that
depend on a central store.
Keep learned-memory writes verified-gated if/when traces later feed
improvement workflows.
Why this matters (the eventual purpose): the deferred meta-loop is
langchain's "Loop 4 / hill climbing" — an analysis agent reads production
traces, spots systematic failure patterns across runs, and proposes
prompt/tool/rubric adjustments, making the inner loops better over time. We do
NOT build it now (no API budget; local-only). But design the Phase 1 trace
contract — stable IDs, parent-child links, per-finding verdicts — so this loop
can later consume traces with zero backfill. That is the reason the trace shape
is first-class now.
Phase 5 - Documentation And Command Cleanup
Do this after substrate changes land, not before.
Update Detritus docs/flows/build/candyland.md to describe the final
lifecycle-owned sidecar.
Add docs/flows/build/quest.md.
Add docs/flows/build/campaign.md or docs/flows/plan/campaign.md;
choose location based on whether the command is framed as build or intake.
Update Candyland README to describe the observe-only sidecar, quests,
campaigns, local traces, review phase, and Detritus-managed lifecycle.
Phase 6 - Candyland UI Hierarchy
The UI should expose the hierarchy without hiding the atomic run/task history.
Users should be able to inspect work at the level they care about and pivot
between levels.
Keep one main history/work section with filters and pivoted views, rather
than separate top-level history pages.
Provide view pivots for runs/tasks, quests, and campaigns inside that main
section.
Keep an all-runs/all-tasks history view so users can see runs executed
outside any quest or campaign.
Add filters for:
no parent, campaign, quest, repo/folder, status, PR state, date, and text.
In run/task views, show parent campaign/quest links when present.
In quest views, show objective, current tick, findings, accepted work
items, child runs, PRs, blockers, and next action.
In campaign views, show original intent, Intent Brief, gates, child
quests/runs, PRs, blockers, review routing, and final intent review.
Support pivoting from any level to children and back to parent without
losing filters.
Keep the UI observe/control focused: pause/stop/resume where supported,
but no broad trace editing.
Phase 7 - Candyland Quest/Campaign APIs
Candyland owns the quest/campaign/run APIs. Detritus should only ensure the
sidecar is running and call these APIs as a client.
Quest API outline:
POST /api/quests creates a quest.
POST /api/quests/{id}/begin starts or continues quest execution.
GET /api/quests/{id} returns quest status and rollup state.
POST /api/quests/{id}/pause pauses future ticks without deleting state.
POST /api/quests/{id}/resume resumes a paused quest.
POST /api/quests/{id}/stop stops the quest and marks the reason.
GET /api/quests/{id}/runs lists child runs.
GET /api/quests/{id}/findings lists findings/work items.
Campaign API outline:
POST /api/campaigns creates a campaign.
POST /api/campaigns/{id}/begin starts or continues campaign execution.
GET /api/campaigns/{id} returns campaign status and rollup state.
POST /api/campaigns/{id}/pause pauses future execution without deleting
state.
POST /api/campaigns/{id}/resume resumes a paused campaign.
POST /api/campaigns/{id}/stop stops the campaign and marks the reason.
GET /api/campaigns/{id}/quests lists child quests.
GET /api/campaigns/{id}/runs lists direct and quest-child runs.
Suggested First Implementation Order
Finish Phase 0 hardening, especially HTTP comms MCP and real review phase.
Normalize local run trace records without centralization.
Add parent-child trace links and UI filters for run/task history.
Add Quest data model and dashboard view.
Add /quest Detritus command and Candyland quest launch endpoint.
Implement quest tick loop with discovery -> triage -> run -> review -> PR.
Add Campaign model and Intent Brief generation.
Add campaign gates for Intent Brief and implementation-plan review.
Add Candyland quest/campaign APIs.
Add /campaign Detritus command that launches Candyland campaigns.
Add review routing suggestions and final intent review.
Keep centralization as future work; only preserve exportable local traces now.
/forge plan contract — Candyland quest & campaign execution flows
This is a handoff backlog for moving Detritus/Candyland toward an intent-driven
development model. It is deliberately self-contained so a fresh agent can pick it up
without needing the conversation that produced it.
Intent
Evolve Candyland from one-shot multi-agent runs into an intent-driven execution
sidecar (Run → Quest → Campaign), with Detritus owning its lifecycle and serving as
the knowledge/command surface its agents compose. Candyland is the execution +
observability surface; Detritus owns doctrine, install/lifecycle, and thin commands.
Acceptance / completion gate
The build is complete when, per
core/completion(inherited viaroles/tech-leadand
core/build— not restated):- [ ]acceptance item below that is in scope is satisfied and checked.go test ./...is green in both repos;go vetandGOOS=windows go build ./...pass in candyland; the candyland stub-based e2e (
scripts/e2e.mjs) and validators pass.kb_getdoctrineand open a PR against a non-public repo in a real stub-driven run (0.2a + 0.9).
/gh-self-reviewover the full diff, no new deferral markers./candylandspawns a deleted subcommand).Out of scope & blockers (core/completion dispositions)
meta-loop. Phase 4 is only local-trace-shape readiness (stable IDs, parent-child
links, exportable JSONL). Building a central store/analytics is a deferral, not
in-scope work.
blocked until the
core/intent-reviewdoctrine doc exists (authoring that doc is anin-scope Phase 3 task — do it first). The 0.2 HTTP-comms work is gated on the
CLI-version spike (in-scope, first candyland commit); if the CLI floor is unmet,
comms-mcpstays a process and 0.2 is skipped without blocking the rest./janitorplan-gating (Phase 2) altersin-session behavior; keep it an isolated, clearly-labelled commit in the detritus PR.
Fork-safe partitioning guidance (for the greenfield phases)
Phase 0/1 items are concrete (file:line). The greenfield phases are specified at goal
level; the tech-lead should partition them along these file-disjoint seams so
coders don't collide, and gate each with the named verification oracle (all stub-based,
no live model — no API budget):
Questmodel + storage [run/types.go-analog, conductor];(b) quest REST endpoints (Phase 7) [httpapi]; (c) quest tick loop [conductor];
(d)
/questcommand [detritus]; (e) quest dashboard view [src/ UI]. Seams a→b→c areordered; d and e fork off once the API shape is fixed.
Oracle: a scripted-stub tick test asserting discover→triage→run→review→PR
transitions and stop/pause state, on the existing
writeFakeClaudeharness.core/intent-reviewdoctrine doc [detritus, FIRST];(b)
Campaignmodel + storage; (c) campaign REST endpoints; (d) supervisor/intent-leadflow + the two gates; (e)
/campaigncommand; (f) campaign UI. b/c/e/f arefile-disjoint; d depends on a+b.
Oracle: a stub campaign asserting Intent-Brief gate, impl-plan gate, and the
per-commitment intent-review verdict schema
{satisfied,partial,missed}+ citedevidence; assert
missedblocks the repo PR andpartialannotates only.src/), disjoint from backend; partition byview (history/filters, run/task, quest, campaign pivots). Oracle: the existing UI
validators + a render/smoke check per view.
per-endpoint handler tests.
Delivery Shape Of This Work
The entire issue ships as exactly one PR per repo — one in detritus, one in
candyland (the two are distinct repos with no shared history, so a PR cannot span
both). Phasing is by commits within each PR, not by multiple PRs over time. The
phase numbers and "Suggested First Implementation Order" below define commit
order, not separate deliverables.
surface and removes
control-mcp; the detritus PR switches to driving candylandover that surface. Merge the consumer-ready side such that
/candylandnever has awindow where it spawns a deleted subcommand (detritus adopting the existing REST +
ensure-up can land first; candyland's deletion follows or lands together). This is a
merge-ordering note, not a phasing-into-many-PRs requirement.
commit-by-commit even though it lands as one PR.
Settled Decisions (so an autonomous run needs no clarification)
These resolve the load-bearing ambiguities a coder would otherwise invent. Each
supersedes any looser phrasing in its phase.
kb_gets a new doctrinedoc (
core/intent-review); it does not inline a rubric. Method: extract eachcommitment from the Intent Brief (one checkable assertion each); for each, emit a
verdict in
{satisfied, partial, missed}with cited evidence (diff/PR/test) —never a vibe check. Gate: a
missedblocks that repo's PR; apartialannotates thePR and routes to the review router but does not block. Defer Phase 3 build until
this doc exists.
resilience.go:81-92:CANDYLAND_QUEST_TOKEN_CAP,CANDYLAND_CAMPAIGN_TOKEN_CAP,CANDYLAND_CONCURRENCY(default = the current parallel-coder cap). Cost estimate =agents × attemptTimeout × model-rate, computed inline; drop the cobus reference.Cap-hit disposition = degrade-to-serial, then deliver-partial — never
pause(a pre-PR pause is a no-PR terminal state under /smith). Anchor token defaults on the
existing candyland
TokensBudget/per-token constants./quest///campaigncommand passes anexplicit level. Campaigns default to L2/L3 (end-to-end delivery is their
contract); never L1 (report-only would strand a campaign with no PR and no in-loop
opt-up moment). Quests default per their intent.
deliverfield. Mirrors the per-repoPRs[]shape, not a scalarbranch:<name>(which can't carry N per-repo branch names):
deliver ∈ {pr, branch}+ derivedper-repo branch
campaign/<campaignID>. Resume = fetch + checkout existingcampaign/<id>if present, else create.["Build","Integrate","Review","PR"]. Land 0.7 + 0.8 inone change. Update the Go literal indices (
executor_claude.go:292=1,helpers.go:52==1→0;len-Nmath self-adjusts) and the duplicated UIarray
src/meta/run.js:7(consumed by RunWorkspace/RunSwitcher/AuditPanel/Dashboard/Tasks) in lockstep; convert offsets to named constants.
/mcp/comms/<agentID>(survivesheader-stripping proxies; header is the weaker fallback). Assert a minimum claude
CLI version at sidecar startup (the installer floats latest;
type:httpsupport isa CLI property pinned nowhere). Run the spike as the first commit; keep 0.2 separable
so
comms-mcpcan remain a process if the CLI floor is unmet.WSL/Linux host they are static-verified + cross-compiled only (
GOOS=windowsbuild + vet); runtime verification is deferred to a Windows host and the run must
not claim they "work." Kill mechanism = a Windows Job Object
(
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE), not "job-object ORtaskkill /T". Exe-swapmirrors detritus's own self-update rename-aside (
update.go:244-263).Product Intent
Detritus is the knowledge and command surface. It owns doctrine,
install/update/lifecycle guidance, skills, and thin commands that route work.
Detritus skills should be composable by default and should avoid duplicate
workflow implementations. When two commands need the same behavior, define the
shared doctrine once and have commands compose or delegate to it.
Candyland is the execution and observability surface. It owns long-lived agent
processes, task graphs, run records, traces, dashboard views, and local records
that can be centralized later with low friction.
Do not add heavy observability to in-session commands like
/forge,/smith, or/vibe. Those are transitional/control surfaces. The durable loop runtime shouldlive in Candyland, where each agent has its own session and the records are
granular enough to improve the platform later.
Component Tree
The intended model is hierarchical. Each level owns data at its own abstraction
level and aggregates child records without flattening away the detail.
Definitions:
Runis the atomic Candyland execution unit. It is the current flow: atech-lead/coder/reviewer agent graph takes a scoped instruction and delivers a
PR or a precise failure.
Questis an iterative loop container. It may be open-ended or finite. It candiscover/triage findings, execute a provided task list, check compliance, audit
a PR or repo against a document, or run any other repeated work pattern. A
quest repeatedly launches runs, so one quest can produce many PRs.
Campaignis a program-level execution container. Its input can be a broadgoal or a detailed plan; what makes it a campaign is that Candyland owns the
end-to-end execution cycle, including brief/plan validation, decomposition,
child quests/runs, review, and delivery.
Work item/findingis the bridge between discovery and execution: aquest or campaign decides it is worth doing, then launches a run to do it.
Agent taskis the partitioned work inside a run.Observability follows the same tree:
blockers, and tick history.
questions/escalations, child quests/runs, review routing, PRs, and final
intent-review outcome.
need to edit or understand the trace store.
Operating Principles To Facilitate
Candyland should facilitate intent-driven development without trying to encode
an organization's human process as product roles. The product model should stay
general and execution-focused:
plans, and delivery artifacts.
user-feedback question loop. Agent roles must decide, answer, escalate within
the agent hierarchy, and handle all handleable work to completion.
traces are the map. Avoid manual explanation as the primary context carrier.
against the generated task list.
scope divergence should be routed promptly to the pertinent agent role instead
of hidden until delivery.
not model human domain experts as agents or require machine-readable org
ownership rules.
Composition Constraint (compose doctrine, do not re-implement in Go)
The Product Intent says: define shared doctrine once and have commands compose or
delegate. Nearly everything quests/campaigns need already exists as Detritus
doctrine. Quest/campaign agents must
kb_getthese docs at the relevant role;Candyland Go owns only the genuinely new orchestration substrate (data models,
APIs, process supervision, trace store). If quest/campaign re-encode loop cadence,
fork-gating, the review rubric, or completion logic in Go, the system drifts and
the plan violates its own principle.
/ghdeliverycore/loop+flows/build/janitorcore/todo-auditfork-gates (evidence window, disjoint files/modules, no cross-dep)core/review-rigor+/gh-self-review(explicitly forbids the hand-rolled rubric Phase 0.8 warns against)core/completion(done-definition, 3 dispositions, K=3 circuit breaker)core/planning(.plan/<slug>.mdcontract + readiness/consistency checks) +core/dream(executive intake, architect owns decisions, no user loop)roles/tech-lead+core/build+core/codercore/coordinationis already dual-driver: "Realization B is built in thecandyland repo (its own PR); detritus ships the protocol + Realization A; candyland
consumes the same contract." Hold this line.
role prompts: each role
kb_gets its doctrine rather than carrying aninlined rubric.
HARD PREREQUISITE — this principle is unbuildable on the current substrate.
Today a spawned agent's
--mcp-configcarries onlycandyland-comms(
resilience.go:137-140); the detritus MCP is not wired in, sokb_get/kb_searchare unreachable and no agent can load doctrine. The composition model isdead on day one until the substrate item below lands. It is a firm requirement
that every candyland-spawned agent can reach the detritus MCP and the same
authenticated
ghused in the VSCode sessions. See 0.2a.Delivery & PR Policy (who opens PRs)
PR delivery is owned by the top-level container, never by the run itself. A
run takes a delivery directive from its parent:
deliver: pr)accepted work item / child run. The quest aggregates them.
work into a per-repo campaign branch (
deliver: branch, commit-only, no PR).The campaign opens one PR per repo involved, after final intent review.
Campaigns may span multiple repos, but each repo gets a single campaign PR so
agents and human reviewers track the program coherently.
This implies a differentiated campaign-child flow: a run under a campaign uses
the same partition/build/integrate/review machinery but its delivery step targets
the campaign's per-repo branch instead of
gh pr create. Makedeliveranexplicit field on the run spec, set by the parent container; the run flow branches
only at the final delivery step.
Delivery is the agents' responsibility, and handling blockers is part of it. A
blocker never abandons delivery: the agent hierarchy resolves it, takes one of the
core/completiondispositions, or escalates upward (quest lead → campaign tech lead→ intent lead) until the work is delivered. Stopping the whole campaign because one
work item hit a blocker is not an option — only a genuinely unresolvable hard blocker
pauses, with a visible reason, and the per-repo campaign branch persists as durable
working state so the campaign resumes from where it stopped (never silently
abandoned). Because children never open PRs, there are also no half-open PRs to
reconcile mid-campaign — the per-repo PR opens once delivery is actually done.
deliverto the run spec:pr(default for standalone) orbranch:<name>(commit-only, no PR) for campaign children.within the hierarchy per
core/completion; the campaign branch persistsacross a pause so a resumed campaign continues delivering.
Autonomy Levels & Budget Ceilings
Staged autonomy and explicit spend limits keep program-scale execution safe and
affordable (L1/L2/L3 rollout and per-loop budgets are standard loop-engineering
practice). A campaign can spawn intent-lead + research + mapper + campaign-TL + quest-leads +
run-TLs + builders + reviewers — each a
claudeprocess. Unbounded, this is a realcost-explosion / HTTP 429 risk.
L1report-only (discover + triage,no edits/PRs),
L2assisted (build but gate PR/delivery),L3unattended(full loop to PR). Default conservative; the user opts up.
cap is hit, pause with a visible reason rather than thrash.
shown before an L3 launch (cobus
loop-costanalogue).claudeagents across aquest/campaign (rate-limit / cost). Tie into the parallelize-only-when-safe
fork-gate from
core/todo-audit.Naming Decisions
questfor an iterative loop. A quest can be open-ended or finite and canproduce many PRs over time.
campaignfor a program-level development cycle. A campaign may startfrom a broad goal or a detailed plan; it drives validation, decomposition,
implementation, review, and delivery.
like
/candyland janitoror/plan a /janitor./questlaunches or manages a Candyland quest./campaignlaunches or manages a Candyland campaign./candylandremains the generic sidecar/control command while the newsurfaces mature.
Current State
Detritus currently provides:
kb_list,kb_get,kb_search,kb_sections.code_map,code_outline,code_graph.skill_put,skill_search,skill_get./plan,/vibe,/smith,/forge,/janitor,/gh,/code,/todo, testing, style, and maintainer workflows.and running, then call Candyland-owned APIs as a client. Detritus should not
host a separate REST API for quests, campaigns, or runs.
Candyland currently provides:
dashboard.
launch_run/run_status/stop_runcontrol MCP in the current release.for future platform improvement, though currently local-only and run-scoped.
Main gap: Candyland has runs, but not first-class persistent quests or
program-level campaigns.
Phase 0 - Candyland Sidecar Hardening
Build these first (as the leading commits — see Delivery Shape). Most work is in
the Candyland repo; Detritus owns install/lifecycle/registration changes.
Target Process Model
When a Candyland run is active there should be exactly:
surfaces.
claudeprocess per active agent.There should be no long-lived per-session
control-mcpprocess and no per-agentstdio
comms-mcpprocess.git,gh, and version probes are transient and mustspawn windowless on Windows.
Settled decisions:
control-mcpentirely. No per-session MCP process for the editor tosidecar trigger. The Detritus command/skill drives Candyland by ensuring the
sidecar is up and calling Candyland REST.
comms-mcpfrom a per-agent stdio process to an HTTP MCP endpoint onthe Candyland app. The bridge is still needed because agents speak MCP tools,
but it must not be a separate process.
health-check.
~/.candyland/, never inside a project.scripts.
wizard and no mode split.
delegation;
Modeis removed end-to-end.0.1 Remove
control-mcp; Detritus Drives Sidecar Lifecycle And Run Triggercontrol-mcpas a stdio subcommand.runControlMCPin Candylandmain.go.internal/control/control.go(
RegisterTools, launch/status/stop MCP tools).registerCandylandJSON,candyland.go,setup.go, and related tests.start the Detritus-managed binary if down, poll until ready, and fail with
clear feedback if startup fails.
Candyland. Detritus is only the client/launcher; Candyland owns the API.
POST /api/runsplus/beginas the trigger path./candylandskill/command so invocation is:ensure Candyland is up -> create and begin the run -> point the user at
the dashboard.
internal/control/spawn_unix.go,internal/control/spawn_windows.go,detachSysProc, andCANDYLAND_ADDRplumbing.control-mcpremoveslaunch_run/run_status/stop_run, which/candylanduses today. TheDetritus REST client + removal from all host MCP configs + the
setup_test.goupdate must land together — a partial update breaks
/candyland.GET /api/systemshells out 3 uncached subprocessesper call (
claude/git/gh --version,system.go→depVersion). Do notuse it as the hot ensure-up health check; add a cheap dedicated liveness
endpoint (or cache the version probes — see 0.5).
0.2 Convert
comms-mcpTo An HTTP MCP Endpoint On The App(go-sdk ships Streamable-HTTP; the ooo/
muxserver can host it). The hard partis per-agent identity — today it's a per-process env var
(
CANDYLAND_AGENT_ID, baked in at spawn,coordinator.go:76-86). A singleshared HTTP endpoint can't tell agents apart, and
--mcp-configheaders arestatic per file. So you need a per-agent URL (e.g.
/mcp/comms/<id>) or aper-agent config. Verify the pinned
claudeCLI actually supports atype:httpmcp-config entry with per-agent identity before building — the Go SDK supporting
it is necessary but not sufficient.
comms-mcpinto an HTTP MCP endpoint hosted by the Candyland app.comms_send,comms_inbox,brief_get,graph_read, andgraph_proposeon the Candyland app, calling the in-process ooo busdirectly where possible.
/mcp/comms/<agentID>or a request header foridentity.
c.busMCPConfig/resilience.goso each agent's--mcp-configpoints at the HTTP endpoint instead of spawning
candyland comms-mcp.comms-mcpstdio subcommand once unused.claudeprocesses plusone app process, and no
comms-mcpchildren.0.2a Agent Capability Substrate (detritus MCP + gh for every spawned agent)
Firm requirement: every candyland-spawned agent (tech lead, coders, reviewers,
and the future quest/campaign roles) must have, at spawn:
kb_get/kb_search/code_*/skill_*reachable, soroles load doctrine instead of carrying inlined rubrics (the Composition
Constraint). This is the substrate the whole quest/campaign model assumes.
ghused in the VSCode sessions — so any agent can readprivate repos and open PRs, end-to-end, without re-auth.
--mcp-configfor every spawnedagent, alongside
candyland-comms. Do it the way that does notreintroduce a per-agent process (the thing 0.2 removes): prefer a long-lived
detritus HTTP MCP the agents connect to, or have the candyland app proxy
kb_*/code_*/skill_*over its own HTTP MCP — not a per-agent stdio detritusspawn. Reconcile with 0.2's transport decision so both MCPs ride the same model.
orchestrator-resolved doctrine injected into a new
bus.Brieffield — but thelive MCP is the requirement; injection is the degraded path, not the goal.
ensures-up / starts the sidecar, pass through the gh credential context (env /
GH_*/GITHUB_TOKEN,GH_CONFIG_DIR/~/.config/gh,HOME/USERPROFILE) sothe sidecar and every agent it spawns inherit it. See 0.9 for the diagnosis.
kb_getsuccessfully AND opens a PRagainst a non-public repo, in one real run.
0.3 Fixed Home Data Directory
~/.candyland/by default.dataPathto~/.candyland/dbusingos.UserHomeDir.--dataPathoverride.~/.candyland/under the user profile.db/to Detritus.gitignore.db/already created in the Detritus repo../db/data../db/dataexists in the launch cwd, move it to~/.candyland/dbon startup. If no DB exists or migration fails, log andcontinue with a fresh DB. Never fail startup/update over this.
0.4 Pure-Go Install And Sidecar Management In Detritus
release binary, place it, and register it.
install.shandinstall.ps1.ownership.
.exe(observed:
candyland --updatefails with "rename … Access is denied" whilethe sidecar runs). Detritus-owned update must stop the sidecar first, or use
the rename-aside-and-swap pattern Detritus already uses for its own
self-update.
0.5 Windows: No Flashing Console Windows On Any Spawn
internal/httpapi/system.goversion probes(
claude/git/gh --version, run on every/api/systempoll) throughthe windowless process config.
internal/conductor/git.gogit commands through the same helper.exec.Commandsites.configureProchelper across packages.per-session
control-mcpand per-agentcomms-mcp.internal/conductor/git.gospawns the actualgit/ghcommands (not just version probes) via plain
exec.CommandContext— routethese through the windowless helper too, not only the
--versioncalls.proc_windows.gokills only the directchild; Unix kills the whole process group (
syscall.Kill(-pid),proc_unix.go). With long-lived quest/campaign agents + pause/stop/resume,stop/cancelwill orphanclaude's grandchildren on Windows. Needs aWindows job-object or
taskkill /T. Gets worse at quest/campaign scale.0.6 Remove "Launch From Your Editor" UI And Dead Backend Code
Detritus/user sessions trigger them.
src/components/PlanningFlow.jsand related UI.creation or planning Q&A, including
/api/runs/{id}/questionsand wizardplumbing. Keep only the Detritus-triggered REST path.
0.7 Remove Developer/Non-Developer Split And
ModeEnd-To-EndModefields end-to-end.src/mode.js,src/components/ModeToggle.js, andmode branches in
App.js/ panels.Mode:internal/run/types.go,internal/conductor/planner.go, conductor mode assignments, andSpec.Mode./candyland.Phasesininternal/run/types.go, or renameit to "Partition" if the split is worth surfacing. Recommendation from the
existing backlog: drop it.
like
["Build", "Integrate", "Review", "PR"].internal/conductor/helpers.goandexecutor_claude.go; they currently indexPhasesby offset such aslen(run.Phases) - 2.0.8 Enforce Real Review Loop With Separate Review Agents
fix findings, and re-review until clean or bounded failure.
PR, and
ReviewinPhasesis not backed by reviewer agents.max-rounds mirroring
maxReplans/maxAttempts.review-rigor//gh-self-reviewstyle)rather than an ad-hoc inline rubric.
fixes, and the run only opens the PR once review is clean.
0.9 Reuse Authenticated
ghIn Candyland JobsFirm requirement (see 0.2a): every Candyland-spawned agent uses the same
authenticated
ghas the VSCode sessions and can open PRs in private repos.claude) spawns already inherit fullos.Environ()(claudeEnv(),resilience.go:26-32,143), and the detachedsidecar launch leaves
cmd.Envnil (control.go:92-94) so it inherits theparent env too —
detachSysProconly sets session/console flags and touchesno env. The "detached path drops env/HOME" hypothesis is refuted by the
code; do not chase it.
target private repo; (b) on Windows, whether
USERPROFILE/HOMEin thespawning context resolves to the profile
gh auth loginactually wrote to(credential-manager /
GH_CONFIG_DIRresolution).owns ensure-up/start (0.1), it must pass the gh credential context through to
the sidecar at launch (
GH_*/GITHUB_TOKEN,GH_CONFIG_DIR/~/.config/gh,HOME/USERPROFILE); agents then inherit it viaos.Environ(). This is thesame propagation tracked in 0.2a — keep them consistent.
repo in one real run.
0.10 Deterministic Replay / Test Harness
without burning tokens. The HTTP brief-stub kept in 0.2 (a process that fetches
its brief over HTTP and stands in for
claude) is the seed of one — formalizeit into a replay/regression harness so quest/campaign flows can be tested
without real model calls (no API budget; see local-only constraint).
0.11 Update README To Match Reality
in-UI planning.
claudeprocess per active agent.~/.candyland/.control-mcp,comms-mcpas a process,install.sh,install.ps1,"Launch from your editor" UI, developer/non-developer modes, and the
"Plan" phase.
the migration.
generated, so update source docs and regenerate.
Phase 1 - Preserve And Normalize Run Traces
Candyland already records much of what is needed inside each task run. Do not
invent a separate trace platform yet. First, normalize the local record shape so
it can later be centralized with low friction. Centralized learning is not part
of the near-term implementation.
Trace Contract By Level
Trace enough at each level to support local observability now and centralization
later without backfilling missing relationships.
Run trace:
runID, parentquestIDand/orcampaignIDwhen present.mode/type, created-by surface.
start/end timestamps, final state.
verification result, review status.
tool/test/review metadata, redacted text/log payload.
failure reason, cancellation reason.
Quest trace:
questID, optional parentcampaignID.verification command(s), stop/pause criteria.
items, launched runs, PRs, blockers, next action.
runID if accepted, final disposition.
pause reason, last progress.
Campaign trace:
campaignID.folders if known.
questions, dependencies, rough sizing, review routing suggestions.
split/deferred/blocked, and why.
campaign gate decisions.
Centralization constraint:
Store parent-child links and stable IDs from the start.
Keep traces local-first and exportable.
Redact or mark sensitive payloads before any future sync.
Do not build central storage, analytics, or platform-learning jobs yet.
Audit current run, agent, task, bus, and event schemas.
Define a stable local trace schema for each run:
intent, prompt/brief, folders/repos, agents, task graph, messages, tool
events, tests, review findings, retries, failures, PRs, timestamps, and
rough token/cost fields when available.
Ensure every agent event is tied to
runID,agentID,taskIDwhereapplicable, and a monotonic sequence.
Preserve original intent separately from generated plans/tasks so final
review can compare output against intent, not only against task completion.
Store PR/issue links as first-class trace artifacts.
Make local trace export possible, even if centralization is deferred.
Do not build a broad user-facing analytics/editing surface yet. Platform
improvement from trace data is a separate concern from everyday developer
use.
Phase 2 - Quest: Candyland Iterative Loop
A quest is a Candyland-native iterative loop. It is the generalized sidecar
homologue to
/janitor, but it is not constrained to maintenance. A quest canbe open-ended or finite, and it may produce several PRs over time.
Quest Roles
whether findings/tasks become work items. This is the technical overview role
for the quest level.
reference document, PR, or repo to identify the next work items.
actionable, and worth launching as a run.
item into agent tasks.
agents.
The quest lead decides whether to launch one run at a time or several parallel
runs. It should parallelize only when findings are independent enough that the
resulting PRs will not collide.
Quest Inputs
Examples:
Quest Lifecycle
Questmodel separate fromRun.It cascades into the existing run flow for each accepted work item/PR.
janitor" so the loop has a crisp objective, scope, iteration strategy,
safety boundary, and verification command.
/janitoras plan-gated setup even for in-session use: it shouldrefine loop intent before execution instead of jumping straight to generic
scheduled audit.
/janitorremains the in-session variant;/questisCandyland-native.
NOTE:
/janitoris currently the deliberately not plan-gated sibling of/smith(it jumps to the audit tick). Plan-gating it changes in-sessionbehavior and touches
core/loop/janitor.mddoctrine — track this as aseparate doctrine change, not bundled with the Candyland substrate work.
loop
kb_getscore/loop+core/todo-audit(parallelize-only-when-safe) +core/completion; reviewerskb_getcore/review-rigor. Do not re-encode in Go.(one per safe work item); a campaign-owned quest opens none (
deliver: branch).a spend cap; pause with a visible reason at the cap.
default goal is to minimize downtime between ticks and keep working until
stopped, blocked, or out of safe findings.
discover or select the next work item, triage safe work, launch one or
more build/check runs, review, open PRs or record compliance results,
update quest state, immediately continue when safe.
sequentially or in parallel, based on file/repo overlap, risk, and review
load.
same blocked item forever.
PRs, blockers, recent trace, and next action.
Detritus Surface
/questcommand in Detritus./questshould read Detritus KB guidance, refine intent, ensureCandyland is running, then call Candyland-owned quest APIs.
/janitordocs to either delegate to/questor clearly describeitself as the in-session/legacy variant.
duplicate quest state in scratchpads except as a launch handoff.
Phase 3 - Campaign: Intent-Driven Development Flow
A campaign is a program-level intent-to-delivery execution cycle. It can start
from a high-level goal, a partially formed brief, or a detailed implementation
plan. The distinguishing feature is not the input shape; it is that Candyland
owns the full execution cycle after launch: validation, decomposition,
implementation, review, and delivery.
Once launched, a campaign should not ask the user clarifying questions. If the
input is under-specified, contradictory, or becomes invalid mid-build, the
campaign routes that issue through its internal roles. Only a true hard blocker
pauses execution.
Campaign Roles
plans into the campaign record, collecting unresolved questions, and deciding
when the Intent Brief is ready for the campaign gate.
external context where allowed.
deployment, design, hardware, or other areas as needed/not needed with
reasons. This is a product/technical mapping role, not a human ownership
model.
what becomes a quest, what becomes a direct run, what can parallelize, and
what must wait.
flow.
on touched surfaces. It does not model those humans as agents.
generated task list.
Campaign Communication Flow
Communication is hierarchical and agent-directed. Peer agents do not negotiate
scope directly, and no role asks the user for clarification during execution.
Rules:
moves the campaign between stages.
context, assumptions, research, and role feedback; it does not ask the user.
parallelization across child quests/runs.
campaign tech lead or intent lead depending on whether they are technical or
definitional.
but does not contact the user or model humans as agents.
Campaign Lifecycle
Campaignmodel aboveQuestandRun.is a high-level goal, partial brief, or detailed plan.
restated goal, scope by domain, resolved/escalated questions, draft task
list, dependencies, rough sizing, and review-routing suggestions.
the campaign input before implementation planning proceeds.
proposed quests/runs would plausibly deliver the campaign input before
execution begins.
is too broad.
resolve what the campaign input means. This escalates to the intent lead
or campaign supervisor, not to the user.
original box: redefine, split, or add resources inside the campaign flow.
Candyland runs. Persistent or exploratory streams become quests; finite
scoped delivery items can become direct runs.
child quests/runs, based on repo/file overlap, dependencies, risk, and
review load.
and trace records.
multiple repos, but each repo should have a single campaign PR so agents
and human reviewers can track the campaign coherently.
modeling domain reviewers as agents.
named).
core/review-rigorcovers code mechanics, not intent-satisfaction.Define a concrete, reproducible method for "did we build what was meant":
e.g. the intent reviewer reads the immutable original input + Intent Brief, then
checks each brief commitment against the shipped diff/PRs and produces a
satisfied/partial/missed verdict per commitment with evidence — not a vibe check.
Without a method this gate is not reproducible.
cap across all child quests/runs and a pre-launch cost estimate; it pauses at the
cap with a visible reason rather than spawning unboundedly.
per-repo campaign branch (no child PRs); the campaign opens one PR per repo at
the gate after intent review. Agents handle blockers to completion (resolve or
escalate within the hierarchy); a blocker does not abandon delivery, and the
per-repo branch persists across a pause for resume.
Detritus Surface
/campaigncommand in Detritus./campaignshould launch the Candyland campaign flow directly from ahigh-level instruction, partial brief, or detailed plan. It should ensure
Candyland is running and call Candyland-owned campaign APIs. It should not
require a prior
/plan./vibedistinct from/campaign./vibeis an in-session flowthat does not use the Candyland multi-agent loop.
/campaignis aCandyland-run program-level execution flow. They may share doctrine, but
one should not be described as a simple legacy/delegating form of the
other.
Phase 4 - Centralization Readiness Only
Do not implement centralized learning data yet. This phase is only about making
local traces easy to centralize later with minimal migration friction.
Developers should not need to understand or edit platform traces to use
Detritus/Candyland.
depend on a central store.
improvement workflows.
langchain's "Loop 4 / hill climbing" — an analysis agent reads production
traces, spots systematic failure patterns across runs, and proposes
prompt/tool/rubric adjustments, making the inner loops better over time. We do
NOT build it now (no API budget; local-only). But design the Phase 1 trace
contract — stable IDs, parent-child links, per-finding verdicts — so this loop
can later consume traces with zero backfill. That is the reason the trace shape
is first-class now.
Phase 5 - Documentation And Command Cleanup
Do this after substrate changes land, not before.
docs/flows/build/candyland.mdto describe the finallifecycle-owned sidecar.
docs/flows/build/quest.md.docs/flows/build/campaign.mdordocs/flows/plan/campaign.md;choose location based on whether the command is framed as build or intake.
detritus --readme && detritus --plugin-commands.go generate ./...after KB docs change.go test ./...in Detritus.campaigns, local traces, review phase, and Detritus-managed lifecycle.
Phase 6 - Candyland UI Hierarchy
The UI should expose the hierarchy without hiding the atomic run/task history.
Users should be able to inspect work at the level they care about and pivot
between levels.
than separate top-level history pages.
section.
outside any quest or campaign.
no parent, campaign, quest, repo/folder, status, PR state, date, and text.
items, child runs, PRs, blockers, and next action.
quests/runs, PRs, blockers, review routing, and final intent review.
losing filters.
but no broad trace editing.
Phase 7 - Candyland Quest/Campaign APIs
Candyland owns the quest/campaign/run APIs. Detritus should only ensure the
sidecar is running and call these APIs as a client.
Quest API outline:
POST /api/questscreates a quest.POST /api/quests/{id}/beginstarts or continues quest execution.GET /api/quests/{id}returns quest status and rollup state.POST /api/quests/{id}/pausepauses future ticks without deleting state.POST /api/quests/{id}/resumeresumes a paused quest.POST /api/quests/{id}/stopstops the quest and marks the reason.GET /api/quests/{id}/runslists child runs.GET /api/quests/{id}/findingslists findings/work items.Campaign API outline:
POST /api/campaignscreates a campaign.POST /api/campaigns/{id}/beginstarts or continues campaign execution.GET /api/campaigns/{id}returns campaign status and rollup state.POST /api/campaigns/{id}/pausepauses future execution without deletingstate.
POST /api/campaigns/{id}/resumeresumes a paused campaign.POST /api/campaigns/{id}/stopstops the campaign and marks the reason.GET /api/campaigns/{id}/questslists child quests.GET /api/campaigns/{id}/runslists direct and quest-child runs.Suggested First Implementation Order
Questdata model and dashboard view./questDetritus command and Candyland quest launch endpoint.Campaignmodel and Intent Brief generation./campaignDetritus command that launches Candyland campaigns.?? Generated with Claude Code