An idea pipeline: research → plan → build across agent sessions

Research, 2026-10-17. Question from the owner: a system where a loose inspiration gets researched into a public domain-expertise document, then turned (with a human-supplied goal) into a private implementation plan, then built — each step an independent job, with unbounded waits between steps. This report answers the owner's ten questions and proposes a concrete design. It is a research document, not an implementation plan: it contains no folder hierarchies, hooks, or build steps that are system-unique beyond pointing at the existing tools it would ride. Companion documents: ~/manifest.md, ~/research/fresh-deno-cockpit-research.html, ~/implementation-plans/checklist-impl-plan.html (the house patterns this borrows), ~/projects/orbit/README.md, the relay skill.

The short answer: half of this system is already built, and the other half is smaller than it looks. The artifacts are folders of self-contained HTML (the house document standard, already in use for research and implementation plans). The tracking mechanism is one small JSON ledger per idea on the filesystem — no database. The job queue does not get invented: it is orbit, the dispatch system this machine already has (checklist §2), with the research and plan steps simply as two more lanes. The public web view is a generated static export of the research tree. What needs building is a thin pipeline CLI, a publish script, and one cockpit card.

1. The shape of the system

Each idea moves through five named states, and each state is crossed by exactly one kind of job — an independent, bounded agent session:

newinspiration→ researchedexpertise doc→ plannedimpl. plan→ builtcode + tests→ shippedverified on/off
StateJob that entered itInputProducesHuman moment
newnone — the owner speaks ita loose ideathe pipeline's ledger entrythis is the seed; the only required input
researchedresearch jobthe inspiration + the webpublic expertise docowner reads/approves the doc
plannedplan jobexpertise doc + owner's goal + the system (manifest, AGENTS.md, live stack)private impl plan, incl. modifications to existing partsowner reads/approves the plan
builtbuild job (orbit)the plancommit(s) in the project repo, passing suiteglance at the diff before verify
shippedverify jobthe built code + the plan's acceptance criteriaoff/on drill, zero-context agent test (AGENTS rule 10), manifest row, mem note, checklist item closedowner uses the thing

Three properties make this work across sessions that may be days apart:

  1. Every artifact outlives the session. The session is disposable; the folder it wrote is the permanent record. A session that died mid-research leaves the partial doc in place — the next re-run of that job reads it and continues, like the orchestration skill for multi-context work (relay, the relay-runner profile) already does with its baton. The pipeline ledger plays the relay roles: ledger = stable agreement, per-job output = baton, log.md = history.
  2. Handoffs are human-gated. Research never auto-becomes a plan. The owner sits at the seams where judgment lives: the idea (what to research) and the goal (what to build). Those two are the only inputs a job can't produce for itself.
  3. Nothing in the chain needs the prior session to be alive. The handoff medium is a file path. "Wait an undefined amount of time" is just "the next job runs when its input exists and the owner releases it" — there is no timer, no daemon waiting, no state to expire.

2. Answer: how is the data organized as it flows?

Three distinct homes, one rule: the filesystem is the source of truth (same ruling orbit's checklist item 2.11 carries — per-task dirs, filesystem is SoT).

~/research/                      the PUBLIC tree — domain expertise
  ├── index.html                 generated catalog (never hand-edited)
  └── searxng-self-host/
        ├── doc.html                   the readable document (self-contained)
        ├── sources.md                 source list with access dates
        └── assets/                      images, diagrams — only if doc.html needs them
        (sibling) searxng-self-host-2026-10-17.tar.gz   portable bundle

~/implementation-plans/          the PRIVATE tree — exactly what's there today
  └── searxng-self-host-impl-plan.html   (+ its reference tarball, existing pattern)

~/pipelines/                     the LEDGER — one small file per idea (the new part)
  └── searxng-self-host/meta.json
~/pipeline-jobs/                 job WORKSPACES — ephemeral, disposable once done
  └── p002-searxng-self-host-research/
        prompt.md  output.md  progress.md  log.md  lock  meta.json

The key separations:

The plan file points at both sides of its chain: its header carries the ledger's path (which chain) and the research doc's path (which expertise it consumed). The ledger points backward the same way. Two cross-references, both cheap, and an idea's entire history is recoverable from its ledger.

3. Answer: how are expertise documents organized, and in what format?

Format: self-contained single-file HTML. One decision, all ten questions get easier. It is already the house standard (AGENTS rule 8): renders identically by an agent reading it, by the owner on a phone, by a browser on the tailnet, or on the public web — and it requires zero tooling to view, which is what matters for a public audience who will not clone a repo.

CandidateViewable in browserDiffs in gitPublic-publish costAgent-readableHouse precedent
HTML (chosen)yes, zero toolingyescopy the fileyes (plain text)all existing research + plan docs
Markdown + local renderernobestbuild stepyesorbit docs (interior, fine there)
SQLite + query UInonogenerator neededawkwardmem — right for ledger rows, wrong for prose

The one thing Markdown does better is diffing. The trade is acceptable: expertise docs change rarely (re-research = new file, per §2), and where diff matters — code — git already does it natively. For documents that genuinely have many multi-kilobyte edits across a long life, the doc becomes a folder: doc.html is the assembled reader view; large tables (source lists, benchmarks) live in sibling files it links. That covers "what a doc needs more than one file" (§7) without breaking the one-file rule for the 95% case — most house documents will always be one file, because the boilerplate keeps them small.

What goes in an expertise doc (per the owner's spec, made concrete):

The no system-specific content rule gets a concrete enforcement: the research job's prompt ends with a checklist the agent verifies before finishing — no paths, no daemon names, no hostnames, no machine specs that aren't generic. (orbit checklist item 2.16, "every lane prompt ends with verification instructions", is the existing pattern.) A doc that fails its own audit gets flagged, not shipped.

4. Answer: public web

Because the document is a self-contained HTML file, publishing is a copy:

pipeline publish            # regenerates index.html, copies ~/research/* → ~/research-public/
                            # (tar.gz alongside; a single rsync/ftp of one folder to the host)

Three viable hosts, in order of friction:

  1. A git remote + GitHub Pages (or Cloudflare Pages): publish rsyncs into a git worktree, commits, pushes. Pages serves the folder; the generated index.html is the catalog. The box gets a git remote for the first time in the system — a new hook that needs a manifest row the moment it lands (AGENTS rule 6). Note this deliberately differs from the no-remotes-standing policy in manifest §5, which covers code repos as backup; this one publishes prose, not code, and the owner rules on it.
  2. Tailscale funnel on the cockpit: /research/… served from the box. Instant, no remote, but the tailnet-identity gate means it is visible to the owner's devices, not the open web — fine if "public" really means "me, on any device".
  3. A home server: rsync the folder. Most moving parts, least magic.

The generated index.html lists each doc with its title, date, and a one-paragraph abstract (read from the doc's <title> + first <p>), newest first — same newest-first convention as ~/tapes/INDEX.md. Regenerating it is derivable work like mem sum: you can rm and rebuild it any time, because the docs are the source.

5. Answer: database, or a folder of files?

Files. Specifically: one JSON file per idea. SQLite would be the wrong shape.

The ledger, concretely:

{
  "slug": "searxng-self-host",
  "inspiration": "replace the Exa free tier with a local search backend",
  "goal": "orbit research jobs get search that costs nothing and can't be rate-limited",
  "state": "planned",
  "created": 1763323333,   // unix epoch seconds (owner 2026-10-17: decisive sort);
                              // legacy day-strings normalize at read, never rejected
  "jobs": [
    {"id": 1, "stage": "research", "status": "shipped",
     "workspace": "~/pipeline-jobs/p001-searxng-self-host-research/",
     "artifact": "~/research/searxng-self-host/doc.html",
     "started": "2026-10-17T21:00:00Z", "finished": "2026-10-17T21:14:00Z",
     "attempts": 1},
    {"id": 2, "stage": "plan",     "status": "shipped",
     "artifact": "~/implementation-plans/searxng-self-host-impl-plan.html",
     "started": "2026-10-17T21:30:00Z", "finished": "2026-10-17T21:44:00Z",
     "attempts": 1},
    {"id": 3, "stage": "build",    "status": "queued", "artifact": null, "attempts": 0}
  ]
}

That file is the answer to "how do I track an idea end to end": a state field for the chain and a status field per job, with timestamps that a fresh session can read without asking anyone. It is also the cockpit card's data source (§8) and the publish script's input. One file, three consumers — the inverse of the lesson in manifest §5, where state spread over tailscaled, the app, and a note, and one of them was wrong.

6. Answer: how are jobs organized?

They don't get a new queue. orbit is the queue. The research and plan steps are the research lane with a lane-level prompt orbit's checklist already specifies (2.3: 27B-class model + web search tools); the build step is the code lane with the plan as its prompt; the verify step is the test model (checklist 2.8: "build ↔ test model handoff"). What orbit v2 gives the pipeline for free, item by item:

Pipeline needorbit checklist item that covers it
a queue that survives reboots2.1 — per-task dirs, filesystem is SoT
one agent at a time, no pileups2.2 — worker pulls serially; no KeepAlive
don't dispatch into a dead model2.3 — health gate, probe before pull
don't retry forever when a job is broken2.4 — attempt cap N>3 → poisoned, needs human
never two agents writing the same artifact2.5 — single-writer assertion, fail fast
jobs that end with self-check2.6 — verification instructions in every prompt
clean on/off2.7 — orbit start/stop scripts (rule 5)
right model per step2.8 / 2.9 — lanes as adapters
owner can see the queue1.2 — the cockpit task-view item
cheap signal on friction2.13 — friction log; also fed to the punchclock ledger

So: pipeline new/research/plan/build <slug> resolves to dispatch_task with a composed prompt (template + inputs), writes the job row into the ledger, and orbit runs it. When the job finishes, the workspace's output files land in the artifact home, the ledger row flips to shipped, the chain's state advances, and — per the owner ruling in checklist 1.2's kin — that is the end of the automated part. The next step waits for the owner.

owner ruling 2026-10-17 (the gate): a queued job must not start while the pi-agent is in use — same contract the image-studio runners live by (this is partly why the focus tool exists). Concretely: pipeline run reads ~/.run/focus.json before any launch; gate on → the job is held (a message, exit 3, the ledger untouched) and relaunches the moment the gate opens; gate off → the detached session is dispatched. The queue persists through the gate, never cancels. In the first pass the launch trigger stays a manual tap in the terminal — the gate decides whether that tap fires. (Whether the focus watch itself should relaunch on flip — auto-drain, the image-studio behavior — is left open for phase 3 with orbit.)
Owner ruling 2026-10-17 (this question, answered): do not build a daemon now. For the first pass, every step is initiated manually — the daemon comes last, after confidence in the system is built. Concretely: pipeline research/plan/build/verify <slug> is a one-shot verb that launches one bounded agent session (no worker, no queue dir, no scheduling); orbit v2 (checklist §2) is the same verbs pointed at a scheduler when it lands. The ledger, artifacts, and handoffs are identical in both — the daemon only replaces timing. This is exactly the right ordering: the parts the owner can inspect (one folder, one HTML doc, one ledger row) come before the parts that run themselves.

7. Answer: multi-file jobs stay one job, because a job is a directory

The orbit pattern already answers this: a job is a directory, and a directory is atomic to the filesystem — there is no "bundle" step, no zip step, no archive to re-attach. The workspace's contents are the bundle:

~/pipeline-jobs/p002-searxng-self-host-research/
  prompt.md        ← exactly what the agent was told (re-runnable: this is the job, verbatim)
  output.md        ← working draft (markdown is fine here; rendered at the end)
  sources.md
  progress.md      ← the baton: what's done, what's next, for a successor after a death
  log.md           ← append-only: what the agent tried, what failed, dates
  lock             ← the single-writer token (orbit 2.5)
  meta.json        ← attempt count, state machine for workspace, model, lane

Two moves keep it clean. First, the finished bundle is the artifact folder (§2), which carries the stable name in the stable home; the workspace gets tarred to a sibling .tar.gz (the existing pattern — every house implementation plan ships with its reference tarball) and the workspace itself is deleted. The tarball is the process record; the folder is the product record. Second, the ledger row points at the folder, never at workspace fragments, so a re-run of a job can never be ambiguous about which work belonged to it. "One job, many files" then has exactly one meaning: a path, plus a machine-readable manifest inside it.

8. Answer: visualizing progress

Two surfaces, same source. Both read the ledgers; neither can write them (the dashboard observes, the terminal mutates — the standing ruling from the cockpit's task card, checklist 1.2).

Both surfaces are derivations of the same five ledgers, so they cannot disagree in any way a human would notice — and if a ledger is corrupt, both fail loudly together, which is the failure mode you want.

9. Answer: resource management — not taking the system down

The box is one 64 GB M4 Mac where the owner lives, so the doctrine is the one already in the house: bounded concurrency, gated admissions, hard caps, clean stops. Each clause maps to something that exists:

DoctrineMechanism
Serial execution — at most one agent job at a time, per laneorbit 2.2 — the worker pulls serially. No "three big sessions at once" pileup is possible by construction, because there is no pool to overdraw.
Health gate before pullorbit 2.3 — probe the model (8-token generation) before dispatching. The 2026-10-11 Ollama death (manifest §5: 13 tasks crash-queued into a re-queue spiral) is the exact case this defuses.
Poison caporbit 2.4 — attempts > 3 → poisoned, human-decidable. No job can burn the box forever while looking busy.
One writerorbit 2.5 — O_EXCL token at workspace start; a second writer fails fast instead of corrupting an artifact.
Model budgetlane = adapter (2.8/2.9): research runs the 27B-class, build runs the lighter model, never both loaded. Two 27B-class models simultaneously is the one thing that would actually squeeze 64 GB into trouble; the serial lane + per-lane-model assignment makes "both" unrepresentable.
Respect for the ownerthe focus gate already owns "is the box in deep use?": job admission checks it (punchclock/focus, already live under launchd). No job launches that the owner's active session would feel; pipeline stop / orbit's off-script (2.7) drains.
Everything pausable, cleanlyrule 5: off/on tested at build time. A pipeline job can be killed mid-flight and re-queued with its progress.md intact — the death is boring by design.
Signal, not silenceorbit 2.13 friction log + punchclock ledger rows per stage transition. If the box ever does get loaded, the ledger shows where, and mem gets told (its own off/on and cadence discipline is already the model: no KeepAlive).

The unsaid clause, stated now: the research and plan jobs are the cheap ones — a few minutes of 27B inference and some web fetches. The build job is the expensive one, and its budget is exactly the project's test suite + the off/on drill, both bounded and existing. Nothing in this pipeline can take the box down, because nothing in it runs unbounded in the background: the only daemons involved (Ollama, orbit worker, focus watch) all have manifest rows with named stops.

10. How this fits what already exists — and what that means for building it

Piece by piece, the new system is a ledger, a lane prompt, a script, and a card:

PartWhat it isWhat exists it rides on
pipeline CLI (the only real new tool)new / research / plan / build / verify / ls / publish / stop — writes the ledger, composes the prompt, launches one bounded session per step (orbit becomes the executor when it lands), renders the stepperchecklist/flags/mem as the pattern (one state file, atomic writes, exit-code doctrine 0/1/2, env overrides, self-resolving ~/bin symlink); the house HTML boilerplate as the doc template
prompt templatesthree files: research.md, plan.md, build.md, each ending in its verification checklistorbit 2.6 / 2.8 / 2.9 lane shapes; the relay skill's baton/compact-state discipline for the plan and build prompts
publish scriptregenerate index.html + rsync/tar the research treethe generated-INDEX convention of ~/tapes; the tarball-as-bundle convention of ~/implementation-plans/
cockpit cardread-only stepper per chain + the research catalog behind the tailnet gatethe tasks card's exact shape (checklist 1.2): GET /api/…, one file read, derive in define.page
orbit v2the scheduler — last, when the owner points at it…is the 13-item checklist; the pipeline's already-trusted verbs are what it executes

Sequencing, as ruled (2026-10-17): (1) the pipeline CLI with one-shot execution — writes the ledger, launches the session, lands the artifact; (2) publish + cockpit card, each an afternoon and independent; (3) orbit v2 as written in its checklist — the same verbs start reading from the queue, and running chains through it becomes the daemon's proof of concept. Nothing here needs a new service, a new port, or a new launchd job in the first two phases — the pipeline CLI is on-call, like mem/tags/checklist/flags. The manifest gets one new row when orbit v2 lands, not a fleet.

11. Decisions (ruled, 2026-10-17)

DecisionRuling
The queue daemon.No daemon in the first pass. Every step initiated manually; the daemon is the last step, adopted once confidence in the system is built. (§6 carries the operative form.)
Public host.Deferred. Undecided for this pass. The research tree and publish script are host-agnostic, so the ruling can land later without design rework; the manifest row writes itself when it does.
First chain.SearXNG self-host (checklist 5.4) — a genuine web research exercise, a real and testable build step, and it lands a named project.
Slug convention.As specified. The slug names the chain; the date suffix rides on re-research versions; pNNN counters the jobs.

Consequence for scope of the first build: the pipeline CLI (one-shot verbs), the three prompt templates, the ledger writer, and the SearXNG research job. Everything else waits its phase.

What I deliberately did not design: a database (any shape) — the scale doesn't pay for it (§5); parallel job execution — the box can't afford it and serial is the safety floor, not a performance choice; a web UI for editing chains — mutations stay in the terminal, the terminal is where the owner's judgment lives; a supersedence column on the ledger — same no-supersedence ruling as mem: the dates are the currency, the reader checks.

One file, zero JS, dark mode, phone-readable per house rule 8. Companion: ~/implementation-plans/ — the plan job for whichever chain the owner releases first lands there as <slug>-impl-plan.html + tarball. Written 2026-10-17.