Planner-E — Conversational Intake and Decomposition
Planner-E — Conversational Intake and Decomposition
Section titled “Planner-E — Conversational Intake and Decomposition”!!! abstract “TL;DR”
Planner-E is the rig’s front door. Humans don’t file issues — they open a Discord thread in #planner and have a conversation. Planner asks the questions that matter, holds the thread state across messages and across days, and only when the plan has converged does it produce GitHub artifacts: an epic plus child issues across the right repos, with TaskSpecs, tier classification, and dependency ordering. The interface is conversational because planning is the activity that benefits most from being phone-friendly. The output is structured because Dev-E and Review-E need a contract.
Planner-E sits between Trust Model (which decides what the rig may attempt) and Quality & Evaluation (which decides whether the rig succeeded). It is the layer that turns a 20-second voice message in bed into a 250-line plan that Dev-E can execute without supervision.
Problem statement
Section titled “Problem statement”The rig already executes issues well. Coffee.dashecorp.com (rig-docs#247, dashecorp/coffee#1-31, shipped end-to-end 2026-04-28 → 04-29) demonstrates the loop works: Dev-E picks issues, opens PRs, Review-E reviews, auto-merge fires, Cloudflare Pages deploys. Nineteen PRs, zero operator touches on code.
But the inputs were hand-authored. The user wrote a 250-line epic in rig-docs#247 and nine milestone issues with detailed acceptance criteria, then sat down and waited. The autonomous loop’s bottleneck is not execution — it is the cost of producing input good enough to feed it.
Three sub-problems compound:
- Vague issues fail. Dev-E faced with “build a coffee site” produces something. It will not be the right thing. Review-E will reject it. The cycle wastes turns and money.
- Decomposition is hard. Real work spans repos and milestones. Coffee’s M9 had to be retro-split into M9.1-M9.5 mid-stream because the human plan oversized it. A novice planner will make the same mistake at scale.
- Planning happens off-keyboard. You think about new ideas while walking, in bed, in line. Asking a human to write 250 lines of structured markdown on a phone is a bad interface for the activity.
Planner-E exists because the right answer to all three is the same: make planning a conversation, not an artifact.
Design principles
Section titled “Design principles”Planner-E follows the ten whitepaper principles with three additions specific to its role:
- Conversation is the unit of work, not the issue. Each Discord thread = one planning session = one epic-in-progress. The thread is the scratch pad; the issues are the deliverable. Issues are output, never input.
- Refinement before commitment. Open questions are resolved in the thread, before any GitHub artifact exists. By the time Dev-E sees an issue, every “what about X?” has already been answered.
- The conversation produces decisions; decisions become memory. What you agreed to in this thread should not be re-asked next thread. The agent learns conventions from real conversations, not from a style guide nobody updates.
The interaction model
Section titled “The interaction model”Trigger: a thread in #planner
Section titled “Trigger: a thread in #planner”The human opens a thread in the #planner Discord channel. The opening message can be anything — a sentence, a paragraph, a voice-to-text transcription. Planner-E is subscribed to #planner and treats every new top-level message as a planning request. It opens a thread reply if the user did not, and the thread becomes the conversation surface from that moment forward.
The runtime trigger flow:
Human posts in #planner ↓Discord webhook → rig-conductor ↓LPUSH signal:rig-planner { threadId, channelId, openingMessage } ↓KEDA scales rig-planner pod 0 → 1 ↓Planner-E reads thread, posts first replyConversation: ask the questions that matter
Section titled “Conversation: ask the questions that matter”Planner-E reads the opening message and asks for whatever is genuinely missing. It does not run a fixed questionnaire — that would be brittle and annoying. It asks only what it cannot infer from context, BRAIN.md, or memory.
For “build me a coffee site” against an empty repo, that means: what’s the data source? what’s the deploy target? is this a public showcase or internal? do you want auth/journaling? is there a deadline?
For “add a bean detail page to coffee.dashecorp.com” against an existing repo, it means: which fields surface? do you want filtering on the detail page or just display? how should it route from the list view? — questions that require knowing the existing app, which Planner-E learns by shallow-cloning the repo and reading the route structure.
The conversation is iterative: human replies → Planner integrates the answer → asks the next question or proposes structure. There is no fixed number of turns. A trivial ask might converge in two messages; an epic might take twenty across three days. The thread is persistent — Planner reads its own previous messages on each wake-up and resumes naturally.
Convergence: the human says “ok, file it”
Section titled “Convergence: the human says “ok, file it””Planner-E does not file issues until the human approves. The standard convergence pattern is:
- Planner posts a draft plan in the thread (epic outline + milestone list with one-line summaries + repo routing + dependency arrows).
- Human reads, asks for changes (“M5 should come before M4,” “drop the timer for now,” “add a journal export”).
- Planner revises the draft inline.
- Human says “ok, file it” (or equivalent — “go”, “ship it”, “do it”).
- Planner files the GitHub artifacts and posts back a summary with links.
The “approve before file” gate is non-negotiable. Filing issues is a partly-irreversible action — closing them later leaves noise in the repo. The thread is reversible until the issues exist.
Output: the GitHub artifact bundle
Section titled “Output: the GitHub artifact bundle”When approved, Planner-E creates in one batch:
- One epic issue in the appropriate tracking repo (typically
dashecorp/rig-docs). Body contains: vision, architecture decisions made in the thread, milestone list withCloseslinks to children, out-of-scope notes. - N child issues in the target repos, each with a full TaskSpec (see schema below). Each child links back to the epic via
Depends on dashecorp/rig-docs#<epic>. - Dependency wiring: where M2 depends on M1, the M2 body includes
Depends on #<M1>. The conductor’sDispatchUnblockedIssuesAsyncreads these to build a DAG and dispatches in the right order. - Tier labels on each child:
tier:t1,tier:t2, ortier:t3. Independent milestones marked parallel with aparallellabel or sharedwave:Nlabel. agent-readylabels on T1 children — they’re cleared for Dev-E pickup. T2 children getagent-readyonly after open questions are answered. T3 children stayneeds-approvaluntil a human signs off in the issue.
Planner-E posts one summary message back in the thread:
✅ Filed. Epic:
rig-docs#250. Children:coffee#1-9. Order: M1 → M2 → M3 → M4-M5 (parallel) → M6 → M7-M8 (parallel) → M9. M3 istier:t2(touches the data layer) and waiting on your answer about the CQI license question. Everything else isagent-ready.
The human sees one notification, glances at the summary, walks away. Dev-E picks up M1 within five minutes.
The TaskSpec schema
Section titled “The TaskSpec schema”Every child issue body follows a fixed shape. This is the contract between Planner-E and Dev-E.
## TaskSpec
**Goal:** One sentence — what this change achieves and why.
**Tier:** T1 (reversible) | T2 (schema/data) | T3 (irreversible)
**Acceptance criteria:**- [ ] Criterion 1 — testable, verifiable by CI or a human- [ ] Criterion 2
**Scope:**- Files/components: `path/to/file`, `src/component/`- Repos affected: `dashecorp/repo-name`
**Out of scope:**- Anything explicitly ruled out in the thread
**Open questions:** (T1: should be empty; T2/T3: must be empty before agent-ready)- (none)
**Depends on:** #N, #MThe schema is the same for an epic and a child, with two additions on the epic: a Decomposition: section listing children, and a Dependency graph: mermaid block.
A runtime validator parses Planner-E’s output before it’s posted. If any required field is missing or malformed, the runtime rejects the post and Planner retries (max 2 retries). This is fail closed — better to surface “Planner couldn’t produce a clean spec” than to ship a broken one.
Tier classification
Section titled “Tier classification”Tier is the safety valve. Planner-E classifies during the conversation, not after. The rules:
| Tier | Meaning | Examples | What Planner does |
|---|---|---|---|
| T1 | Reversible — features, UI, docs, config | Add a route, edit a doc, tweak Tailwind, refactor a function | File issue, set tier:t1, set agent-ready, Dev-E picks up |
| T2 | Schema/data — structurally significant but recoverable | DB migration, data layer change, breaking internal API, dependency major bump | File issue, set tier:t2, set agent-ready only after decomposition is complete and open questions answered |
| T3 | Irreversible — destructive infra, credential rotation, public API break | Drop a table, rename a GCS state bucket, force-push main, public SDK break | File issue, set tier:t3, set needs-approval, comment @stig-johnny needs approval, ping #admin. Never set agent-ready |
Tier is decided in the thread, not after the issue exists. If during the conversation Planner notices a T3 element (“this requires rotating the conductor’s GitHub App PEM”), it surfaces it then: “Heads up — this needs a credential rotation, that’s T3 and stays human-gated. Want me to file it as a separate child so the rest can run autonomously?” The human decides scope before the issues exist.
This is the reversible-before-irreversible principle applied at intake. An agent can undo what an agent did. Humans gate anything that cannot be undone.
Memory and learning
Section titled “Memory and learning”Planner-E reads three kinds of context on every wake-up:
- Thread history — the full Discord thread, scrollback included. This is the working memory for the active session.
- Repo memory —
read_memories(repo=<target>)returns prior decisions, learnings, and gotchas tagged to that repo. If you decided last month “we use Cloudflare Pages, not Vercel, for static sites in dashecorp,” Planner reads that and proposes Pages without re-asking. - Org memory —
read_memories(scope="org")returns conventions: branch naming, conventional-commits rules, frontmatter requirements, theCloses #Nmandate from CLAUDE.md.
After each filed epic, Planner writes back:
- Decisions (“we chose SvelteKit + adapter-static for coffee, reason: matches the rig’s static-site stack and CI is already wired”). Tagged
kind=decision, repo=dashecorp/coffee. - Patterns (“user prefers M-numbered milestones with one acceptance bullet group per milestone”). Tagged
kind=learning, scope=org. - Anti-patterns when something didn’t work and we corrected mid-thread (“first plan had M9 as a single mega-issue, user split it — keep mega-milestones decomposed”).
The next thread starts further along. Over time, Planner converges on the user’s conventions without explicit training.
This is the Memory chapter applied to planning. Memory is what differentiates the second conversation from the first.
Cross-repo awareness
Section titled “Cross-repo awareness”Real work in dashecorp spans repos. Coffee’s actual scope was:
dashecorp/infra#186— provision the new repo (T2, human-bootstrapped)dashecorp/rig-docs#247— epic trackingdashecorp/coffee#1-9— implementation milestones
Planner-E owns this routing. It reads BRAIN.md to know which repo owns what concern (rig-docs = tracking + ADRs, infra = OpenTofu IaC, rig-gitops = HelmReleases, etc.) and emits the cross-repo issue map up front. Dev-E should never discover a cross-repo dependency mid-implementation — Planner already wired it.
The rule of thumb encoded in the persona:
| Concern | Repo |
|---|---|
| Cross-cutting epic, ADR, research note | dashecorp/rig-docs |
| OpenTofu infra, GCP, Cloudflare, Tailscale, GitHub repo settings | dashecorp/infra |
| Helm releases, k8s manifests, SOPS secrets | dashecorp/rig-gitops |
| Agent persona, runtime, provider | dashecorp/rig-agent-runtime |
| Conductor logic, events, projections | dashecorp/rig-conductor |
| Application code | the application’s own repo (coffee, fast-e, nutri-e, …) |
Planner-E uses BRAIN.md as the live source of truth — when a new repo is added to the rig, BRAIN.md updates, and Planner picks up the new routing without retraining.
What Planner-E deliberately cannot do
Section titled “What Planner-E deliberately cannot do”Planner-E is the Spec-E + Architect-E hybrid persona. It is not an executor. The runtime denies these capabilities at the shell level — even if the model attempted them, the calls would fail:
| Capability | Why denied |
|---|---|
git push, branch creation | Planner does not write code. Code = Dev-E’s job. |
gh pr create, gh pr merge | Planner produces issues, never PRs. |
Filesystem writes outside /tmp/<scratch> | Planner reads repos but does not modify them. |
| Secret access | Planner has no business reading secrets. |
gh api PATCH on repo settings | Per CLAUDE.md absolute rule — repo settings via OpenTofu only. |
| Closing an existing issue | Issues are state; closing them is Dev-E + Review-E’s domain. Planner can comment and link, never close. |
Adding agent-ready to a T3 issue | Hard-coded in the runtime — even if the prompt told it to, the label-add call to /api/labels/add would reject for tier:t3. |
The capability surface is small on purpose. The fewer things Planner can do wrong, the more confidently the rest of the rig can trust its output.
Fallback path: issues filed without a thread
Section titled “Fallback path: issues filed without a thread”Sometimes humans (or external bots) file an issue directly without going through #planner. Coffee#1-9 were authored this way before Planner-E existed. After Planner ships, the fallback handler is:
- Issue lands without
agent-readylabel. - rig-conductor’s webhook handler signals Planner via
signal:rig-plannerwith{ source: "webhook", issueRef }instead of{ source: "discord", threadId }. - Planner reads the issue body, posts a comment: “Let’s discuss this — I’ve opened a thread in #planner: ”, and creates a thread linked to the issue.
- Conversation moves to Discord. When the thread converges, Planner edits the original issue body to insert the TaskSpec (instead of filing a new one) and adds the right tier label.
This is the secondary path. The primary path is always Discord-first. Issues are output, not input.
Validation: the coffee regression test
Section titled “Validation: the coffee regression test”The bar for shipping Planner-E is a single empirical test:
Open
#planner. Type: “I want to build a tea brewing companion site, similar style to coffee.dashecorp.com.” Have a 5-message conversation answering whatever Planner asks. Approve. Walk away.
Success criteria:
- Epic filed in
dashecorp/rig-docswith vision, architecture, decomposition list - 8-12 child issues filed in the right repo (a new
dashecorp/teaif it exists; otherwise a tracking issue in rig-docs noting the missing repo and pinging #admin) - Tier labels applied correctly — repo-creation child is T2, content milestones are T1
- Dependency ordering matches what a human would write (data layer before UI, scaffold before features)
- At least one independent-pair marked parallel
- The full set passes ≥70% shape-match against the hand-written
rig-docs#247+coffee#1-9(manual diff in PR review) - Total operator time: ≤5 minutes of conversation, zero markdown writing
The coffee project becomes the regression corpus: any change to Planner-E’s persona or schema is re-evaluated against “would this still produce something at least as good as what we wrote by hand for coffee?”
Failure modes and how Planner handles them
Section titled “Failure modes and how Planner handles them”| Failure | Planner’s response |
|---|---|
| Human asks for something genuinely irreversible (drop prod DB) | Refuse to file as agent-ready. Mark T3, comment in thread “this stays human-driven, here’s the runbook outline as a doc PR instead” |
| Conversation drifts into a different idea | Ask: “this feels like a separate thread — should I close this one and you start fresh?” |
| Human disappears mid-thread | After 7 days of no activity, post: “Closing this thread out — start a fresh one when you’re ready.” Do not file partial epics. |
| Output validator rejects the TaskSpec twice | Post in thread: “I can’t produce a clean spec — here’s what I’m stuck on. Can you clarify Goal and Acceptance for M3?” Stop. Do not retry blindly. |
| Cross-repo routing is ambiguous | Ask in thread: “this could live in rig-gitops or rig-agent-runtime — which feels right to you?” Don’t guess. |
| User asks for something the rig can’t do (deploy iOS to App Store autonomously) | Per CLAUDE.md forbidden actions — refuse. Comment: “this needs human approval at submission time, I can plan up to the build step but not the submit.” |
Failing closed is the rule. A bad plan is worse than no plan, because Dev-E will execute the bad plan.
Deployment
Section titled “Deployment”| Field | Value |
|---|---|
| Slug | rig-planner |
| Namespace | rig-planner |
| Image | rig-agent-runtime:node |
| GitHub App | rig-planner-bot (App ID 3546083, dashecorp install 128162238) |
| Discord bot | Application ID 1499108685777993788, channel #planner |
| KEDA signal | signal:rig-planner (Valkey list) |
| Min/max replicas | 0 / 1 (planner is single-writer per thread) |
| Provider | claude-cli |
| Model | claude-opus-4-7 (decomposition is the highest-reasoning task in the rig) |
| Temperature | 0.1 |
| MaxTurns | 30 (planner writes one comment per wake-up, then exits) |
| GitOps path | dashecorp/rig-gitops/apps/rig-planner/ |
Bootstrap is documented in dashecorp/infra/BOOTSTRAP.md step 19.
Open questions for v1
Section titled “Open questions for v1”- Multi-thread interleave. If a user has three active threads, does Planner-E read all three on each wake-up or only the one being replied to? Default v1: only the active thread. Multi-thread context is a v2 problem.
- Voice input. Discord supports voice messages; the runtime currently reads only text. Voice → text via Whisper is a v2 enhancement.
- Inline issue editing post-file. If the user changes their mind after Planner files, does Planner re-edit the issues or open a new thread? v1: human edits manually or asks Planner in a new thread. Auto-edit risks an infinite loop.
- Cross-org planning. Planner-E is dashecorp-only. If a user wants to plan work in
Stig-Johnny/*(legacy app repos), v1 declines and points to the consolidation epic. Multi-org is a v3 concern after the org consolidation lands.
Relationship to other whitepaper chapters
Section titled “Relationship to other whitepaper chapters”| Chapter | Relationship |
|---|---|
| Trust Model | Planner-E classifies tier; the trust model decides what each tier may attempt. |
| Safety | The runtime capability gate denying Planner write/push/merge is a Pillar-1 dangerous-command guard tuned for this persona. |
| Memory | Planner is the heaviest writer to repo-scoped decisions and patterns. |
| Quality & Evaluation | The coffee regression test is the eval harness for Planner. |
| Self-Healing | If Planner produces a bad TaskSpec and Review-E rejects the resulting PR, the failure surfaces in conductor metrics; a v2 self-correction loop could route the rejection back to Planner as a learning signal. |
| The Autonomous Engineering Rig | Planner is the Spec-E + Architect-E personas merged into one conversational agent. |
Roadmap
Section titled “Roadmap”v1 (current rollout, ~2 weeks) — issues dashecorp/rig-docs#248 (epic), dashecorp/rig-gitops#276 (HelmRelease), dashecorp/rig-agent-runtime#180 (persona + validator), dashecorp/rig-conductor#602 (webhook + Discord trigger), dashecorp/infra#192 (tier labels), dashecorp/infra#194 (bootstrap doc).
- Discord-thread trigger
- Single TaskSpec output
- T1/T2/T3 classification
- Cross-repo issue filing
- Repo + org memory read/write
- Coffee regression test as acceptance gate
v2 (post-validation) — multi-thread context, voice transcription, rejection-feedback learning loop, cross-org planning when org consolidation lands.
v3 (long-term) — Planner proposes ADR PRs for genuinely architectural decisions instead of just decomposing into implementation issues. The line between “decompose” and “design” blurs at scale; v3 makes Planner a co-author of the whitepaper itself.
Why this layer exists at all
Section titled “Why this layer exists at all”The autonomous loop without Planner-E works — coffee proved it. But it works only when the human spends an hour writing a 250-line plan first. The human-time cost is the bottleneck on rig throughput. Planner-E moves that hour from the human’s keyboard to a 5-minute Discord conversation that can happen on a phone in bed.
The rig’s value is not “AI writes code.” Reviews of the coffee shipping log show Dev-E + Review-E + auto-merge handled the implementation loop autonomously. The rig’s remaining cost is the planning loop — and Planner-E is the answer to that.
The day Planner-E is live and the coffee regression test passes is the day the rig stops being “an autonomous executor with a human planner” and starts being “an autonomous engineering team with a human product manager.” That is the substantive shift this layer enables.