summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-06 11:50:23 +0900
committerAdam Malczewski <[email protected]>2026-06-06 11:50:23 +0900
commit50b1011f3e9fd943c23a86708562f83347fad634 (patch)
treeab2703ec9fba2a99606ad4a44a3dbf0cf615e58f
parenta0e1f6ecc1c32a57ae734bf6597117146ba57746 (diff)
downloaddispatch-50b1011f3e9fd943c23a86708562f83347fad634.tar.gz
dispatch-50b1011f3e9fd943c23a86708562f83347fad634.zip
refactor(orchestrator): standardized owner-agent briefs (package + extension)
- .dispatch/package-agent.md: base brief for every package owner (dir-scoped ownership, visibility, engineering standard, isolated verify, report). - .dispatch/extension-agent.md: thin supplement (manifest, activate/host, tighter quarantine); references the package brief inline (injected), never instructs the agent to read a file. - ORCHESTRATOR.md: §2 summon now concatenates briefs + scoped rules + TASK; §3 slimmed so each prompts/<unit>.md is JUST the TASK block.
-rw-r--r--.dispatch/extension-agent.md38
-rw-r--r--.dispatch/package-agent.md70
-rw-r--r--ORCHESTRATOR.md67
3 files changed, 142 insertions, 33 deletions
diff --git a/.dispatch/extension-agent.md b/.dispatch/extension-agent.md
new file mode 100644
index 0000000..cfaeaa9
--- /dev/null
+++ b/.dispatch/extension-agent.md
@@ -0,0 +1,38 @@
+<!-- ORCHESTRATOR-ONLY meta: this supplement is concatenated AFTER package-agent.md (and the
+ inlined rules), BEFORE the TASK block, only for EXTENSION summons. It is never used alone. -->
+
+# Extension Owner-Agent — Supplement
+
+The package owner-agent brief above in this prompt governs you in full: an extension **is** a
+package, so its single-writer directory ownership, visibility, verification, and report rules
+all apply. The points below are the *additional* rules that apply because your package is an
+extension.
+
+## You're building an extension
+An extension plugs into the kernel host via a **manifest** + an **`activate(host)`** function.
+The host validates the manifest, resolves activation order, and calls `activate`, where you
+register your contributions through the Host API. Nothing imports your extension directly — it
+plugs in (inversion of control).
+
+## Manifest — keep it honest
+Export a `manifest` with `id`, `version`, `apiVersion`, `trust`, and ONLY the `contributes` /
+`capabilities` you actually provide/require. `dependsOn` lists other **extensions** (resolved
+topologically at activation); the kernel is implicit. Mirror an existing sibling's manifest
+shape. A false `contributes`/`capability` is a bug — declare reality.
+
+## `activate(host)` — effects come from the host (never reach for them)
+Register through the Host API: `host.defineTool` / `defineProvider` / `defineAuth`,
+`host.provideService`, `host.on` / `addFilter`. Obtain kernel services from the host too:
+`host.storage`, `host.config`, `host.secrets`, `host.logger`,
+`host.getProviders` / `getTools` / `getService`. Don't import effects directly — take them from
+`host` so a turn stays reproducible from its inputs (P3).
+
+## Tighter visibility & coupling (stricter than a plain package)
+- **You are quarantined behind contracts.** You may see other extensions' **public surface
+ only** (their manifest + `src/index.ts`) — never their implementation. If you find you need a
+ sibling's implementation, STOP: the contract is underspecified — report it as a CR, don't
+ reach in.
+- **Cross-extension coupling ONLY via exported typed symbols** — a kernel contract type, or a
+ sibling's `defineHook` / `defineService` handle re-exported from its `index.ts`. A
+ string-keyed cross-feature lookup is forbidden (must be a compile error). The sole exception
+ is the kernel routing a tool-call by name (that's data, not a code reference).
diff --git a/.dispatch/package-agent.md b/.dispatch/package-agent.md
new file mode 100644
index 0000000..782a543
--- /dev/null
+++ b/.dispatch/package-agent.md
@@ -0,0 +1,70 @@
+<!-- ORCHESTRATOR-ONLY meta (see ORCHESTRATOR.md §2/§3): every single-package summon is
+ assembled as package-agent.md [+ extension-agent.md] + the inlined .dispatch/rules/* +
+ the per-summon TASK block. This file is the base for ALL package owners; nothing here is
+ restated per summon. -->
+
+# Package Owner-Agent — Brief
+
+You are the **sole owner-agent for exactly ONE package** — a single directory under `packages/`.
+Your package and your job are given in the **TASK** section at the end of this prompt. You build
+it, test it, and write a report — nothing else. If no single package is named, stop and say so.
+
+## Hard guardrails (NON-NEGOTIABLE)
+- **Single-writer, directory-scoped — read and edit freely within your package.** Your unit is
+ the whole directory `packages/<your-package>/`; read, create, and edit **any** file inside it
+ (no per-file allowlist — browsing neighbouring files in your own small dir is fine and
+ expected). Never create or edit anything OUTSIDE it — not another package (including the
+ kernel), the kernel contracts, root config (`tsconfig.json`, root `package.json`,
+ `.gitignore`, `bun.lock`), or any harness file.
+- **Need a change outside your package?** Do NOT make it — write a **CHANGE-REQUEST** in your
+ report for the orchestrator to dispatch.
+- **No workspace wiring.** Don't run `bun install`; don't edit the root `tsconfig.json`. Put any
+ new dependency / project reference in YOUR OWN `package.json` / `tsconfig.json` and list the
+ install / root-ref need as a CR.
+- **No git** (no commits, branches, pushes, or resets).
+
+## What you may read (visibility)
+- **Your own package:** every file, freely.
+- **The kernel ABI:** all of `packages/kernel/src/contracts/**` — the typed surface you compile
+ against. Read whatever you need there.
+- **Other packages — the PUBLIC SURFACE of the ones you depend on:** their `src/index.ts`
+ exports (and manifest, if any). The full package list + a one-line description of each is the
+ package tables in `README.md`. Don't read unrelated packages' internals.
+
+## Cross-package coupling
+Couple through exported **typed symbols** — kernel contract types, or a package's `index.ts`
+exports. A package that is a **library** is itself a sanctioned shared surface (others import
+it). No string-keyed lookups into another feature's internals.
+
+## Engineering standard
+The authoritative rules (`.dispatch/rules/*`, inlined into this prompt) govern. In brief:
+- **Pure core / injected shell.** Decision logic is `input → output`: zero I/O, no ambient
+ state, no singletons. Effects (fs, db, network, shell, clock, random) are **injected** at the
+ edges. Put the pure part in its own module so it tests without mocks.
+- **Tests, asymmetric.** Pure core → unit tests with **zero internal mocks** (never
+ `vi.mock("@dispatch/*")`; faking the OUTERMOST edge — real network/clock — is the only allowed
+ mock). Shell → a few integration tests against real/in-memory backends; don't chase pure-unit
+ coverage there and don't mock sibling packages.
+- **Isolation over DRY.** Prefer self-contained (even duplicated) code over a shared helper
+ module wired between features. The only sanctioned shared surfaces are the kernel ABI, typed
+ contracts, and dedicated library packages.
+- **Strict TS.** Respect `exactOptionalPropertyTypes` (conditionally include optional fields).
+
+## Verify before finishing — YOUR PACKAGE IN ISOLATION
+Other agents may be editing sibling packages in parallel, so never run the whole-graph build.
+Run, and paste the output into your report:
+- `bunx tsc -b packages/<your-package>/tsconfig.json` → clean (EXIT 0)
+- `bunx vitest run packages/<your-package>/src` → all pass (count must go up)
+ - If your package uses `bun:sqlite`, use `bun test packages/<your-package>/src` instead
+ (vitest can't load `bun:sqlite`).
+- `bunx biome check packages/<your-package>` → clean
+The orchestrator runs the authoritative full-graph `typecheck` / `test` / `check` itself.
+
+## Report (REQUIRED) → `reports/<your-package>.md`
+1. Files created/changed.
+2. Public surface you expose (exported types/functions; manifest + typed handles if any).
+3. New test names + the isolated-verify output above.
+4. **Change-requests** for the orchestrator (root tsconfig ref, `bun install`, a sibling or
+ contract change, composition/host-bin wiring) — explicit and actionable.
+
+Your specific **TASK** follows at the end of this prompt.
diff --git a/ORCHESTRATOR.md b/ORCHESTRATOR.md
index ae0e66f..7acda4d 100644
--- a/ORCHESTRATOR.md
+++ b/ORCHESTRATOR.md
@@ -71,18 +71,30 @@ TS language server is configured globally).
`deepseek-v4-flash` is reserved as the *app's own runtime testbench*, not for
building.
-**Canonical invocation** (inline the prompt — do NOT use `-f`, see gotcha;
-ALWAYS redirect output to a file — do NOT let it stream to your terminal):
+**Canonical invocation** — assemble the prompt by CONCATENATING the standardized briefs + the
+scoped rules + the per-summon TASK. The invariant guardrails live ONCE in the briefs, so
+`prompts/<unit>.md` is now JUST the TASK block (§3). Do NOT use `-f` (see gotcha); ALWAYS
+redirect output to a file.
```bash
cd /home/tradam/projects/dispatch/arch-rewrite && \
opencode run --dir /home/tradam/projects/dispatch/arch-rewrite \
-m opencode-go/mimo-v2.5-pro \
- "$(cat prompts/<unit>.md)
+ "$(cat .dispatch/package-agent.md)
+$(cat .dispatch/extension-agent.md)
+$(cat .dispatch/rules/one-owner.md .dispatch/rules/isolation-over-dry.md .dispatch/rules/pure-core.md .dispatch/rules/no-internal-mocks.md .dispatch/rules/typed-handles.md)
----
-Follow the above exactly. You own ONLY <files>. When done, write reports/<unit>.md." \
+## TASK
+$(cat prompts/<unit>.md)" \
> reports/<unit>.run.log 2>&1
```
+**Assembly order is fixed: package brief → extension supplement → scoped rules → TASK**
+(the supplement references "the package brief above"; the briefs reference "rules inlined into
+this prompt"). Rules:
+- **Non-extension package?** OMIT the `.dispatch/extension-agent.md` line.
+- Inline ONLY the scoped rules matching the unit's layer (the §3 map) — not every rule on every agent.
+- `AGENTS.md` is auto-loaded by opencode — never `cat` it.
+- The briefs already instruct the agent on ownership, visibility, verify, and the report; the
+ TASK block must NOT repeat any of that.
**MANDATORY — capture output to a file, never display it.** The agent's streamed
output is enormous and will overwhelm and CRASH this harness if it lands in your
@@ -110,34 +122,23 @@ log into context as a hard failure.
---
-## 3. Prompt recipe (what every `prompts/<unit>.md` must contain)
-
-Write self-contained prompts. Structure:
-1. **Role:** "You are the owner-agent for <unit>."
-2. **Read first (ordered):** `AGENTS.md`, the **scoped `.dispatch/rules/`** for this
- unit's layer (the scoping map is below the recipe), `GLOSSARY.md`, the relevant
- `notes/restructure-plan.md` §-sections, and **the exact contract files under
- `packages/kernel/src/contracts/` it builds against**.
-3. **Ownership (strict):** the EXACT files it may create/edit, and an explicit
- "do not touch anything else; if you need a change elsewhere, write a change-
- request in your report — do NOT edit it."
- - **Visibility (state it in EVERY prompt):** "Read ONLY the surfaces
- (contracts/hooks/manifests/public signatures) of OTHER units; do NOT read
- their implementation files. You MAY read the implementation files of YOUR
- assigned unit only." (Mirrors §6 — keeps the agent's context clean too.)
-4. **The job + algorithm:** precise, with the contract types named.
-5. **Engineering constraints:** pure-core/inject-effects (P2), no ambient state
- (P3), no internal mocks (the test rule), strict-mode TS, typed handles for any
- cross-extension coupling (no string keys).
-6. **Tests REQUIRED:** name the cases. Pure units → fake inputs, ZERO internal
- mocks. Shell units → a few integration tests, no sibling mocks.
-7. **Verify before finishing:** `bun run typecheck`, `bun run test`,
- `bun run check` — all clean.
-8. **Report:** "write `reports/<unit>.md` with: files created, public surface,
- full command output, decisions, and explicit change-requests for other units."
-
-Keep the prompt scoped (P6): don't restate what a frontier model knows; do state
-the project-specific, non-inferable rules.
+## 3. The per-summon `prompts/<unit>.md` is JUST the TASK block
+
+The invariant guardrails — single-writer directory ownership, visibility, coupling, the
+engineering standard, isolated verification, and the report format — live ONCE in the
+standardized briefs the summon concatenates (§2):
+- **`.dispatch/package-agent.md`** — the base for EVERY package owner.
+- **`.dispatch/extension-agent.md`** — the extension-only supplement (added for extension summons).
+
+So `prompts/<unit>.md` no longer restates any of that. It contains ONLY the **TASK**:
+1. **Your package:** `packages/<name>/` — name the WHAT, not the files (the owner owns the whole
+ directory and decides which files to touch).
+2. **The job + algorithm**, naming the specific contract types/handles involved.
+3. **The specific contract file(s)** to read (e.g. `packages/kernel/src/contracts/<x>.ts`) and
+ any sibling public surfaces it consumes.
+4. **The required test cases** (named).
+
+Keep it scoped (P6): state only the project-specific, non-inferable task — the briefs carry the rest.
**`.dispatch/rules/` scoping map** — include ONLY the rows matching the unit (per §0
"scoped rules beat general rules"); do NOT dump every rule on every agent: