← plans · north_os · DESIGN.md24 juil. 2026

Async research delegation — North-in-Cowork orchestration speed — design spec

Status: Planned · Author: Claude (with Christophe) · Date: 2026-07-24 · Repo: north-os (apps/mcp-server, packages/agent-runtime, packages/knowledge, packages/connector-onedrive, a new worker-research)
Related: docs/reviews/2026-07-24-retrieval-speed-research.md (research memo), docs/reviews/2026-07-24-preprod-search-benchmark.md (benchmark), docs/superpowers/specs/2026-07-09-cowork-plugin-design.html (MCP surface), docs/superpowers/plans/2026-07-18-mcp-partial-state.html (partial-state contract)

Problem

Per-tool latency is already good (preprod: knowledge search ~1.5s, matter search 87ms, memory 3ms). The felt slowness on real work is turn count, not tool latency:

total latency ≈ Σ(per-tool latency)  +  turns × (model re-planning + MCP round-trip)

A real task — "across all our Settlement Housing Fund matters, did we get the Clusters 3 Freddie modifications anywhere else, cite each source" — ran on Claude Cowork over our MCP as ~30+ sequential round-trips: find 25 matters → read Clusters 3 → sweep matter-by-matter → read docs one at a time → then spawn a compare subagent. Every round-trip pays MCP-HTTP RTT + Cowork re-planning. The same task on our own heynorth.dev harness finished faster and answered tighter, because our tools run in-process and our graph owns orchestration and stopping.

Two conclusions: (1) collapsing turns beats shaving any single tool — raising server-side concurrency removes zero model turns; (2) the answer also over-delivered ("the investigation became the answer") — a calibration failure downstream of weak tool-use reasoning.

Goals

Non-goals

The granularity spectrum (the balance)

25→1 is the right collapse for a genuine cross-matter research question, but wrong for a two-document lookup. The surface is three tiers, and the briefing + tool descriptions steer the agent to the smallest tier that fits:

TierTool shapeUse whenTurns
1 — Atomic (today)matter_search, matter_context, matter_documents_search, read_document, knowledge_search1–2 calls answer it; ambiguous matter needs a lawyer choice; a write/draft/confirmation; the lawyer wants to inspect intermediate steps1–3
2 — Batch / fan-out (new, synchronous)matter_documents_extract (read K docs → quote-bearing evidence in one call); explicit matter_ids[] sweepsa bounded, known set of matters/docs (≈2–8); the agent still wants to reason over the returned evidence itself1 call replaces N
3 — Async research subagent (new, non-blocking)north__research_matters — one durable job running a read-only agent-runtime graph in-processself-contained research spanning many matters/docs, no mid-task lawyer choice, deliverable directly in chat (the SHF case)1 external Cowork turn; 5–8 internal

The tiers compose: for a mixed task, delegate only the research packet to tier 3, then let Cowork draft fine-grained from that packet. Tier 2 is the deliberate middle — it collapses turns without handing the whole task to a black box. That is the "25→1 is sometimes too much" answer.

Tier 3 — the async research subagent

Shape

north__research_matters is a domain-scoped agent task (one conceptual action: produce a grounded, cited cross-matter research answer) — not a workflow, not a generic executor. Internally it runs a read-only agent-runtime graph — plan → extract → synthesize → verify → stop — with an explicit tool allowlist (no ask_user, no writes, no confirmations), the same RLS gates and methodology as the interactive runtime, and a 5–8 internal-round budget.

Non-blocking lifecycle (the core of "run it in the background")

The tool is a durable job, not a long synchronous call — so it survives disconnects, streams progress, is cancellable, and can report back after the lawyer has moved on:

Where it runs: a dedicated headless worker (worker-research, per the one-worker-per-domain rule) consumes a research queue and runs the graph, writing progress/result to a research_job table (RLS, org-scoped). The MCP _start only enqueues. This is the same headless-agent pattern worker-automations already uses for automation.run (evaluate reuse vs a new worker in the plan).

How the lawyer keeps working + gets reported back:

Inputs / outputs

Input is intent + scope (a natural-language question + optional matter/doc-type scope), not resolved IDs — the graph resolves matters itself (no cheating). Output is the calibrated answer: bottom line first, minimum supporting analysis, source docs with operative quotes and matter/doc/section binding, and an explicit coverage statement ("25 resolved SHF matters; 24 fully searched, 1 unreadable") so a negative is honestly scoped.

Tier 2 — batch evidence extraction

north__matter_documents_extract({ matter_ids | targets[], intent }) reads K documents server-side (6-wide shared admission) and returns compact quote-bearing evidence with strict matter/document binding and full/partial coverage semantics — no write behavior. This is the 25-sequential-reads → 1-call collapse, available to Cowork directly (not only inside tier 3), for asks where the agent wants to keep control of the reasoning.

Enabling speed layers

These make tier 3 feel instant rather than "one long opaque call"; specified fully in the research memo, summarized here:

Answer-shape / stop discipline

Add a supported-negative stop rule to the briefing (cowork/briefing.ts, legal-assistant/prompt.ts, apps/mcp-server/src/tools/briefing.ts): answer the actual question first; bottom line in sentence one; a supported negative is a complete answer; don't add sections because research was extensive; offer one specific follow-up instead of padding. Applies to both the tier-3 graph output and the interactive runtime. It fixes the "trop étalé" SHF answer and removes 0–2 post-answer exploration turns.

Correctness / RLS acceptance gate (must pass before latency counts)

Telemetry

Extend eval-cowork-bench.ts to record and reward turn count as a primary metric (today it records model calls + wall-clock but not turns): external Cowork calls, host model turns, internal graph calls, native tool calls, decision depth, time-to-first-progress, time-to-final-answer, citation/coverage/conciseness. Stand up the already-committed monitoring stack on preprod so we can tell whether a bet survives real traffic.

Open decisions

  1. worker-research as a new domain worker vs reusing the worker-automations headless-agent chassis. (Lean new worker per the domain rule; confirm.)
  2. MCP Tasks vs a bespoke durable start/status/result/cancel lifecycle. (Lean bespoke-durable first; add MCP Tasks once Cowork capability is verified.)
  3. Report-back channel priority: desktop/Polaris notification vs surfacing on next chat turn vs a North-side task record. (Lean all three off the one clicky.events completion event.)
  4. Default budget ceiling per research job (matters × docs × model calls) and per-org fairness.