e3d-pilot 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,660 @@
1
- # Temporary Holding Version
1
+ # e3d-pilot
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **Multi-model AI problem solving: independent answers → critique → convergence → human decision → execution → review → provenance.**
4
+
5
+ ![e3d-debate: independent AI models answer a question, critique each other across rounds, converge on a synthesis with consensus and named dissent, then hand off to a human decision, execution, and provenance](docs/images/debate-convergence.svg)
6
+
7
+ e3d-pilot is an open-source system for getting multiple AI models to work on the same problem instead of trusting a single model's answer — from a one-off question to a fully executed, human-gated software change.
8
+
9
+ It starts simply. Ask several configured models (Claude, Codex, Grok, Devin, or others you wire in) the same question. Let them answer independently, see and critique each other's positions, revise, expose real dissent, and converge on the strongest answer. That's `bin/e3d-debate` — a standalone tool, no repo or pipeline required.
10
+
11
+ Then e3d-pilot takes the same instinct further, into real software work: `discover → ideate → approve → draft → negotiate → execute → review → publish → outcome`. Every step is preserved in an append-only ledger, so the system (or a human, or a fresh AI session) can later reconstruct where an idea came from, which models or people influenced it, what it produced, and what happened afterward.
12
+
13
+ ## Try e3d-debate in 60 seconds
14
+
15
+ ```bash
16
+ git clone https://github.com/spacepacket1/e3d-pilot.git
17
+ cd e3d-pilot
18
+
19
+ bin/e3d-debate \
20
+ "Should e3d-pilot's provenance data be a graph, or is that over-engineering?" \
21
+ --providers claude,codex --rounds 3
22
+ ```
23
+
24
+ (Any `lib/providers/<name>` adapter can join — add `devin`/`grok-build`/others if you have them configured; `claude`/`codex` are the two most people trying this will already have.)
25
+
26
+ Round 1: every provider answers independently. Round 2+: each sees the others' prior-round positions and must defend, revise, rebut, or concede. The debate stops early if they genuinely converge; a synthesizer then reads the full transcript and reports a final answer, consensus, and any remaining dissent.
27
+
28
+ That question isn't hypothetical — it's a real debate we ran this way, condensed from the [full transcript](docs/debates/2026-09-07-e3d-graph-generalization/transcript.md):
29
+
30
+ ```text
31
+ QUESTION
32
+ Should the E3D 3D graph generalize into a standalone product, or should
33
+ e3d-pilot instrument its own provenance instead?
34
+
35
+ CLAUDE (round 3, the only one to formally reach "approved")
36
+ Don't create e3d-graph yet — build a confidence-annotated, domain-neutral
37
+ provenance emitter inside e3d-pilot, prove attribution questions are
38
+ answerable from the data alone, add a 2D lens only if they are, and extract
39
+ a public repo only on external pull or paid demand.
40
+
41
+ CODEX (round 3)
42
+ Build outcome-linked Pilot provenance first, then open-source a narrow
43
+ standalone viewer only if measured workflow value and external pull
44
+ justify extraction.
45
+
46
+ DEVIN (round 3)
47
+ Instrument Pilot with a domain-neutral provenance schema from day one; gate
48
+ public extraction on the internal experiment succeeding, not on indefinite
49
+ deferral.
50
+
51
+ GROK-BUILD (round 3)
52
+ Do not ship standalone e3d-graph; instrument Pilot provenance first and
53
+ treat visualization as a 2D lens inside E3D.
54
+
55
+ SYNTHESIS
56
+ Do not ship a standalone e3d-graph product. Instrument e3d-pilot now with
57
+ an append-only, domain-neutral, confidence-annotated provenance schema —
58
+ the ledger stays canonical, the graph is an index, not memory. Validate by
59
+ answering real attribution questions from the data alone before any UI.
60
+
61
+ DISSENT (reported, not hidden)
62
+ Devin and partly Codex would gate public extraction on the internal
63
+ experiment succeeding; Claude and Grok-build require external pull or paid
64
+ demand instead — a real, named disagreement the tool didn't paper over.
65
+ ```
66
+
67
+ **What happened next:** we built exactly that, then ran it against three real ideas in this repo's own history. All three came back "more useful than reading the raw ledger by hand" — and one of them caught a real error in the spec that proposed it. Later graph-intelligence queries were evaluated just as honestly: one clear win, two explicitly "no signal" because the real data was still too sparse — reported as-is, not oversold. That full arc (spec, dogfood results, the honest misses) is in [`docs/provenance-graph-experiment.md`](docs/provenance-graph-experiment.md) and [`docs/graph-intelligence-experiment.md`](docs/graph-intelligence-experiment.md).
68
+
69
+ **Experimental: the provenance graph.** e3d-pilot now derives structural relationships — ideas, actors, models, decisions, repos, commits, evidence, outcomes — from its own immutable event ledger. We're testing whether that graph reveals patterns that are genuinely hard to get from the raw ledger, not claiming it already does.
70
+
71
+ You don't need the rest of e3d-pilot to use `e3d-debate` on its own — see [e3d-debate](#e3d-debate-experimental) below for the full flag reference. Keep reading for the part that takes a debate's answer all the way to a shipped, reviewed, provenance-tracked change.
72
+
73
+ ## Use e3d-debate from GitHub Copilot (MCP)
74
+
75
+ `bin/e3d-mcp` is a zero-dependency [Model Context Protocol](https://modelcontextprotocol.io) server, so Copilot agent mode in VS Code (and any other MCP client: Claude Code, Cursor, ...) can ask for a multi-model second opinion mid-task.
76
+
77
+ Tools: `e3d_debate` (answer + consensus + named dissent + transcript), `e3d_list_providers`, and read-only `e3d_provenance_trace` / `e3d_ideas_list` ("why does this change exist?").
78
+
79
+ **Install (VS Code / Copilot agent mode):** [one-click install](https://insiders.vscode.dev/redirect/mcp/install?name=e3d-pilot&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22-p%22%2C%22e3d-pilot%22%2C%22e3d-mcp%22%5D%7D), or add this to `.vscode/mcp.json`:
80
+
81
+ ```json
82
+ {
83
+ "servers": {
84
+ "e3d-pilot": { "type": "stdio", "command": "npx", "args": ["-y", "-p", "e3d-pilot", "e3d-mcp"] }
85
+ }
86
+ }
87
+ ```
88
+
89
+ Prerequisites: Node 18+, `jq`, bash 4+ (macOS: `brew install bash jq`), and at least two model CLIs logged in (e.g. `claude` and `codex`). Check them all with `npx -y -p e3d-pilot e3d-mcp --doctor`. From a clone, `bin/e3d-mcp --print-config --local` prints a config pointing at your checkout.
90
+
91
+ Then, in Copilot agent mode: *"Before you pick a storage layer, run e3d_debate on SQLite vs flat JSON for this CLI."* To make Copilot do that unprompted for contestable design choices, copy [examples/copilot-instructions.md](examples/copilot-instructions.md) into `.github/copilot-instructions.md` or `AGENTS.md`.
92
+
93
+ Notes:
94
+ - Debates are slow (minutes) and spend **your** model credits. The server caps rounds/providers/concurrency: `E3D_MCP_MAX_ROUNDS` (3), `E3D_MCP_MAX_PROVIDERS` (4), `E3D_MCP_MAX_CONCURRENT` (2), `E3D_MCP_TIMEOUT_SEC` (900).
95
+ - It uses whatever provider CLIs/keys are in the server's environment (`claude`, `codex`, ... see `e3d-pilot providers list`). Needs at least two available.
96
+ - The Copilot *coding agent* runs on GitHub-hosted runners, where those provider CLIs are not installed; use the local (stdio) setup above for now.
97
+ - The server never writes to a repo. Recording a verdict into provenance is still `e3d-debate --repo --idea`.
98
+
99
+ ## Why we built this
100
+
101
+ Autonomous coding agents solved the *execution* half of the problem: point a good model at a good spec, and it will faithfully implement it. What's still missing is everything **before** that — noticing what's worth building, making sure it isn't a rehash of a closed PR or last week's abandoned branch, and getting more than one model to actually agree the plan is safe and sound before anything touches a working tree. Skip that half and you get agents that happily reimplement existing features, argue with themselves in a PR nobody asked for, or quietly blow through a repo's real diff budget.
102
+
103
+ e3d-pilot exists to be that missing half: a small, auditable layer that sits *above* e3d-code (formerly spec2code) rather than duplicating it. e3d-code stays the dumb, reliable phase executor — "run this spec." e3d-pilot's job is deciding what the spec should even be, proving it's worth doing, and refusing to let it run unsupervised past the point where a human needs to look.
104
+
105
+ The other reason: good ideas rarely come from staring harder at the same backlog. e3d-pilot's discover stage explicitly borrows from domains outside a repo's own category — a game's progression loop, a marketplace's liquidity trick, a social feed's notification mechanics — and its ideate stage grades every candidate on attraction and retention (does this bring people in, does it bring them back) with revenue treated as a secondary tiebreaker, never the deciding factor. The goal is features people actually want, not just the next item on an internal TODO list.
106
+
107
+ A third reason, less about any single run and more about what accumulates across many of them: a decision made once shouldn't have to be re-explained from scratch to the next session that picks the work back up. Every tracked idea's ledger record is a durable, cross-session target — `ideas context`/`ideas handoff` let a fresh Claude Code, ChatGPT, or Codex session read exactly what's already known about an idea (its decisions, its findings, its current state) instead of replaying a whole prior conversation, and `ideas note` lets that session write back what it just learned. The same instinct — don't trust a single pass of reasoning on a genuinely contested question — is why `e3d-debate` exists as a standalone tool: run any question through several models across rounds until they converge or leave a named, specific dissent, the same mechanism e3d-pilot's own negotiate stage already depends on internally, available for any decision, not just code changes.
108
+
109
+ ## What it does differently
110
+
111
+ - **Never repeats work.** Every idea is checked against the target repo's open branches, its PR history (open and closed), and every prior e3d-pilot run before it's allowed to proceed.
112
+ - **Never runs on one model's opinion.** The negotiate stage requires every configured reviewer — two today, more later, purely via config — to independently approve the same unchanged draft. Disagreement means bounded retries, then a clean "needs human" stop, not a forced merge.
113
+ - **Never treats absence of approval as approval.** Discovery and ideation can run unattended, but source-mutating stages require `ideas approve`, and base-branch merge requires `approve-merge` for the exact PR head SHA.
114
+ - **Never touches source before the first gate.** Execution happens in an isolated worktree on its own branch only after implementation approval. A path denylist and real post-execution diff ceilings are enforced before anything is reviewed or published.
115
+ - **Never merges a different revision.** Merge approval is separate from GitHub review approval and is bound to the observed PR URL, base branch, and head SHA. A pushed commit invalidates the approval until a human reviews and approves the new head.
116
+ - **Never assumes it's talking to spacepacket1's repos.** The entire contract with a target repository is one JSON config file. No fixed org, no fixed remote host, no `e3d-*` naming assumptions baked into the pipeline.
117
+ - **Never lets an idea's context evaporate between sessions.** `ideas note`/`ideas context`/`ideas handoff` give any AI session — not just e3d-pilot's own pipeline runs — a durable place to read and write what's been learned or decided about a tracked idea, independent of its lifecycle status.
118
+
119
+ ## How it can help others
120
+
121
+ If you maintain a repository and want a standing second opinion on "what should we build next" — one that does its homework before proposing anything, gets independent model consensus before acting, and hands you a draft PR with a full audit trail instead of a fait accompli — adopting e3d-pilot is meant to be a one-file decision: write `.e3d-pilot/config.json`, run it once to validate, then point it at your repo (or a whole fleet of them) on whatever cadence you choose (a cron entry, a scheduled job — e3d-pilot doesn't invent its own scheduler). It works identically on GitHub, on a remote-less local repo, and — architecturally, even before a forge adapter exists for it — on any other git host, because only the final publish step knows what forge it's talking to.
122
+
123
+ ## Pipeline
124
+
125
+ ![e3d-pilot's autonomous agentic loop: discover, ideate, draft, negotiate, execute, review, publish, orbiting a central autonomous pilot core, with gold safety gates before the diff-ceiling check and before publish](docs/images/agentic-loop.svg)
126
+
127
+ ```mermaid
128
+ flowchart LR
129
+ A[discover] --> B[ideate]
130
+ B -->|optional candidate_scoring| S[read-only ensemble]
131
+ S --> I[[proposed idea ledger]]
132
+ B -->|selected: none| STOP1((nothing to do))
133
+ I -->|ideas approve| C[draft]
134
+ I -->|ideas reject| STOPR((rejected))
135
+ C --> D[negotiate]
136
+ D -->|needs human| STOP2((stop for review))
137
+ D --> E[execute]
138
+ E -->|over ceiling| STOP2
139
+ E --> F[review]
140
+ F -->|verify failed| STOP3((blocked))
141
+ F --> G[publish]
142
+ G --> H[[implemented: draft PR / local branch]]
143
+ H -->|approve-merge for exact head SHA| M[merge]
144
+ M --> Z[[merged / partially_merged / merge_failed]]
145
+ ```
146
+
147
+ 1. **discover** — writes `findings.md`: Git history, branches, issues/PRs, existing docs and TODOs, plus a model-researched "External Context" section that includes an explicit cross-domain "Analogous Patterns" subsection (see [Ideation sourcing](#ideation-sourcing-and-scoring) below).
148
+ 2. **ideate** — writes ranked, deduplicated `candidates.md` and materializes every non-duplicate candidate as a `proposed` idea. `selected: none` is a valid, clean stop when everything proposed is already covered. If `candidate_scoring` is configured, an ensemble of read-only workers re-ranks non-duplicate candidates before materialization; the original model pick is stored as `model_selected`.
149
+ 3. **approval gate 1** — a human approves or rejects the exact idea. `proposed` never means rejected, and no source-mutating stage can run without current implementation approval.
150
+ 4. **draft** — turns the approved candidate into an e3d-code-shaped `spec-draft.md`, with machine-readable `pilot:touches` annotations per phase so later guards can check real paths instead of guessing from prose.
151
+ 5. **negotiate** — every configured reviewer must approve the same unchanged draft in one pass; disagreement drives bounded revision rounds, ending in `spec-final.md` on success or a clean "needs human" stop.
152
+ 6. **execute** — hands `spec-final.md` to the configured execute backend inside an isolated worktree on its own branch, then enforces `protected_paths` and the real post-execution `max_diff_files`/`max_diff_lines` ceilings. The default backend is e3d-code (formerly spec2code). `providers.execute: "grok-build"` is an experimental alternative that still uses the same worktree, ceilings, review, and draft-PR path.
153
+ 7. **review** — runs (or auto-detects) verification commands and asks an independent review provider to inspect the actual diff.
154
+ 8. **publish** — only after verification passes: commits the run's audit artifacts to the branch and hands off to a publish backend (`github` or `local`) to open a draft PR or leave a local review branch.
155
+ 9. **approval gate 2** — a human runs `approve-merge` after reviewing the draft PR/local branch. For GitHub targets, e3d-pilot records the current PR head SHA and refuses to merge any later head without a new approval.
156
+
157
+ Generated run artifacts live under `.e3d-pilot/runs/<run-id>/` in the *target* repository. Idea ledger state lives under `.e3d-pilot/ideas/<idea-id>/idea.json`, with append-only events in `.e3d-pilot/events.jsonl`. `idea.json` is derived from events and can be rebuilt; `events.jsonl` is the immutable audit source. `discover` and `all` without `--run-id` start a new, collision-safe run-id and update `.e3d-pilot/latest-run`; every other stage resumes that latest run-id unless you pass `--run-id <id>` explicitly. Create `.e3d-pilot/paused` in a target repo to stop stages before any external work happens.
158
+
159
+ ## Ideation sourcing and scoring
160
+
161
+ Discover's model call doesn't just summarize "state of the art" — it's asked to pick the 2-3 most transferable entries from a configurable `analogy_domains` list (or a sensible built-in default spanning games, social platforms, marketplaces, dev tools, and fintech) and name, concretely, how each mechanic could apply to *this* repo.
162
+
163
+ Ideate then scores every non-duplicate candidate on `Attraction` and `Retention` (1-5 each), tags a `Category` (data, workflow, social, gamification, testing, marketing, selling, or other), cites the `Analogy` it drew on, and estimates `Effort`. Ranking is driven primarily by `Attraction + Retention`; an optional `Revenue` score can only break ties between otherwise-equal candidates — it can never outrank a candidate that attracts or retains users better. That priority order is deliberate: growing and keeping users is the point, revenue is a secondary outcome of doing that well.
164
+
165
+ ### Semantic duplicate detection (Jev, optional)
166
+
167
+ Exact-duplicate candidates are already caught by hashing the proposal (`ideas_find_duplicate_by_digest`) before materialization. Separately, if `TYPESAFE_API_KEY` is set, every newly materialized idea is checked against the other live ideas in the same ledger via Jev (TypeSafe's System One Choice API) for a *semantic* duplicate — same underlying gap, different wording — that hashing can't catch. This runs automatically on every `ideas ingest`/propose call; no config flag turns it on beyond the credential being present, and its absence is a silent no-op, not an error.
168
+
169
+ It is shadow-mode and advisory-only: a match never blocks ingest or changes the candidate, it only appends a finding note ("possible semantic duplicate of `<idea-id>`, confidence `<level>` — does not block this idea") for a human to read during review. It stays advisory until a real calibration sample validates Jev's false-positive rate on this specific judgment (see `idea-980bf5b4df6b` / `idea-82a5c2225266`). See `lib/ideas/jev_dedup.sh`.
170
+
171
+ ### Optional ensemble scoring
172
+
173
+ After the ideate provider writes candidates, an optional `candidate_scoring` block can re-rank them with 3–5 independent read-only workers before ideas are materialized. The original model pick is stored as `model_selected`; `selected` becomes the ensemble winner among non-duplicate candidates. Scoring never executes, publishes, or approves — the two human gates still apply.
174
+
175
+ Any `lib/providers` adapter can be the scoring provider. `grok-build` is one option, intended as a cheaper fan-out in front of frontier negotiate and e3d-code execute:
176
+
177
+ ```json
178
+ "candidate_scoring": {
179
+ "provider": "grok-build",
180
+ "workers": 3
181
+ }
182
+ ```
183
+
184
+ `workers` must be an integer from 3 to 5 (default 3). Artifacts land in the run directory as `ideate-scoring.json`, `ideate-response.model.md`, and per-worker prompts/stdout under `ideate-scoring.artifacts/`. Fleet discover uses the same block in `.e3d-pilot-fleet/config.json`, writing `fleet-ideate-scoring.json`. Each idea record stores the ensemble average as `scores.ensemble` when scoring ran; that field is not part of the approval digest.
185
+
186
+ ### Revenue-focused runs
187
+
188
+ Pass `--focus revenue` to `e3d-pilot run` (any stage) to flip that priority for a dedicated pass: `discover` adds a `### Monetization Signals` subsection (existing monetization mechanisms in the repo, plus 2-3 adjacent-industry models that could extend them), and `ideate` ranks candidates by `Revenue` first — `Attraction`/`Retention` only break ties, and `Revenue` becomes a required numeric field instead of an optional tiebreaker. Candidates may be net-new monetization surfaces, not just extensions of existing features; duplicate-checking still applies equally either way.
189
+
190
+ Focus is resolved once per run and persisted to `.e3d-pilot/runs/<run-id>/focus`, so a later stage of the same run (e.g. a standalone `--stage ideate` invocation after `discover` already ran) inherits it automatically unless `--focus` is passed again explicitly, which overwrites it. Default behavior (`--focus default`, i.e. attraction/retention-first) is unchanged.
191
+
192
+ ## Fleet live operations
193
+
194
+ Fleet discovery can surface two read-only operational signals from optional `.e3d-pilot-fleet/config.json` fields:
195
+
196
+ - `live_instances`: an array of objects with exactly `name` and `url`. `name` must be a non-empty display string. `url` must be a non-empty `http://` or `https://` URL with a non-empty authority and no userinfo. The collector makes exactly one `GET` request per instance, follows at most one redirect, caps each request at 10 seconds, allows only HTTP/HTTPS on initial and redirected requests, and never retries.
197
+ - Live classification is deterministic: `healthy` means HTTP 200 at or below 1500 ms; `degraded` means HTTP 200 above 1500 ms or any other 2xx/3xx response; `down` means curl failure, invalid elapsed/status output, or any non-200-399 status, including 000, 1xx, 4xx, 5xx, and 6xx-9xx.
198
+ - `social_accounts`: an array of objects with exactly `platform`, `name`, `channel_id`, and `bot_user_id`. `platform` must be the string `discord`. `bot_user_id` is a public exact-authorship identifier, not a credential. Discord collection reads `DISCORD_BOT_TOKEN` from the environment, makes exactly one messages request per credentialed account, and makes zero requests when the token is missing or empty.
199
+ - Discord collection is read-only and uses `GET https://discord.com/api/v10/channels/{channel_id}/messages?limit=50` with no retries. It distinguishes `no recent messages found`, zero-engagement messages, and collection failures. Reactions are summed only for messages whose `author.id` exactly matches `bot_user_id`.
200
+ - `## Live Operations` is appended only when at least one of those arrays is non-empty. `### Live Instance Status` appears first whenever the section is present; if there are no live instances but Discord is configured, it says `No live instances configured.` `### Social Engagement` appears only when `social_accounts` is non-empty.
201
+ - `### Operational Recommendations` is included only for degraded/down live instances and Discord zero-engagement or collection-failure bullets, in configuration order. It repeats the exact observed state and does not guess a cause. Healthy instances, nonzero Discord engagement, and `no recent messages found` do not get recommendations.
202
+ - Moltbook support is planned as a later sibling branch.
203
+ - Keep credentials out of fleet config; only `DISCORD_BOT_TOKEN` belongs in the runtime environment.
204
+
205
+ Start from [`examples/sample-fleet-config-with-ops.json`](examples/sample-fleet-config-with-ops.json) if you want a ready-made fleet config with fictional `.example.com` live instances and a fictional Discord account.
206
+
207
+ ## Requirements and installation
208
+
209
+ Install Bash, Git, `jq`, and `curl`; the full pipeline's execute stage also needs [`e3d-code`](https://github.com/spacepacket1/e3d-code) (formerly `spec2code`; the debate and MCP tools do not). Install and authenticate whichever model CLIs and forge CLI your configuration uses (`claude`, `codex`, `devin`, a local OpenAI-compatible endpoint, and/or `grok` for `grok-build`). Add this repository's `bin` directory to `PATH`:
210
+
211
+ ```bash
212
+ git clone https://github.com/spacepacket1/e3d-pilot.git
213
+ export PATH="$PWD/e3d-pilot/bin:$PATH"
214
+ e3d-pilot --help
215
+ ```
216
+
217
+ Node.js is only needed for the optional `e3d-pilot web` dashboard (see [Web UI](#web-ui-optional) below) — every other command needs only Bash, Git, `jq`, and `curl`.
218
+
219
+ ## Configure a repository
220
+
221
+ Create `.e3d-pilot/config.json` in the target repository. Start from [`examples/sample-config.json`](examples/sample-config.json). The fields are:
222
+
223
+ - `verify`: commands run in the execution worktree before publish. An empty list is auto-detected from `package.json`, `requirements.txt`, or `Makefile`.
224
+ - `protected_paths`: globs that generated specs and execute-time guards reject.
225
+ - `research_topics`: hints for discovery research.
226
+ - `analogy_domains`: optional cross-domain seed list for discovery's analogy pass (see above); falls back to a built-in default when omitted.
227
+ - `providers`: provider names for `discover`, `ideate`, `draft`, ordered
228
+ `negotiate` reviewers, independent `review`, and optional `execute` (`e3d-code` by
229
+ default, or experimental `grok-build`). `discover`, `ideate`, `negotiate`,
230
+ and `review` may be a string or an array of provider names; when an array is
231
+ set, every listed model runs (discover/review concatenate their output;
232
+ ideate merges candidates; negotiate still requires one unchanged-draft
233
+ consensus pass). `draft` remains a single provider. `grok-build` is a normal
234
+ adapter: put it in the same fields you would use for `claude`, `codex`,
235
+ `devin`, or `local`.
236
+ - `candidate_scoring`: optional `{ "provider": "grok-build", "workers": 3 }`.
237
+ After ideate proposes candidates, 3–5 independent read-only workers re-rank
238
+ them. `provider` is any `lib/providers` adapter; `grok-build` is one option.
239
+ Scoring never executes, publishes, or approves. Omitted means no scoring.
240
+ - `max_diff_files` and `max_diff_lines`: actual post-execution ceilings.
241
+ - `docs`: optional guidance-document path; otherwise common filenames are detected.
242
+ - `live_verify`: optional `{ "command": "..." }` hook. It runs only when repository docs identify a supported E3D paid-API surface and `e3d-agent` is available; otherwise it is skipped.
243
+ - `pr`: `base_branch`, draft flag, labels, and backend (`auto`, `github`, or `local`).
244
+ - `notify`: optional `{ "email": { "to": "...", "command": "..." } }`. See [Notifications](#notifications).
245
+ - `approval`: optional `{ "implementation_required": bool, "merge_required": bool }`. Both default to `true`; see [Approval-gated operator workflow](#approval-gated-operator-workflow).
246
+ - `tracking`: optional `{ "project_url": "..." }`. Overrides `E3D_PILOT_TRACKING_PROJECT_URL` for this repo; see [Project board tracking](#project-board-tracking).
247
+
248
+ Validate and run:
249
+
250
+ ```bash
251
+ e3d-pilot config validate /path/to/repository
252
+ e3d-pilot run --repo /path/to/repository --stage all
253
+ ```
254
+
255
+ ## Approval-gated operator workflow
256
+
257
+ The default `run --stage all` discovers and ideates autonomously, materializes ideas, then stops before `draft` unless the selected idea already has current implementation approval. This is a successful waiting state, not a crash.
258
+
259
+ List and inspect proposed ideas:
260
+
261
+ ```bash
262
+ e3d-pilot ideas list --repo /path/to/repository --status proposed
263
+ e3d-pilot ideas show --repo /path/to/repository idea-abc123def456
264
+ ```
265
+
266
+ Approve or reject implementation:
267
+
268
+ ```bash
269
+ e3d-pilot ideas approve --repo /path/to/repository idea-abc123def456 --actor you@example.com --note "Build this next"
270
+ e3d-pilot ideas reject --repo /path/to/repository idea-abc123def456 --reason "Not aligned this cycle" --actor you@example.com
271
+ ```
272
+
273
+ `ideas approve` is the first gate. It authorizes drafting, negotiation, execution, review, and publication for the exact idea content and approved target plan. It is not a GitHub PR review, and it does not authorize merge.
274
+
275
+ Record findings and decisions on an idea, and pull them back out as compact context, independent of the idea's lifecycle status:
276
+
277
+ ```bash
278
+ e3d-pilot ideas note --repo /path/to/repository idea-abc123def456 "Discovered the API rate-limits at 50 req/min" --actor you@example.com
279
+ e3d-pilot ideas note --repo /path/to/repository idea-abc123def456 --decision "Ship the read-only slice first" --actor you@example.com
280
+ e3d-pilot ideas context --repo /path/to/repository idea-abc123def456 [--json]
281
+ e3d-pilot ideas handoff --repo /path/to/repository idea-abc123def456
282
+ ```
283
+
284
+ These exist to close one specific gap: nothing outside e3d-pilot's own pipeline invocations ever writes to `.e3d-pilot/`, so context discovered in an ad hoc Claude Code, ChatGPT, or Codex session about a tracked idea has nowhere durable to go. `ideas note` appends a freeform finding (or, with `--decision`, a decision) to the idea's existing ledger record via a pure self-loop event (`note_appended`) that never gates and is never gated by lifecycle status — it works on an idea in any state, including `proposed`, `implemented`, or `merged`. `ideas context` reads that idea back as a short summary plus its accumulated decisions and findings, separated. `ideas handoff` renders the same information as a compact packet (GOAL / STATUS / RELEVANT DECISIONS / RELATED CONTEXT / RECENT FINDINGS) sized to hand to a fresh model session instead of re-explaining everything from scratch. None of this adds a new schema or a new idea type — it's three thin verbs over the existing per-idea ledger.
285
+
286
+ ### Provenance export and trace experiment
287
+
288
+ The provenance commands derive a disposable graph or a single-idea trace directly from the same event ledger:
289
+
290
+ ```bash
291
+ e3d-pilot provenance export --repo /path/to/repository [--out /path/to/provenance.jsonl]
292
+ e3d-pilot provenance trace --repo /path/to/repository idea-abc123def456 [--json]
293
+ e3d-pilot fleet provenance export /path/to/fleet.json [--out /path/to/provenance.jsonl]
294
+ e3d-pilot fleet provenance trace /path/to/fleet.json idea-abc123def456 [--json]
295
+ ```
296
+
297
+ `provenance export` regenerates canonical nodes and edges, including the repositories a fleet idea proposed; `provenance trace` reads `events.jsonl` directly and separates decisions, findings, work Pilot produced, external commits it merely observed, outcomes, and failures. Add `--evidence <path-or-url>` to `ideas note` to retain a pointer to supporting material in repo-mode traces and exports without copying that material into the ledger. This is the deliberately UI-free experiment agreed in the e3d-graph debate: validate that the trace answers real attribution questions faster and more accurately than reading the ledger by hand before doing any visualization work.
298
+
299
+ Every `provenance export` also writes a sibling `<name>.manifest.json` (node/edge counts by type, orphan nodes, the highest-degree node, and a `graph_events_ratio` of derived graph size against source ledger size) — engineering telemetry to catch the graph quietly bloating or losing structure, not product analytics.
300
+
301
+ The fixed `provenance query` subcommands summarize idea-to-outcome `lineage`, repeated review `reversals`, implementation `failures`, and fleet-only `cross-repo` propagation; each supports `--json`, fleet mode uses `e3d-pilot fleet provenance query <name> /path/to/fleet.json`, and repo mode uses `e3d-pilot provenance query <name> --repo /path/to/repository` (where `cross-repo` intentionally returns an empty result).
302
+
303
+ A separate, standalone script — `bin/e3d-provenance-agreement --repo /path/to/repository` (same not-wired-into-the-subcommand-tree pattern as `e3d-debate`) — aggregates provider agreement across that repo's historical negotiate and review rounds under `.e3d-pilot/runs/`, reusing the existing `lib/negotiate/parse-status` and `lib/review/parse-verdict` parsers as subprocesses rather than re-deriving their contract. It prints JSON on stdout: each provider's negotiate approval rate, each provider-pair's agreement rate, and the specific disagreements (run ID, round, both providers' status and stated reason). Response files that predate the current format or fail to parse are skipped and counted separately, never counted as either agreement or disagreement.
304
+
305
+ Implement approved ideas:
306
+
307
+ ```bash
308
+ e3d-pilot ideas implement --repo /path/to/repository idea-abc123def456
309
+ e3d-pilot ideas implement-approved --repo /path/to/repository
310
+ ```
311
+
312
+ Successful implementation records the run ID, branch/worktree, changed files and lines, verification results, review result, publish backend, PR URL/number, and final PR head SHA. GitHub publication creates a draft PR; local publication leaves a local review branch and summary.
313
+
314
+ `ideas implement` always starts a brand-new run and redoes draft, negotiate, and execute from scratch on retry — including when only the last stage (typically publish, e.g. a forge label that didn't exist yet) failed on an otherwise fully verified and reviewed attempt. If a specific run already got that far, resume it in place instead of paying for another draft/negotiate/execute cycle:
315
+
316
+ ```bash
317
+ e3d-pilot ideas repair-run --repo /path/to/repository --run-id <run-id> [--from-stage <stage>] idea-abc123def456
318
+ ```
319
+
320
+ `--from-stage` defaults to `publish`. Every stage strictly before the resume point must already have its real success artifact on disk — this can only skip work that's provably already done, never work that never happened.
321
+
322
+ After reviewing the draft PR, approve and perform merge with the second gate:
323
+
324
+ ```bash
325
+ e3d-pilot ideas approve-merge --repo /path/to/repository idea-abc123def456 --actor you@example.com --note "Reviewed head"
326
+ e3d-pilot ideas merge --repo /path/to/repository idea-abc123def456
327
+ ```
328
+
329
+ `approve-merge` records the exact PR URL, base branch, and head SHA. `ideas merge` refreshes forge state immediately before merging and refuses stale heads, changed base branches, draft PRs, closed PRs, or missing approvals. A GitHub review approval is useful social evidence, but it is not an e3d-pilot merge approval.
330
+
331
+ Request changes, sync forge state, and record outcomes:
332
+
333
+ ```bash
334
+ e3d-pilot ideas request-changes --repo /path/to/repository idea-abc123def456 --reason "Tighten scope"
335
+ e3d-pilot ideas sync --repo /path/to/repository
336
+ e3d-pilot ideas outcome --repo /path/to/repository idea-abc123def456 --window 7d --metric retained=true --metric revenue=42
337
+ e3d-pilot ideas rebuild --repo /path/to/repository
338
+ ```
339
+
340
+ `sync` observes PR head changes, draft/ready changes, checks, closures, and external merges without approving anything. A new PR head invalidates merge approval. `outcome` appends typed metrics; it never overwrites history. `rebuild` rematerializes derived `idea.json` snapshots from `events.jsonl`.
341
+
342
+ ## Migration
343
+
344
+ Existing `.e3d-pilot/runs/<run-id>/` artifacts remain readable. A legacy selected candidate can be materialized as a `proposed` idea by rerunning ideation for that run:
345
+
346
+ ```bash
347
+ e3d-pilot run --repo /path/to/repository --stage ideate --run-id <legacy-run-id>
348
+ ```
349
+
350
+ That command may create a proposed idea record, but it never creates implementation approval. A human must still run `ideas approve`.
351
+
352
+ Existing open e3d-pilot PRs should be adopted only through an explicit adoption command when one is available for your installed version. Adoption must record provenance for the PR/run, start the idea at `implemented`, and still require `approve-merge` before any base-branch merge. Do not treat an open PR, a GitHub review approval, or a branch name as ledger approval.
353
+
354
+ ## Providers and negotiation
355
+
356
+ Built-in adapters are `claude`, `codex`, `local`, `devin`, `grok-build`, and
357
+ the opt-in `gemini` trial adapter; check them with `e3d-pilot providers list`.
358
+ `grok-build` is selected the same way as the others: name it in `providers.*`.
359
+ It is available when the `grok` binary is on `PATH` (override with
360
+ `GROK_BUILD_BIN`).
361
+
362
+ `discover`, `ideate`, `negotiate`, and `review` can each list more than one
363
+ model so every configured adapter gets a turn. A string is still valid and
364
+ means “only this one.” `negotiate` already worked this way; discover, ideate,
365
+ and review now do too. If one discover/ideate/review adapter is missing or
366
+ fails, the others still run and the stage continues; the stage only fails if
367
+ every listed adapter fails. Negotiate still fails fast on an unavailable
368
+ reviewer, because consensus is the point of that stage.
369
+
370
+ **grok-build** — shells out to the Grok Build CLI in headless mode. Reasoning
371
+ stages use the read-only sandbox. Install with
372
+ `curl -fsSL https://x.ai/cli/install.sh | bash`, then `grok login --device-auth`
373
+ or `XAI_API_KEY`. Override the binary, timeout, or model with `GROK_BUILD_BIN`,
374
+ `GROK_BUILD_TIMEOUT` (seconds, default 900), and `GROK_BUILD_MODEL`. There is
375
+ no extra enable flag: naming `grok-build` in config is the opt-in, the same as
376
+ the other adapters.
377
+
378
+ **gemini** — an opt-in trial adapter, intended for an explicitly selected
379
+ `e3d-debate --providers ...gemini...` run. It is absent from `e3d-debate`'s
380
+ defaults and from every default or recommended `providers.*` configuration;
381
+ like every other adapter here, there is no separate enable flag beyond
382
+ naming it explicitly, so nothing in code stops it from also being named in a
383
+ pipeline stage's own `providers.*` config, but its shared, quota-limited free
384
+ tier (see below) makes it a poor fit for any stage that must always succeed.
385
+ Install the [Gemini CLI](https://geminicli.com/docs/get-started/installation/)
386
+ and follow its [personal Google OAuth instructions](https://geminicli.com/docs/get-started/authentication/).
387
+ The adapter rejects API-key, Vertex AI, Google Cloud, credential-override,
388
+ missing, ambiguous, and overage-billable authentication instead of risking a
389
+ paid call -- `settings.json`'s `billing.overageStrategy` must be exactly
390
+ `"never"` (its own default is `"ask"`, not `"never"`). It runs
391
+ headlessly with all built-in, extension, and MCP tools denied by policy, and
392
+ also refuses to run if any Gemini CLI hook, `mcpServers` entry,
393
+ `admin.mcp.config`, `admin.mcp.requiredConfig`, or `adminPolicyPaths` entry
394
+ is configured in the user, system-settings, or system-defaults settings
395
+ file (hooks execute arbitrary commands with prompt access at lifecycle
396
+ events; MCP servers -- including enterprise-admin-required ones, which
397
+ Gemini CLI documents as injected "regardless of user preferences" -- launch
398
+ a command at CLI startup during discovery; admin policy paths point at
399
+ additional policy files this adapter cannot audit -- all independent of the
400
+ tool-calling path the policy denies). Set
401
+ `GEMINI_BIN` (default `gemini`), `GEMINI_MODEL` (unset by default),
402
+ `GEMINI_TIMEOUT` (seconds, default `120`), or `GEMINI_TOKEN_LIMIT` (default
403
+ `200000`) to override its limits. Successful calls report the exact response
404
+ model and tokens when Gemini supplies both, with unmeasured telemetry otherwise;
405
+ the timeout and token ceiling fail the call rather than returning partial output.
406
+ See the [motivating Gemini/Qwen provider debate](docs/debates/2026-09-15-gemini-qwen-provider-addition/transcript.md).
407
+
408
+ To use Grok only as a cheap candidate ranker, keep your existing
409
+ ideate/negotiate providers and add `candidate_scoring` (see
410
+ [Optional ensemble scoring](#optional-ensemble-scoring)). That fan-out never
411
+ executes. Human approval, negotiate, and e3d-code execute stay in place.
412
+
413
+ **devin** — shells out to the Devin CLI in non-interactive print mode. Defaults to `claude-sonnet-4-6-thinking-1m`; override with environment variables:
414
+
415
+ ```bash
416
+ export DEVIN_BIN=devin # binary path (default: devin)
417
+ export DEVIN_MODEL=claude-sonnet-4-6-thinking-1m # model override
418
+ export DEVIN_PERMISSION_MODE=auto # permission mode (default: auto)
419
+ ```
420
+
421
+ **local** — calls an OpenAI-compatible endpoint. Useful for a self-hosted model (e.g. Qwen via Ollama) as a third negotiate reviewer:
422
+
423
+ ```bash
424
+ export LOCAL_MODEL_ENDPOINT=http://localhost:11434/v1
425
+ export LOCAL_MODEL_NAME=my-model
426
+ ```
427
+
428
+ Then add `"local"` anywhere in `providers.negotiate`; reviewer count is not hardcoded. A configured unavailable reviewer fails fast and is never silently skipped.
429
+
430
+ Every real call through the local adapter serializes through a machine-wide lock (a `mkdir`-based mutex at `${TMPDIR:-/tmp}/e3d-pilot-qwen.lock`, override with `LOCAL_MODEL_LOCK_DIR`) so that two e3d-pilot runs — even against different target repos, from cron or fleet mode — never hit a shared local model endpoint at the same moment. This matters because a local endpoint is typically one memory-resident model process backing multiple repos' agents; concurrent requests to it risk OOM, not just contention. A run waits up to `LOCAL_MODEL_LOCK_TIMEOUT` seconds (default 900) for the lock before failing; a stale lock left by a killed process is detected and reclaimed automatically.
431
+
432
+ A negotiate reviewer that omits the optional `reason:` field gets a synthesized `"(no reason provided by reviewer)"` rather than failing the parse — small models that produce a valid `status:` line but drop the reason field are tolerated.
433
+
434
+ The execute stage defaults to `e3d-code`, which currently dispatches
435
+ Codex and Claude. An experimental `providers.execute: "grok-build"` path runs
436
+ Grok directly inside the same approval-gated isolated worktree. e3d-code remains the
437
+ recommended executor. See [Grok Build integration and benchmarks](docs/grok-build.md).
438
+
439
+ ## Publishing
440
+
441
+ `auto` selects `github` for a `github.com` origin and `local` otherwise. GitHub pushes only the run branch and calls `gh pr create --draft`; it never merges or pushes the base branch. Local commits the worktree branch without network access and writes `publish-summary.md`. The scripts in `lib/publish/` share the extension seam for a future GitLab backend.
442
+
443
+ Only after verification passes, publish force-adds findings, candidates, negotiation log, final spec, and e3d-code manifest under the run's audit path so summary links resolve on the branch. Labels configured in `pr.labels` are applied to the GitHub PR at creation time.
444
+
445
+ ## Notifications
446
+
447
+ Once a run publishes — a new branch (and, on GitHub, a draft PR) now exists and is ready for a human to look at — e3d-pilot can send a best-effort email so you don't have to go check. It's opt-in: add `notify.email` to the target repo's config and nothing else changes.
448
+
449
+ ```json
450
+ "notify": {
451
+ "email": {
452
+ "to": "you@example.com"
453
+ }
454
+ }
455
+ ```
456
+
457
+ The email's subject names the branch (and calls out when the outcome `needs-attention`, e.g. no `gh` available for a GitHub repo); the body is the PR URL or local branch/path followed by the same summary that goes into the PR body — findings excerpt, the selected candidate and why it wasn't a duplicate, the negotiation outcome, and links to every audit artifact.
458
+
459
+ By default it shells out to `mail -s "$E3D_PILOT_EMAIL_SUBJECT" "$E3D_PILOT_EMAIL_TO"` with the body on stdin. Override `notify.email.command` to use `sendmail`, `msmtp`, or a script that calls SES/SendGrid/etc. — same env vars, any transport:
460
+
461
+ ```json
462
+ "notify": {
463
+ "email": {
464
+ "to": "you@example.com",
465
+ "command": "msmtp \"$E3D_PILOT_EMAIL_TO\""
466
+ }
467
+ }
468
+ ```
469
+
470
+ If `notify` is absent, or no mail command is configured or found on `PATH`, publish still succeeds — the notification step degrades to a no-op (or a one-line warning) rather than failing the run.
471
+
472
+ ## Project board tracking
473
+
474
+ Ideas otherwise only live in the local ledger (`ideas list`/`show`) until they reach a PR — there's no visibility into what's proposed or approved unless someone goes and asks. Point e3d-pilot at a GitHub Projects (v2) board and it keeps a card for every idea in sync with its actual lifecycle status, from the moment it's proposed through merge:
475
+
476
+ | Idea status | Board column |
477
+ | --- | --- |
478
+ | `proposed` | Backlog |
479
+ | `approved_for_implementation`, `changes_requested`, `implementation_failed` | Ready |
480
+ | `implementing` | In progress |
481
+ | `implemented`, `approved_for_merge`, `partially_merged`, `merge_failed` | In review |
482
+ | `merged` | Done |
483
+ | `rejected`, `closed`, `reverted` | archived (not deleted) |
484
+
485
+ It's opt-in and off by default. Set it once for every repo via an environment variable (same shape as `LOCAL_MODEL_ENDPOINT` — one setting, everywhere):
486
+
487
+ ```bash
488
+ export E3D_PILOT_TRACKING_PROJECT_URL="https://github.com/users/<owner>/projects/<n>"
489
+ ```
490
+
491
+ or per-repo in `.e3d-pilot/config.json` (overrides the env var for that repo):
492
+
493
+ ```json
494
+ "tracking": {
495
+ "project_url": "https://github.com/orgs/<org>/projects/<n>"
496
+ }
497
+ ```
498
+
499
+ A proposed idea gets a draft card. Once it reaches a real PR, e3d-pilot reuses an existing board item for that PR if one is already there — including one a project's own "auto-add" workflow created — rather than leaving a stale draft alongside it. Every sync is best-effort: a misconfigured URL, missing `project`/`read:project` `gh` auth scope, or a transient API error degrades to a stderr warning, never a failed command. Tracking state is recorded as part of the same append-only ledger everything else uses, so `ideas rebuild` never loses which board item an idea is linked to.
500
+
501
+ ## Fleet mode
502
+
503
+ Provide a JSON array of repository paths:
504
+
505
+ ```bash
506
+ e3d-pilot fleet examples/sample-fleet.json
507
+ ```
508
+
509
+ Each repository runs independently. Fleet continues after failures, prints a per-repository result and final totals, and exits nonzero if any repository failed.
510
+
511
+ ### Cross-repo ideation
512
+
513
+ `e3d-pilot fleet <repos.json>` is deliberately blind to opportunities that span repos — each one runs its own isolated pipeline. `e3d-pilot fleet discover` is the complement: a single portfolio-level discover+ideate pass across every repo in the fleet file at once, looking specifically for ideas that only make sense because 2+ of those repos exist together (e.g. one repo's data feed combined with another's payment rails). It never proposes anything that a single repo could do alone — that's what regular `fleet`/`run` are for.
514
+
515
+ ```bash
516
+ e3d-pilot fleet discover examples/sample-fleet.json
517
+ e3d-pilot fleet discover examples/sample-fleet.json --focus revenue
518
+ ```
519
+
520
+ It needs its own small config — `providers.discover` and `providers.ideate`, plus optional `candidate_scoring` (see [`examples/sample-fleet-config.json`](examples/sample-fleet-config.json)) — at `.e3d-pilot-fleet/config.json` next to the fleet file, or pass `--config <path>` to point elsewhere. Output lands under `.e3d-pilot-fleet/runs/<run-id>/findings.md` and `candidates.md`, mirroring the single-repo run layout: `findings.md` has a per-repo `## Portfolio` digest (README/AGENTS/CLAUDE content, head sha) and a model-researched `## Cross-Repo Context` section; `candidates.md` ranks candidates the same way single-repo `ideate` does, except every candidate must name 2 or more repos in a `Repos:` field, and dedup is checked only against prior `fleet discover` runs in the same workspace — not against each individual repo's own branches or PRs, which is a real scope limit worth knowing about.
521
+
522
+ This stage stops after materializing fleet ideas in `.e3d-pilot-fleet/ideas/`, with events in `.e3d-pilot-fleet/events.jsonl`. Cross-repo implementation still requires explicit approval:
523
+
524
+ ```bash
525
+ e3d-pilot fleet ideas examples/sample-fleet.json list --status proposed
526
+ e3d-pilot fleet ideas examples/sample-fleet.json show idea-abc123def456
527
+ e3d-pilot fleet ideas examples/sample-fleet.json approve idea-abc123def456 --actor you@example.com
528
+ e3d-pilot fleet ideas examples/sample-fleet.json implement idea-abc123def456
529
+ e3d-pilot fleet ideas examples/sample-fleet.json implement-approved
530
+ ```
531
+
532
+ A fleet idea records ordered per-repo targets at approval time. Targets are implemented sequentially. If some targets merge and a later target fails or changes, the fleet idea becomes `partially_merged`; e3d-pilot records which repositories merged and which did not. It never claims cross-repo atomicity.
533
+
534
+ ## Reviewing fleet improvements
535
+
536
+ After a fleet run, `fleet prs` gives you a terminal view of open e3d-pilot draft PRs across repos. Use it for visibility, not as the approval workflow:
537
+
538
+ ```bash
539
+ e3d-pilot fleet prs ~/e3d-fleet.json
540
+ ```
541
+
542
+ ```
543
+ repo PR state idea A R effort
544
+ ────────────────────────────────────────────────────────────────────────────────────────────────
545
+ e3d-docs #1 DRAFT In-docs "Ask the Docs" AI assistant 5 5 high
546
+ e3d-sdk #1 DRAFT MCP-native tool bindings for AI agents 5 4 high
547
+ e3d-trade #1 DRAFT Trade Decision Receipts 4 5 medium
548
+ └─ https://github.com/spacepacket1/e3d-sdk/pull/1
549
+ ```
550
+
551
+ If `~/e3d-fleet.json` exists it is used by default; pass an explicit path otherwise.
552
+
553
+ Recommended fleet approvals use the idea ledger:
554
+
555
+ ```bash
556
+ e3d-pilot fleet ideas ~/e3d-fleet.json approve-merge idea-abc123def456 --actor you@example.com
557
+ e3d-pilot fleet ideas ~/e3d-fleet.json merge idea-abc123def456
558
+ e3d-pilot fleet ideas ~/e3d-fleet.json merge-approved
559
+ ```
560
+
561
+ `fleet ideas approve` is implementation approval. `fleet ideas approve-merge` is merge approval for the exact reviewed head SHA. A GitHub review approval or `fleet prs --approve` action must not be treated as either ledger approval.
562
+
563
+ ## Web UI (optional)
564
+
565
+ `fleet prs` and `ideas list` cover the terminal; `e3d-pilot web` is an optional dashboard for reviewing and deciding on ideas across one or more repos in a browser, for anyone who's fine adding Node.js for it. It is not required — every other e3d-pilot command needs only Bash, Git, `jq`, and `curl`, and `e3d-pilot web` refuses to start with a clear error if Node isn't on `PATH`.
566
+
567
+ ```bash
568
+ export E3D_PILOT_WEB_AUTH_USER=you
569
+ export E3D_PILOT_WEB_AUTH_PASS='a real secret, not this'
570
+ e3d-pilot web --repo /path/to/repo-a --repo /path/to/repo-b --port 4173
571
+ ```
572
+
573
+ Open `http://127.0.0.1:4173` (basic auth, the credentials above) to see every configured repo's own idea ledger merged into one filterable list, and a detail page per idea with its summary, scores, dedup rationale, approval/merge state, event history, linked run artifacts, and action buttons (approve, reject, request changes, approve-merge, sync, implement). Every action is a thin, synchronous shell-out to the exact same `e3d-pilot ideas ...` subcommand you'd type yourself — the web UI never reimplements ledger or approval logic, so it can never drift from the CLI's guarantees.
574
+
575
+ Clicking **Implement** spawns `e3d-pilot ideas implement` as a detached background process (draft → negotiate → execute → review → publish can take 30+ minutes) and the idea page live-tails its `implementation-stage-log.md` while it runs.
576
+
577
+ Both `E3D_PILOT_WEB_AUTH_USER` and `E3D_PILOT_WEB_AUTH_PASS` are required; there is no unauthenticated mode. This is meant to run on a trusted machine or behind your own reverse proxy/tunnel — it has no built-in TLS, rate limiting, or multi-user accounts.
578
+
579
+ ## e3d-debate (experimental)
580
+
581
+ `bin/e3d-debate` is a separate, standalone script — not wired into `bin/e3d-pilot`'s subcommand tree or `config.schema.json`, the same way `bin/e3d-backend-benchmark` and `bin/e3d-grok-workers` already aren't — for the "ask several models a question and see whether they actually agree" loop, applied to any question rather than repo work specifically. It reuses the same `lib/providers/<name>` adapters and the `lib/negotiate/convergence` primitive that discover/ideate/negotiate/review already depend on. "Experimental" here means still standalone, not wired into the pipeline proper — not unused or untested: `tests/phase34.sh` covers the provenance-linking flags below, and it has already been the deciding mechanism behind several real architecture and product-direction calls for this project, not just a demo.
582
+
583
+ ```bash
584
+ bin/e3d-debate "Should this service store timestamps as UTC or local time+offset?" \
585
+ --providers claude,codex,devin,grok-build --rounds 3
586
+ ```
587
+
588
+ Round 1: every listed provider answers independently. Round 2+: each provider sees every other provider's prior-round answer and is asked to restate its position, rebut, or concede, ending with `POSITION: <one-line answer>` and `status: approved|revise` — "approved" means a person acting on this answer and a person acting on every other participant's current answer would do the same thing; added nuance or extra caveats don't count as disagreement. Once every provider reports `approved`, `lib/negotiate/convergence` stops the debate early instead of burning the remaining rounds. After the last round (early-stopped or not), one designated `--synthesizer` (default `claude`) reads the full transcript and produces a `FINAL ANSWER` / `CONSENSUS` / `DISSENT` summary.
589
+
590
+ Any `lib/providers` adapter can take part, including `devin` — useful if a Devin/Windsurf subscription would otherwise sit unused. The full transcript (prompts, every round's raw responses, and the synthesis) is written to a temp directory by default, or to `--out-dir <path>` if given.
591
+
592
+ By default a debate's verdict goes nowhere but stdout/the transcript file — it isn't wired into any repo's provenance graph. Pass `--repo <path> --idea <idea-id>` (both required together, plus `--out-dir` pointed somewhere inside `--repo`, e.g. `docs/debates/<slug>`) to automatically record the verdict on an idea that already exists in that repo's ledger once synthesis succeeds, equivalent to running `e3d-pilot ideas note --decision --evidence <transcript-path> <idea-id> "<verdict>"` by hand:
593
+
594
+ ```bash
595
+ bin/e3d-debate "Should we ship it?" --providers claude,codex --repo /path/to/repo --idea idea-abc123 --out-dir /path/to/repo/docs/debates/ship-it
596
+ ```
597
+
598
+ This links the evidence, it does not create the idea — propose that separately (e.g. via `ideas ingest`) first. The transcript itself still needs to be committed for the evidence link to stay durable, the same way the existing `docs/debates/` transcripts are.
599
+
600
+ ## Running on a schedule
601
+
602
+ e3d-pilot is deliberately not a daemon — every invocation is a single, short-lived CLI call that runs (or resumes) a stage and exits. There's no built-in scheduler, so "continuous" is up to whatever calls it: cron, a systemd timer, a scheduled CI workflow, or your own orchestrator all work equally well.
603
+
604
+ Separate autonomous ideation from approved implementation, sync, and dataset export. For example:
605
+
606
+ ```cron
607
+ # Autonomous single-repo ideation; stops before implementation approval.
608
+ 0 */6 * * * /path/to/e3d-pilot/bin/e3d-pilot run --repo /path/to/repo --stage all --focus revenue >> /var/log/e3d-pilot-ideate.log 2>&1
609
+
610
+ # Implement only ideas that humans already approved.
611
+ 15 * * * * PATH="/usr/local/bin:$PATH" /path/to/e3d-pilot/bin/e3d-pilot ideas implement-approved --repo /path/to/repo >> /var/log/e3d-pilot-implement.log 2>&1
612
+
613
+ # Observe forge state and invalidate stale merge approvals.
614
+ */30 * * * * PATH="/usr/local/bin:$PATH" /path/to/e3d-pilot/bin/e3d-pilot ideas sync --repo /path/to/repo >> /var/log/e3d-pilot-sync.log 2>&1
615
+
616
+ # Weekly labeled dataset export for local Qwen evaluation/training.
617
+ 0 3 * * 1 /path/to/e3d-pilot/bin/e3d-pilot fleet train export /path/to/fleet.json >> /var/log/e3d-pilot-export.log 2>&1
618
+ ```
619
+
620
+ Fleet equivalents:
621
+
622
+ ```cron
623
+ 0 2 * * * PATH="/usr/local/bin:$PATH" LOCAL_MODEL_ENDPOINT="http://127.0.0.1:5050/v1" /path/to/e3d-pilot/bin/e3d-pilot fleet discover /path/to/fleet.json --focus revenue >> /var/log/e3d-pilot-fleet-ideate.log 2>&1
624
+ 20 * * * * PATH="/usr/local/bin:$PATH" /path/to/e3d-pilot/bin/e3d-pilot fleet ideas /path/to/fleet.json implement-approved >> /var/log/e3d-pilot-fleet-implement.log 2>&1
625
+ */30 * * * * PATH="/usr/local/bin:$PATH" /path/to/e3d-pilot/bin/e3d-pilot fleet ideas /path/to/fleet.json sync >> /var/log/e3d-pilot-fleet-sync.log 2>&1
626
+ ```
627
+
628
+ A nonzero exit can mean a real failure, or a legitimate stop (`ideate`'s "nothing to do," a `negotiate` deadlock needing human input, a failed `verify`) — check `.e3d-pilot/runs/<run-id>/` in the target repo before treating it as a crash. Drop a `.e3d-pilot/paused` file in a target repo to make the scheduled job a no-op without touching the crontab.
629
+
630
+ ## Weekly exports
631
+
632
+ Use fleet training commands to aggregate the fleet ledger plus every repo ledger named by the fleet file:
633
+
634
+ ```bash
635
+ e3d-pilot fleet train readiness /path/to/fleet.json --since 2026-08-01T00:00:00Z
636
+ e3d-pilot fleet train export /path/to/fleet.json --week 2026-W32
637
+ ```
638
+
639
+ Exports write `ideation.jsonl`, `preferences.jsonl`, `implementation.jsonl`, and `manifest.json` under `.e3d-pilot-fleet/datasets/<YYYY-Www>/` by default. Pending ideas may be exported as unlabeled ideation records, never as rejected examples. Explicit approvals, rejections, changes requested, failures, merges, partial merges, closures, reversions, and typed outcomes provide the labels.
640
+
641
+ ## Safety model
642
+
643
+ Discovery, ideation, and optional `candidate_scoring` do not mutate source. Scoring is read-only and cannot execute a candidate. Draft, negotiate, execute, review, and publish require current implementation approval. Execution uses a separate worktree and per-run branch. Protected paths are checked both when drafting and immediately before the execute backend runs. Actual file/line ceilings stop before review. Failed verification blocks publish. Publication opens a draft PR or local review branch. e3d-code is the default execute backend; Grok Build cannot waive those outer gates even if `providers.execute` selects it.
644
+
645
+ Merge is a separate operation. `approve-merge` binds approval to the observed target set and exact PR head SHA. Merge refuses stale heads, changed base branches, draft PRs, closed PRs, missing approvals, and unsupported local merge backends. e3d-pilot never force-pushes or pushes directly to a protected base branch.
646
+
647
+ Project board tracking (see above) is best-effort and never in the safety path: it's off unless explicitly configured, and a misconfigured URL, missing `gh` auth scope, or transient API failure degrades to a stderr warning rather than blocking ideate, approve, implement, or merge.
648
+
649
+ The optional web UI (see above) adds no new authority of its own: every action it exposes is a direct shell-out to the same `e3d-pilot ideas ...` subcommand, so the same approval gates, transition guards, and merge-SHA binding apply identically regardless of whether a decision came from a terminal or a browser.
650
+
651
+ Run the repository test suite with:
652
+
653
+ ```bash
654
+ set -e
655
+ for test_file in tests/phase{1..25}.sh; do bash "$test_file"; done
656
+ ```
657
+
658
+ ## License
659
+
660
+ [MIT](LICENSE) © 2026 FutCo LLC. Part of the [FutCo](https://futco.ai/projects) open-source ecosystem.