Omniscio documentation
Browse all documentation
  1. Getting Started19
  2. Sessions & Agents135
  3. Inbox & Notifications68
  4. Projects & Tasks98
  5. Automation & Scheduling76
  6. Knowledge & Memory28
  7. AI Features71
  8. Integrations112
  9. Plugins & Marketplace41
  10. Cloud & Teams52
  11. Settings & Customization76
  12. Account & Billing28
  13. Troubleshooting80
  14. CLI & API Reference28
  15. Legal & Policies5
  16. Uncategorised17

How a crew is led — the persistent lead and the lead as a function

How a crew can be led two ways — by a lead session that stays running, or by a lead turn seated for each event — and how the app measures the difference. Covers the switch, what a function turn actually is, the seven numbers the comparison reports (and which of them a seeded run can honestly produce), the one command that runs a seeded comparison, and the rule that a number with no source says so instead of showing zero.

Two ways to lead the same crew

Every crew has a lead post: the seat that acts on the crew's record — closing tasks, moving promises, answering a member. How that seat is filled is a per-crew setting.

  • Persistent lead (the default). One session stays running and holds the post. It keeps its context between events, so it can carry a plan across turns — and it keeps spending turns while it waits.
  • Lead as a function. No always-running session. The post keeps its session id, its schedules and its scorecard identity, but the app retires the running process as each turn settles and starts it fresh on the next event. Every turn is seated by an event, acts on the crew's record and the event, and gives the post back.

The setting belongs to one crew and ships as persistent for everyone. A crew that never switches is unchanged.

Who can switch it

Only the person can. The switch is a privileged control-server call (PATCH /crew/lead-mode), and an agent session's own credential is not admitted to it. The seeded comparison below never uses that route — it sets the mode inside a throwaway database that no live crew can see.

Switching is allowed while a session is holding the post, because the shape keeps that session as the post: what changes is how its turns start, not who the lead is.

The seven numbers the gate reads

GET /crew/lead-mode-comparison answers per crew, and every number carries a status:

Number What it is Where it comes from
moves per paid lead turn real work the lead did, divided by the turns it was given the crew scorecard
owner replies per lead-day how often the person had to step in the crew scorecard
promises proven deliverables the crew actually delivered the crew scorecard
spend per paid lead turn what the lead's turns cost the crew scorecard's spend columns
missed events events raised at the post that never produced a turn the crew's turn ledger
turn latency how long an event waited before its turn started the crew's turn ledger
refusals events the post could not accept the crew's turn ledger

The three statuses matter as much as the numbers:

  • measured — read from the live record.
  • scripted — produced by a seeded run. A seeded run uses a stub turn, so its numbers prove the pipeline works end to end; they cannot rank the two shapes.
  • unavailable — there is no source, and the report says why. A crew that has never recorded a turn reads unavailable for the three ledger numbers, never 0, because a zero would read as a perfect result and decide a gate.

Today the turn ledger is written only by the seeded comparison itself. Nothing on the live delivery path records a turn yet, so on a real install the three ledger numbers — missed events, turn latency and refusals — read unavailable for every crew, including a crew already switched to the lead-as-a-function. They become measurable when the app records each attempt as it delivers an event; that writer is tracked separately. The report telling you unavailable is the honest answer, not a bug in the table.

Run a seeded comparison

npm run lead-mode:compare -- --seeded

The command copies the shipped starting database into a temporary folder, seeds two crews of the same shape that differ only in how they are led, and drives one identical scripted event stream — a member's report, a red success number, a stalled promise, the person's reply, a second report, an event that arrives while the post is stopped, and one that follows it — through both. Each event starts one turn, and the turn performs the same deterministic stub actions on both sides.

It prints the seven numbers for both shapes beside the live persistent-lead baseline, then deletes its temporary database. Add --keep to inspect it, or --json for a machine-readable answer.

What it does not do. It spawns no session and spends no tokens, so its spend number is unavailable. Its latency is the model's fixed turn-start cost. Both sides act on the same events, so the table is equal by construction — that equality is the point: it shows the pipeline produces every number, and it is not evidence that one shape is better.

Where the code lives

  • src/shared/crew-lead-mode-metrics.ts — the seven keys, the ratios and the three statuses. One definition, used by the live route and the harness alike.
  • src/main/db/crew-lead-mode-sql.ts — the move query, the comparison query and the turn read, run by the app through its database layer and by the harness through its own handle.
  • src/main/services/overseer/crew-lead-mode-seeded-run.ts — the seeding, the scripted events and the stub turn.
  • scripts/crew/lead-mode-compare.ts — the command.
  • The table agent_crew_lead_turns — one row per event-to-turn attempt, which is what makes missed events, latency and refusals measurable.

Last verified 2026-10-17