Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions prd/0018-take-what-omp-got-right.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
---
openprd: "0.3"
id: "0018"
title: "Take what omp got right: cross-engine handoff, stream rules, and a usage ledger"
status: Draft
authors:
- anthony@profullstack.com
created: 2026-09-25
updated: 2026-09-25
repo: https://github.com/moshcoder/moshcode
discussion:
implementation: src/cost.mjs, src/pty.mjs, src/engines.mjs, src/openfleet.mjs, src/swarm.mjs, src/herd.mjs, src/mcp.mjs
tags:
- engines
- herd
- cost
- openfleet
- dx
supersedes:
superseded-by:
---

## Problem

moshcode v0.104.2 added omp as an engine (#536). Installing it meant reading what it
does, and omp turns out to be the most interesting harness in the set: roughly 80k
lines of Rust, 60+ providers, 31 built-in tools, 14 LSP operations, 28 DAP operations,
and a handful of ideas nobody else has shipped.

Most of that is not ours to take. The Rust core, the in-process ripgrep, the LSP and
DAP wiring are engine internals. moshcode is a wrapper. It inherits those from whatever
engine it launches, and rebuilding them would be building a twelfth engine instead of
wrapping eleven.

But a few of omp's ideas are only half-built, because omp can only ever apply them to
omp. It imports sessions from Claude Code and Codex, one direction, into itself. Its
stream rules correct one model, its own. Its usage report covers the providers it
happens to be configured with. Each of those is a single-agent version of something
moshcode is already positioned to do across all eleven engines.

Three things make this cheap rather than speculative:

- `src/cost.mjs` already parses every engine's transcript format, because that is how
burn windows and folded subagent transcripts work. The expensive half of a
cross-engine session handoff is written and tested.
- `src/pty.mjs` and the herd panes already sit between the user and the engine's output
stream. Stream rules belong at that layer, where they are engine-agnostic by
construction.
- `moshcode cost` already reports spend. It does not report remaining limits, which is
the number that actually matters when one Anthropic key is shared across 13 production
vaults under a single spend cap.

Two things are already done and should not be re-proposed. `src/completion.mjs`
generates shell completions from `src/cli-schema.mjs`, so moshcode already has omp's
no-drift completions. And `src/advisor.mjs` is advis0r.com equity research, not an
advisor model, so that filename is taken and any advisor-model work needs a different
name.

## Goals

- A conversation can move between engines. Start in Claude Code, continue in Codex,
finish in omp, without retyping context or losing what was decided.
- A swarm's lineage gap closes as a side effect, because a handoff is exactly the edge
OpenFleet wanted recorded and PR 502 did not write.
- Correcting a model mid-run does not cost context, and does not have to be reimplemented
per engine.
- Before a run starts, the sysop can see what headroom is left on the account it will
land on, not just what the last run cost.
- No engine process ever reads a credential out of a .env file.
- Every verb this PRD adds is reachable from the CLI, the TUI and the MCP bridge, per the
house agent-surfaces rule.

## Non-Goals

- Rebuilding omp's engine internals. The Rust core, in-process utilities, LSP and DAP
stay where they are. moshcode wraps omp to get them.
- Shell completions. Already generated from `cli-schema.mjs`.
- A web dashboard on a localhost port. omp's `stats -p` is a browser page. The house
stack says hqtui for dashboards, so moshcode's equivalent is a TUI.
- Lossless handoff. Engines do not share a transcript schema and never will. This PRD
targets a faithful conversational handoff, not a byte-exact clone.
- Replacing `moshcode swarm`. `cleanse` is a preset over the existing swarm, not a
second orchestrator.

## Users

- The sysop running several engines a day who currently restarts a conversation from
scratch whenever one engine stalls or hits a cap.
- The human reading `moshcode fleet tree` afterwards, who wants to know which run
descended from which.
- The operator on a shared key who needs to know whether the next run will be refused
before starting it.

## Requirements

- R1 [P0] `moshcode handoff <from-engine> <to-engine> [--session <id>]` reads the source
engine's transcript with the existing `cost.mjs` reader, renders it to a portable
transcript, and launches the target engine seeded with it. Defaults to the source
engine's most recent session for the current directory.
- R2 [P0] A handoff writes an OpenFleet record linking child to parent, so the edge shows
up in `moshcode fleet tree` without a separate lineage feature.
- R3 [P0] The portable transcript is a documented format under `prd/` or `docs/`, not an
internal shape, so a twelfth engine only needs a reader and a writer to join.
- R4 [P0] `moshcode cost limits` reports remaining provider headroom per account, across
engines, alongside the burn rows already there. Credentials come from the vault, never
from the environment.
- R5 [P1] `moshcode cost route <model>` is a dry run answering which account a call would
actually land on, before spending anything on finding out.
- R6 [P1] Stream rules. A rule watches an engine's output stream through `pty.mjs` and
can inject a correction without adding to the model's context. Rules live in
`~/.moshcode`, sync through synconfig, and apply to every engine because they sit below
all of them.
- R7 [P1] `moshcode rules test <rule> <transcript>` replays a rule against a saved
transcript so a rule can be trusted before it is armed. Tests use `node --test`.
- R8 [P1] `moshcode auth serve` hands per-engine credentials to engine processes from the
vault, so no engine reads a .env. Honours the existing `login` and `whoami` verbs.
- R9 [P2] Session branching. Forking a conversation at an earlier turn opens the branch as
a new herd pane beside the original, rather than as a modal tree the user pages through.
Both branches run and are visible at once.
- R10 [P2] `moshcode grievances [list|clean|push]` collects engine complaints about their
own tooling and pushes each as an issue to the correct repo.
- R11 [P2] `moshcode cleanse [-n <agents>]` is a swarm preset that finds and fixes
diagnostics and failing tests.
- R12 [P0] Every verb above is exposed through the MCP bridge, per the house rule that a
CLI ships an MCP bridge. Any dashboard is hqtui.
- R13 [P0] Copy in this feature set follows the house standard. Short sentences, no em
dashes.

## UX Notes

The handoff is the whole product and should read like one line of intent. `moshcode
handoff claude codex` with no further arguments picks the obvious session and says what
it picked before launching. When the target engine is already running in a herd pane, the
handoff lands in that pane rather than opening another.

Naming matters here. `advisor` is taken by equity research, so an advisor-model feature
needs its own word if it is ever built. `cost limits` is a verb under an existing noun
rather than a new top-level `usage`, because the sysop already looks at `moshcode cost`
and should not have to learn where the other half of the same question lives.

Stream rules are the one feature that can silently make an engine worse. They are off
until armed, `rules test` runs against a real saved transcript, and an armed rule that
fires is visible in the pane rather than invisible.

## Success Metrics

- A conversation survives a move between at least three engines with the decisions intact,
judged by the receiving engine continuing the work without re-asking.
- `moshcode fleet tree` shows handoff edges, closing the lineage gap PR 502 left.
- `moshcode cost limits` answers "will this run be refused" before the run, on the shared
Anthropic key.
- Zero engine processes launched by moshcode read a credential from a .env file.
- Stream rules are engine-agnostic in fact, demonstrated by one rule correcting at least
three different engines unchanged.

## Risks & Open Questions

- Transcript formats drift. `cost.mjs` reads them today and will break when an engine
changes its shape. Handoff inherits that fragility and makes it louder, since a bad read
now corrupts a conversation instead of a cost number. Fixtures per engine, and a handoff
that refuses rather than guesses.
- Seeding a target engine is per-engine work. Some take a prompt on stdin, some take a
file, some have a resume flag that only reopens their own last session. `engines.mjs`
already records the resume argv, so the seam exists, but each engine needs its own
writer and some may not be seedable at all. Those should be listed as unsupported rather
than half-supported.
- A rule that injects mid-stream is close to prompt injection against your own engine.
Rules must be local files under `~/.moshcode`, never fetched, and never installable by
an agent without the human arming them.
- Provider limit reporting is not uniform. Some providers publish headroom, some only
report after a refusal. `cost limits` should say which of the two it is showing rather
than presenting a guess as a reading.
- Open question: does handoff carry tool results and file edits, or only the conversation?
Carrying edits risks replaying them. The proposal is conversation plus a summary of what
was changed, with the working tree as the real state.
- Open question: the portable transcript format is a candidate for a `@profullstack/*`
package if anything else ever needs to read engine transcripts. Per the reuse-first rule,
check before writing a second copy.
3 changes: 2 additions & 1 deletion prd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ Start one with `moshcode prd "<idea>"` (TUI: `/prd`).
| [0014](0014-remote-mcp-session-gateway.md) | Expose live Moshcode sessions over remote MCP | Draft |
| [0015](0015-swarm-one-task-a-herd-of-agents.md) | Swarm — one task, a herd of agents, one answer | Draft |
| [0016](0016-openfleet-the-record-a-swarm-leaves-behind.md) | OpenFleet: the record a swarm leaves behind, and the fleet verb that reads it | Draft |
| [0017](0017-moshcode-on-the-omarchy-bar.md) | Put the herd on the Omarchy bar — a plugin, and the one snapshot it reads | Draft |
| [0017](0017-moshcode-on-the-omarchy-bar.md) | Put the herd on the Omarchy bar — a plugin, and the one snapshot it reads | Accepted |
| [0018](0018-take-what-omp-got-right.md) | Take what omp got right: cross-engine handoff, stream rules, and a usage ledger | Draft |
<!-- PRD-INDEX:END -->
Loading