diff --git a/agent/.agents/skills/impl/SKILL.md b/agent/.agents/skills/impl/SKILL.md new file mode 100644 index 0000000..fe3f70f --- /dev/null +++ b/agent/.agents/skills/impl/SKILL.md @@ -0,0 +1,193 @@ +--- +name: impl +description: Polish and expand the relevant feature specs first, then implement one phase of the project impl plan end-to-end with high quality bars (correctness, elegance, performance), and run an independent code review against the polished specs before declaring done. Use whenever the user says "build phase N", "implement the next phase", "land M0/M1/M2/M3", "follow the impl plan", "ship phase X entirely", "based on specs think ultra hard and build phase X", or asks for a phase-shaped slice of the spec set. Trigger even when the user does not say "impl" if they reference an impl plan / roadmap milestone and ask Codex to build it. +--- + +# Impl + +Land one phase from the project impl plan to a publishable bar — no TODOs, no half-finished modules, no quality-gate bypasses — then run a thorough independent review against the polished specs and fix every valid finding before claiming done. Before writing implementation code, expand and polish the relevant feature specs until they are detailed, concrete, internally consistent, and executable by another engineer. The phase is the unit of completion; partial phases create drift the spec set is meant to prevent. + +## When this fires + +- "build phase N entirely" / "implement phase N" / "land M" +- "based on the impl plan and other specs in `./specs`, follow `@AGENTS.md`, think ultra hard, build phase X" +- "previous phases are done — continue with the next one" +- "ship the spec; one phase at a time" +- The user names a milestone (M0/M1/M2/M3) or a Phase-N task and asks Codex to write the code + +## What this skill is *not* + +- Not for one-off bug fixes or feature requests outside a planned phase. Use direct edits. +- Not for greenfield design work. If `./specs/` is empty or the relevant phase is not specified, hand off to the **spec** skill first. +- Not for prototyping. The quality bar here is "publishable"; throwaway code lives somewhere else. + +## Diagram expectation + +When an implementation phase changes architecture, data flow, processing flow, lifecycle/state transitions, or build/dependency order, update the corresponding spec or research diagrams in the same phase. Use fenced ASCII-style diagrams (` ```text `) with nested boxes or grouped lanes for non-trivial systems, matching the spec/research skill standard. Prefer terminal-safe box-drawing characters (`┌─┐│└┘`, `▼`, `▲`) when they make ownership and runtime boundaries clearer. For request/protocol flows, use vertical lifelines with numbered steps so the ordering is reviewable. Do not leave diagrams as stale prose-adjacent decorations; they must show the real components, channels, storage, external systems, state transitions, and failure/shutdown paths that changed. + +## Workflow + +### 1. Bind the scope + +Resolve which phase to build, exactly: + +- Read the project impl plan and find the requested phase. In this repository, prefer `./specs/delivery/impl-plan.md`; if a project still uses legacy numbered specs, use `./specs/91-impl-plan.md`. If the user named a milestone (M0/M1), translate it via the roadmap (`./specs/delivery/roadmap.md` or legacy `90-roadmap.md`) — milestones and phases pair 1:1 but are numbered differently. +- Read every spec section the phase tasks cite. The impl plan's task table has a "Spec" column for a reason. +- Read `./docs/research/` memos referenced by those specs. Their decisions bind the implementation. +- Read project `AGENTS.md` (and global `~/.codex/AGENTS.md`). Engineering norms (error handling, async, type design, security, logging) apply unconditionally. +- Read `./vendors/` references the spec or research cites — for prior art and exact API shapes. + +If a previous phase is *not* fully landed (per its exit criteria), say so and offer to land it first. Do not paper over a gap by starting later. + +### 2. Polish the specs first + +Before implementation, make the specs good enough that the phase can be built without guessing. This is a hard gate: do not write production code until the relevant feature specs and impl plan are executable. + +- Expand or refine the cited specs under `./specs` before code. If a new spec file is needed, follow the project naming and index rules from `AGENTS.md`, then update `./specs/index.md`. +- Bring the feature spec to implementation depth: intended behavior, public API/CLI/schema/protocol shape, domain invariants, validation rules, error model, persistence/state changes, lifecycle/shutdown behavior, concurrency model, security and trust boundaries, observability/audit/metrics events, performance budgets, compatibility/migration concerns, tests, and exit criteria. +- Keep the impl plan in sync with the polished specs: task rows, dependencies, spec links, quality gates, and phase exit criteria must point at the current design, not stale placeholders. +- Update diagrams whenever architecture, data flow, processing flow, lifecycle/state transitions, dependency order, or failure paths matter. A diagram that cannot guide implementation is not polished. +- Record new or changed architectural decisions in the key-decisions spec (`./specs/foundation/key-decisions-log.md` in this repository, or the project's canonical equivalent). +- If the spec gap requires a product or architecture decision that cannot be inferred from existing specs, research, or code, ask the user before writing code. +- If the requested phase is already well specified, state that briefly and proceed; do not rewrite specs for churn. + +Spec polish is complete only when another engineer could implement the phase from the docs without this conversation. If that is not true, keep polishing. + +### 3. Plan the phase + +Before code: + +- Write a TaskCreate entry per row in the phase's task table. Status starts pending; mark in_progress one at a time. +- Identify any task that still has unresolved dependencies on specs or research after the polish pass. If anything is unclear, ask the user **before writing code**, not after. +- Check the phase's exit criteria. Those are the conditions for "done"; if you cannot articulate them now, you cannot meet them later. + +### 4. Implement, task by task + +- Work through tasks in the order the impl plan lists them. The order is dependency-correct; deviating without reason invites retrofits. +- For each task: smallest reasonable PR-shaped commit; passing tests local to that change; no `TODO` / `raise NotImplementedError` stubs / `pass # placeholder` bodies / `# noqa` or `# type: ignore` suppressions introduced to silence a gate. +- **Match the polished specs exactly.** If you find yourself diverging — wrong API name, different invariant, different envelope shape — stop. Either the spec is wrong (update the spec first when the correction is in-phase and unambiguous; otherwise record it in the project's deferred-findings spec — see § "Deferred-findings backlog" below — and get the user's call), or your reading is. Drift kills spec sets. +- Make illegal states unrepresentable. If the spec lists invariants, encode them in types — frozen `@dataclass` value objects, `NewType`, `Enum` / `Literal` unions, `Protocol` interfaces, `Final` constants, and validated constructors (`__post_init__` or pydantic models at trust boundaries) that refuse to build invalid values. +- Performance budgets in the spec are not aspirational. If the phase task table cites a budget, write the bench (`pytest-benchmark`) and run it before claiming the task complete. + +### 4a. Python engineering norms (binding — anchor: AGENTS.md) + +Project `AGENTS.md` and `~/.codex/AGENTS.md` define the binding Python norms for this codebase — error model, async/concurrency patterns, type design, safety/security rules, serialization shapes, testing conventions, observability, performance, dependencies, code style. **Read both before writing code in this phase** and apply every applicable section unconditionally; they are not aspirational. + +Do not paraphrase AGENTS.md here — it is already loaded into your context. Open it, follow it. The recurring high-leverage sections in order: *Error Handling*, *Async & Concurrency*, *Type Design & API*, *Safety & Security*, *Serialization*, *Testing*, *Logging & Observability*, *Performance*, *Dependencies*, *Code Style*. + +If a spec for this phase silently relaxes an AGENTS.md rule, the spec is wrong: record it in the deferred-findings backlog and raise it before writing code. If you genuinely need to deviate at a specific call site (e.g. a single `# type: ignore[override]` or `# noqa: `), the suppression must carry the specific error code, and the commit message must name the `file:line` and the reason — reviewers will check. Bare, code-less suppressions are never acceptable. + +### 5. Run the standard quality gates + +After the spec polish pass, run text checks relevant to the changed docs (`git diff --check`, targeted link/index checks, and any project doc checks). After each meaningful implementation task and again before claiming the phase complete: + +```bash +uv sync --all-extras # or the project's documented env bootstrap +uv run ruff format --check . +uv run ruff check . +uv run mypy --strict src tests # or pyright, per project config — never both loosened +uv run pytest -q # full suite, warnings-as-errors per project config +``` + +Type checking in `--strict` mode (or the project's configured equivalent) catches API drift and `None`-handling bugs — cheap to enforce, easy to let rot if you skip it. + +For boundary modules and any code touching external input, also: + +```bash +uv run bandit -r src -ll +uv run ruff check --select S,BLE,TRY,DTZ,PTH . +uv run pytest tests/ -q -W error +``` + +If the phase introduces dependencies, run: + +```bash +uv lock --check +uv run pip-audit +``` + +If the project has a `Makefile` with these gates wired (`make check` / `make ci`), prefer that — keeps the gates discoverable. + +**Never** bypass a gate (`--no-verify`, blanket `# noqa` / `# type: ignore`, `@pytest.mark.skip` added to make CI green, deleting a failing test). If a gate fails, fix the underlying cause. + +### 6. Verify exit criteria + +The phase has explicit exit criteria in the impl plan. Each one is observable: a test passes, a bench fits a budget, a behaviour can be demonstrated. Show evidence for each — paste the green output, the bench number, or a one-line repro. "Looks done" is not done. + +If a phase exit criterion is *blocked* by something the user must decide (a credential, a third-party endpoint), say so explicitly and stop. Do not claim done. + +### 7. Commit + +Stage with named paths (never `git add -A`). One commit, or a small ordered series; either way the message names the phase and the milestone: + +``` +phase : + + + + +``` + +### 8. Independent code review + +This is the load-bearing step. The phase is **not done** until reviewed against the spec and the valid findings fixed. + +- Spawn a code-review subagent (`Agent` tool) with `subagent_type: "general-purpose"` (or a project-specific reviewer if one is configured). Brief the agent like a colleague who hasn't seen this conversation: + + > Review the diff for phase `` against the polished specs under `./specs/` and `./docs/research/`. The phase is supposed to deliver ``. The senior architect persona expects: spec adherence (concrete, correct, elegant, performant); AGENTS.md compliance (error handling, async, type design, safety/security); no TODOs / dead code / silent fallbacks; matching invariants between polished spec and code; tests covering the phase's exit criteria. Cite findings as `path:LINE` with severity P0/P1/P2/P3 and a recommended fix shape. Do not propose redesigns; defer those to the project's deferred-findings backlog spec. + +- The agent runs read-only and produces a finding list. Read it carefully. + +- Categorise findings: + - **Valid + in-phase** — fix in this phase before claiming done. + - **Valid + out-of-phase** — append to the deferred-findings backlog spec (see below) with severity, file:line, and fix shape. Do not silently inflate scope. + - **Invalid** — note why in the response so the user can sanity-check the call. + +- Fix the in-phase findings. Re-run quality gates. If a fix is non-trivial, commit separately ("phase N review: fix ") so history shows the review pass. + +- If a finding reveals a **spec defect** (the spec is wrong, not the code), record it in the deferred-findings backlog and surface it to the user before patching either side. Spec drift here is exactly what the spec set exists to prevent. + +#### Deferred-findings backlog + +Out-of-phase findings, deferred items, and surfaced spec defects need a single home so they don't get lost. Where this lives is a project choice — the obs project uses `./specs/93-improvements-review.md`, but any single Markdown file under `./specs/` (or wherever the project's `AGENTS.md` directs) works as long as it is the *one* canonical location for the team. If the project does not yet have one, create it and note in the commit message; if it does, append. Each entry should include severity (P0/P1/P2/P3), `file:line` citation, and a one-line fix shape so the next phase can pick it up without re-deriving the context. + +### 9. Hand off + +Final report to the user, in this shape: + +- **Phase**: N — ``. +- **Specs polished/covered**: ``. +- **Exit criteria**: each criterion with `✅` + evidence (test name, bench number, command output). +- **Files changed**: high-level summary, not a file list. +- **Review**: number of findings, P0/P1 fixed in this phase, P2/P3 deferred to `93` with citations. +- **Next phase**: which phase is unlocked, what its first task is. + +## Quality bar + +- Spec adherence is binary, not "mostly". Either the API matches and the invariants hold, or you stop and reconcile spec ↔ code in writing. +- Specs are part of the deliverable. A phase cannot be publishable if the relevant specs are vague, stale, or missing exit criteria. +- No `TODO`, `raise NotImplementedError("later")`, `pass # stub`, or `...` placeholder bodies in production code. If a piece of work cannot be completed in this phase, it does not belong in this phase — defer via a deferred-findings entry. +- No dead code or blanket suppressions. If something is unused, remove it; if a suppression is unavoidable, it carries a specific error code and a `file:line` justification in the commit. +- Tests are part of the deliverable, not an afterthought. Each public surface introduced has at least one happy-path test and one error-path test; load-bearing invariants get property tests (`hypothesis`) where the shape allows. +- Bench harnesses (`pytest-benchmark`) ship alongside any task with a perf budget; CI gates the regression. +- Every public module, class, and function has a docstring; the module has a top-level docstring; doctest examples (where used) run green under the test suite. +- Every function signature on a public surface is fully type-annotated; `Any` at a boundary is a finding, not a convenience. + +## Common failure modes (avoid) + +- **"Phase done" with the review skipped.** The review is the load-bearing checkpoint. Always run it. +- **Starting code from underspecified docs.** Polish the specs first. If the implementation requires guessing, the spec is not ready. +- **Refactor smear.** Touching files outside the phase's scope. Resist; defer to `93` and keep the diff focused. +- **`except Exception: pass` in a "non-critical" path.** All paths reachable from external input are critical. Catch the narrowest exception type, handle it or re-raise with context (`raise NewError(...) from exc`); never swallow. +- **Mutable default arguments and shared module-level state.** `def f(items=[])` and module-global caches are latent bugs; use `None` sentinels, factories, or explicit dependency injection. +- **Blocking calls inside `async def`** (the project's AGENTS.md is explicit on this — follow it): no synchronous I/O, `time.sleep`, or CPU-heavy loops on the event loop; use the async client, `asyncio.to_thread`, or a worker pool. +- **Adding features the spec did not request.** If it's not in the spec for this phase, it is out of scope. Either update the spec first or land later. +- **Skipping `ruff format --check` and `mypy --strict`.** Both are required gates per the project policy; an unformatted or untyped diff is not reviewable. +- **`git reset --hard` to recover from confusion.** Never. Investigate; ask the user; preserve work. The git reflog is your friend. + +## Cross-references + +- The **spec** skill produces and refines the spec set; this skill polishes the relevant specs before consuming them for implementation. +- The **research** skill produces `./docs/research/-*.md`; this skill respects their decisions. +- The project's deferred-findings backlog spec under `./specs/` (whatever the project names it; obs uses `93-improvements-review.md`) is the single home for findings deferred out of the current phase. +- `./specs/99-key-decisions.md` is the canonical record of *why*; if your code conflicts with a decision there, escalate to the user before writing. diff --git a/agent/.agents/skills/impl/agents/openai.yaml b/agent/.agents/skills/impl/agents/openai.yaml new file mode 100644 index 0000000..4131d14 --- /dev/null +++ b/agent/.agents/skills/impl/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Impl" + short_description: "Polish specs, then implement and review one phase" + default_prompt: "Use the impl skill to polish the relevant specs until implementation-ready, land the requested implementation-plan phase end-to-end, run quality gates, review the diff, and fix valid findings." diff --git a/agent/.agents/skills/research/SKILL.md b/agent/.agents/skills/research/SKILL.md new file mode 100644 index 0000000..a727645 --- /dev/null +++ b/agent/.agents/skills/research/SKILL.md @@ -0,0 +1,211 @@ +--- +name: research +description: Vendor reference repos as git submodules under ./vendors and produce deep research memos under ./docs/research covering architecture, design, key data structures, and load-bearing algorithms. Use whenever the user says "do research on X", "study how Y works", "submodule this repo and look into it", "understand the design of Z before we start", "spike on …", references prior-art crates / repos that should be evaluated, or asks to refer to ./vendors before designing or implementing. Trigger even when the user does not say the word "research" if they paste GitHub URLs and ask Codex to learn from them, compare alternatives, or extract patterns. +--- + +# Research + +Capture prior art with rigour: vendor the upstream code, read it deeply, write a memo that future you (and the spec / impl skills) can rely on. Memos are load-bearing; they pin assumptions before code is written so spec drift and rework do not happen later. + +## When this fires + +- "do deep research on ``" / "study how `` works" +- "submodule `` to `./vendors`" / "vendor `` for reference" +- "before we design X, look into how `` does it" +- "spike on ``" — a single-question, time-boxed memo +- The user pastes GitHub URLs and asks Codex to learn from them +- The spec or impl skill needs prior-art before proceeding and there is no memo yet + +If `./docs/research/` already contains a relevant memo, **read it first** and decide whether to update it instead of writing a new one. Do not duplicate. + +## What to produce + +For each topic, exactly one memo at `./docs/research/-.md` plus an updated `./docs/index.md` (or wherever the project's `AGENTS.md` says research lives). Three memo kinds, picked by intent: + +- **`spike-.md`** — a single, sharp, time-boxed question ("does `ArcSwap>` compose?", "is `linkme` reliable on macOS arm64 release+LTO?"). Validates one assumption with a runnable artefact. ≤ 2 pages. +- **`study-.md`** — a deep-dive into one or more vendored repos ("how `tokio-rs/tracing` resolves dispatcher per call site", "how `defmt` interns log strings", "comparing how `prost` / `quick-protobuf` / `buffa` handle unknown fields"). 3–10 pages, cites file paths and line numbers. +- **`survey-.md`** — pure web / docs research where vendoring is not warranted ("latest `axum` middleware patterns", "current state of Rust async cancellation"). Cite the latest stable version of each source, link to upstream docs / blog posts / RFCs, and note the date — surveys go stale faster than spikes or studies. + +Always pick the narrowest kind that fits; specificity beats breadth. + +### Diagram expectation + +Use fenced ASCII-style diagrams (` ```text `) whenever they materially improve understanding of high-level architecture, data flow, processing flow, component/subsystem relationships, lifecycle/state transitions, or build/dependency order. Diagrams are load-bearing documentation: keep labels precise, show directionality, and place the diagram before the prose that explains it. Prefer terminal-safe text diagrams over Mermaid so specs and research stay readable in terminals, code review, and plain Markdown renderers. Unicode box-drawing characters (`┌─┐│└┘`, `▼`, `▲`) are encouraged when they make the structure clearer. Do not add decorative diagrams that merely repeat a short paragraph. + +For non-trivial studies, use nested boxes or grouped lanes like an architecture chart, not a bare arrow chain. Show module ownership, runtime boundaries, spawned tasks/threads, queues/channels, external systems, storage, and error or shutdown paths where they explain the design. A short arrow chain is acceptable only for a simple linear call path with no meaningful branch or boundary. + +For ordered protocols, request lifecycles, async handoffs, retries, shutdown, or multi-party handshakes, use a sequence-style ASCII diagram with vertical lifelines and numbered steps. Preserve time from top to bottom, name each participant as a column, and label durable state changes, validation, persistence, external calls, and failure branches. + +Example shape: + +```text + ┌──────────────────────────────────┐ + │ Public API / macro entry point │ + │ │ + │ ┌────────────────────────────┐ │ + │ │ Frontend parser / builder │ │ + │ │ - validates shape │ │ + │ │ - interns metadata │ │ + │ └─────────────┬──────────────┘ │ + └────────────────┼─────────────────┘ + │ generated callsite + ┌──────────────────────────────▼──────────────┐ + │ Runtime dispatcher │ + │ - lock-free fast path │ + │ - fallback on disabled subscriber │ + └──────────────┬──────────────────────────────┘ + │ + ┌────────────────────▼────────────┐ ┌──────────────────────┐ + │ Subscriber / sink stack │─────▶│ Output / transport │ + │ - filters │ │ - batching │ + │ - formatting │ │ - backpressure │ + └─────────────────────────────────┘ └──────────────────────┘ +``` + +Sequence-flow shape: + +```text +Client Runtime External Service + │ │ │ + │ 1. Create request context │ │ + │ attach trace id │ │ + │ │ │ + │ 2. Enqueue work ──────────────▶│ │ + │ │ 3. Reserve capacity │ + │ │ record pending state │ + │ │ │ + │ │ 4. Send request ──────────────▶│ + │ │ │ + │ │ 5. Response / error ◀─────────│ + │ │ │ + │ │ 6. Commit, retry, or cancel │ + │ │ according to policy │ + │ │ │ + │ 7. Deliver outcome ◀──────────│ │ + │ │ │ +``` + +## Workflow + +1. **Confirm scope** — Restate in one sentence what question the memo will answer. If it is broad ("how does tracing work"), force it narrower until it names a specific subsystem, decision, or invariant. A memo with no question becomes a wiki page nobody reads. + +2. **Vendor the repo** — for any upstream code that will be cited: + + ```bash + git submodule add vendors/ + git submodule update --init --recursive + ``` + + Pin to a specific commit (`git -C vendors/ rev-parse HEAD`) and record it in the memo. If the user names a tag/branch, check it out before pinning. Vendor whenever you need grep / Read / git-blame access to upstream source; being on crates.io is not a reason to skip vendoring (the obs project vendored `tracing`, `defmt`, and others precisely to read their internals). For pure API browsing without reading internals, `cargo doc --open` is enough. + + For broad studies that compare alternatives, multiple vendored repos in one memo is fine — name each one's pin in the header. + +3. **Read with intent** — open the vendored tree with `Read` / `Grep` / `Explore` agent. Three passes: + + - **Map**: `Cargo.toml`, top-level `lib.rs` / `mod.rs`, README, `ARCHITECTURE.md` if any. Sketch the module graph. + - **Hot path**: trace the most-trafficked code path end-to-end (emit, dispatch, encode, flush…). Note every allocation, lock, and atomic. + - **Edge cases**: panic paths, drop order, async cancellation, FFI boundaries, `unsafe` blocks. These are where the design's assumptions live. + + Rust-specific reading aids when the structure is non-obvious: `cargo doc --document-private-items --no-deps` to see private surfaces, `cargo expand` (in a tiny driver crate) to see what macros generate, `cargo asm` / `cargo-show-asm` for hot-path codegen questions. Use them sparingly — they are tools, not deliverables. + + Quote real `vendors//path/to/file.rs:LINE` citations in the memo so a reader can verify without re-finding the code. + +4. **Validate spikes with running code** — for `spike-*.md`, write a tiny standalone crate under `/tmp/-spikes//`, run it, paste the output. A spike without a runnable artefact is a guess. Bench with `criterion --quick` when latency claims are made. + +5. **Write the memo** using the template below. Keep it terse: a future reader (often the spec skill) wants the **decision** and the **why**, not a tour. + +6. **Wire it in** — append the memo to `./docs/index.md` under a "Research" section (create the file if missing). If the project's AGENTS.md says research goes elsewhere, follow AGENTS.md. + +## Memo template + +Spikes (single-question, time-boxed): + +```markdown +# Spike: + +Status: · Owner: · Date: · Outcome: **** + +## Question + +The spec / design assumption being tested, copied verbatim or with a precise reference. State what fails if this assumption is wrong. + +## Method + +The runnable artefact: crate path, deps + versions resolved, hardware, the exact thing measured. Reproducible in one paragraph. + +## Findings + +Numbered, terse, evidence-backed. Each finding cites `vendors//path:LINE` or pasted output. Use ✅ / ⚠ / ❌ markers for at-a-glance scanning. + +## Decision + +**GO / NO-GO / GO-with-amendments**, plus the *implementation rules* the spec must adopt as a result. This is the load-bearing section. + +## Risks identified + +What could still bite us, with a follow-up plan or a CI gate that pins the assumption regression-tested. +``` + +Studies (broad architectural deep-dive): + +```markdown +# Study: > + +Status: · Owner: · Date: · Vendor pin: `vendors/` @ `` + +## Why this study + +What downstream design / spec / code needs this knowledge. If nothing needs it, do not write it. + +## Architecture map + +Boxed ASCII-style module graph, architecture chart, or sequence-flow diagram where useful. Name the load-bearing types, runtime boundaries, queues/channels, external systems, state transitions, and trait boundaries. + +## Hot path walkthrough + +Trace the dominant code path step by step with `vendors//path:LINE` citations. Call out each allocation, lock, atomic, and async boundary. + +## Key data structures + +For each: shape, invariants, who mutates, who reads, why it was chosen over alternatives. One paragraph each. + +## Key algorithms + +For each: input/output, complexity, correctness argument. Include a small trace example if non-obvious. + +## What we will adopt + +Concrete patterns, types, trait shapes we will copy or adapt. Cite the exact upstream lines. + +## What we will avoid + +Patterns that look attractive but do not fit our constraints, and *why*. Future reviewers will ask; answer once here. + +## Open questions + +Anything that needs a follow-up spike. Each item gets a `spike-.md` filename so it can be picked up later. +``` + +## Quality bar + +- A memo is **done** when a teammate who has not opened the vendored repo can answer the memo's question and cite the upstream lines that justify the answer. +- Every claim about behaviour cites a file path + line number, not a vague reference. +- Every claim about performance has a number with units and the bench harness used. +- **No vendored copy of code in the memo body** — link to `vendors//...:LINE` instead. Quoting is fine for ≤ 5 lines when the structure is the point. +- Do not write TODOs in the memo. If something is unknown, write "open question" + a spike filename so it is tracked, not buried. + +## Anti-patterns + +- A "research doc" that is really a redesign — if you find yourself proposing your own architecture, stop; that belongs in `./specs/`, not `./docs/research/`. +- Vendoring 10 repos and skimming all of them. Pick one, read it deeply, write the memo, then move on. +- Memos that conclude "more investigation needed" without naming what specifically. Always name the next concrete artefact. + +## Hand-off + +When the memo is committed, point the user (and the next skill) to: + +- the memo path, +- the upstream commit pin (for spikes/studies) or sources + date (for surveys), +- the headline takeaway in one sentence — for a spike, the GO/NO-GO decision; for a study, the patterns adopted/avoided; for a survey, the recommended approach. + +The spec skill will cite this memo by path; the impl skill will rely on the decision / patterns. diff --git a/agent/.agents/skills/research/agents/openai.yaml b/agent/.agents/skills/research/agents/openai.yaml new file mode 100644 index 0000000..2e7e154 --- /dev/null +++ b/agent/.agents/skills/research/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Research" + short_description: "Vendor references and write research memos" + default_prompt: "Use the research skill to vendor reference repositories or survey current sources, then produce a concise memo under docs/research." diff --git a/agent/.agents/skills/spec/SKILL.md b/agent/.agents/skills/spec/SKILL.md new file mode 100644 index 0000000..58a3916 --- /dev/null +++ b/agent/.agents/skills/spec/SKILL.md @@ -0,0 +1,397 @@ +--- +name: spec +description: Turn a feature idea or rough requirement into a complete, dependency-ordered spec set under ./specs — PRD, component designs, glossary, security/perf/test cross-cuts, key-decisions log, stakeholder roadmap, and engineer-facing implementation plan — cross-referenced with prior-art memos in ./docs/research and vendored code in ./vendors. Use whenever the user says "write the spec", "design this", "let's plan X", "produce a PRD / impl plan / roadmap", "restructure the specs", "review and re-organise the design", "think ultra hard and split this into phases", or describes a non-trivial system that needs a written design before code. Trigger even when the user does not say "spec" if they ask for phased delivery, milestone exit criteria, or a build-order graph. +--- + +# Spec + +Turn requirements into a load-bearing spec set: numbered, cross-linked, dependency-ordered, with a stakeholder-facing roadmap and an engineer-facing implementation plan that pair 1:1. The spec set is the contract between intent and code; if it is wrong or incoherent, every downstream phase pays for it. + +## When this fires + +- "write the spec / PRD / design / impl plan / roadmap for X" +- "restructure the specs so it can be built incrementally" +- "review the design and add the missing specs" +- "phase this delivery — what lands when?" +- The user describes a system non-trivial enough that ad-hoc coding will produce drift, missing invariants, or unbounded scope +- The research skill has produced memos and the next move is to commit decisions to a spec + +## Output shape + +A directory of numbered Markdown files under `./specs/`. The numbering is the **build order** — reading top-to-bottom matches the milestone progression in the roadmap. Update `./specs/index.md` so a fresh reader can navigate. + +### Diagram expectation + +Use fenced ASCII-style diagrams (` ```text `) whenever they materially improve understanding of high-level architecture, data flow, processing flow, component/subsystem relationships, lifecycle/state transitions, or build/dependency order. Diagrams are part of the spec contract: keep labels precise, show directionality, and put the diagram near the decision it clarifies. Prefer terminal-safe text diagrams over Mermaid so the spec remains readable in terminals, code review, and plain Markdown renderers. Unicode box-drawing characters (`┌─┐│└┘`, `▼`, `▲`) are encouraged when they make the structure clearer. Do not add decorative diagrams that merely restate simple prose. + +For non-trivial systems, the diagram must be structurally rich enough to review: use nested boxes, lanes, or grouped boundaries rather than a bare `A -> B -> C` chain. Show component ownership, trust/runtime boundaries, queues/channels, storage, external services, error paths, and fan-in/fan-out where they matter. A simple arrow chain is acceptable only for a short linear ordering with no meaningful boundary or alternative path. + +For ordered protocols, login flows, request lifecycles, retries, shutdown, or multi-party handshakes, use a sequence-style ASCII diagram with vertical lifelines and numbered steps. Include the actor names as columns, preserve time from top to bottom, and label durable state changes, redirects, validation, token minting, persistence, and failure branches that affect correctness. + +Example shape: + +```text + ┌────────────────────────────────────┐ + │ Public crate API / CLI │ + │ │ + │ ┌──────────────────────────────┐ │ + │ │ Validation boundary │ │ + │ │ - length / range caps │ │ + │ │ - typed domain newtypes │ │ + │ │ - serde deny_unknown_fields │ │ + │ └──────────────┬───────────────┘ │ + │ │ │ + │ ┌──────────────▼───────────────┐ │ + │ │ Domain command / envelope │ │ + │ │ - invariants encoded │ │ + │ │ - thiserror failures │ │ + │ └──────────────┬───────────────┘ │ + └─────────────────┼──────────────────┘ + │ bounded mpsc + ┌────────────────────────────▼───────────┐ ┌────────────────────┐ + │ Actor / state owner │ │ Observability │ + │ - owns mutable state │──▶│ - tracing spans │ + │ - restart / shutdown policy │ │ - redacted fields │ + └──────────────┬─────────────────────────┘ └────────────────────┘ + │ + ┌──────────────▼──────────────┐ + │ Storage / external system │ + │ - timeout / retry budget │ + │ - classified data boundary │ + └─────────────────────────────┘ +``` + +Sequence-flow shape: + +```text +CLI / Client Service Actor External Provider + │ │ │ + │ 1. Build validated request │ │ + │ and correlation id │ │ + │ │ │ + │ 2. Submit command ────────────▶│ │ + │ │ 3. Persist pending state │ + │ │ with TTL / idempotency key │ + │ │ │ + │ │ 4. Call provider ─────────────▶│ + │ │ timeout / retry budget │ + │ │ │ + │ │ 5. Provider response ◀──────── │ + │ │ │ + │ │ 6. Validate + classify result │ + │ │ update durable state │ + │ │ │ + │ 7. Return typed outcome ◀──────│ │ + │ or domain error │ │ + │ │ │ + │ 8. Emit structured span │ │ + │ with redacted fields │ │ +``` + +### Right-size the spec set to the problem + +**The number of files is a function of system complexity, not a template to fill.** Do not generate every slot below just because the layout shows it. A small library might ship as `00-prd.md` + `10-design.md` + `90-roadmap.md` and nothing else; a large multi-crate platform might need every slot plus a few more. Pick the smallest set that captures the load-bearing decisions for *this* system. + +Heuristics for sizing: + +- **Tiny (1–3 files)** — a single-purpose crate, one or two integration points, no novel invariants. Often: PRD + one design doc + a short roadmap. Skip the cross-cuts; their content fits in the design doc. +- **Medium (5–10 files)** — multiple components with non-trivial contracts between them, more than one integration point, real performance or security constraints. PRD + per-component designs + roadmap + impl-plan + glossary if any term is overloaded. Cross-cuts only when their content does not fit cleanly in the component designs. +- **Large (15+ files)** — a platform / SDK with many components, multiple consumers, long-lived contracts, freeze windows, public RFCs. The full canonical layout below earns its keep. + +A good test before adding a file: *what specific question does this file answer that nothing else answers?* If you cannot name one, fold it into the nearest related spec. + +### Canonical layout (illustrative — pick what applies) + +The structure below is the **example layout the obs project ended up with after the system grew** (an observability SDK with ~10 components, hard perf/security budgets, and a public RFC freeze). Treat it as a menu of named slots so files can grow in cleanly later — not a checklist. Omit any slot that does not earn its keep for the current scope; keep the numbering scheme so future additions slot in without renumbering. + +``` +specs/ +├── index.md — table of every spec + reading order + build-order graph +├── 00-prd.md — product requirements (vision, users, goals, non-goals, success metrics) +├── 10-data-model.md — wire shapes, envelope / message / record types, naming conventions +├── 11-runtime-core.md — engine: lifecycle, traits, threading, panic policy +├── 12-.md — additional foundation designs, in dependency order +├── 13-.md +├── 20-.md — outward-facing integrations (transports, sinks, exporters) +├── 30-.md — interop with neighbouring ecosystems +├── 40-.md — middleware / framework adapters +├── 50-cli.md — CLI surface, if any +├── 60-dev-ergonomics.md — what using the SDK feels like; concrete examples; quickstart +├── 61-crates-and-features.md — workspace layout, dependency graph, feature flags +├── 70-security.md — threat model, classification, redaction, secrets +├── 71-performance-budgets.md — P50/P99 targets, bench harness, CI gates +├── 72-testing-strategy.md — test pyramid, fixtures, integration mocks +├── 80-glossary.md — disambiguate overloaded terms +├── 90-roadmap.md — STAKEHOLDER-facing: milestones M0…Mn, exit criteria, calendar shape +├── 91-impl-plan.md — ENGINEER-facing: dependency-ordered phases, effort estimates +├── 92-rfc-.md — public-comment summary at freeze (when applicable) +├── 93-improvements-review.md — (example) deferred-findings backlog spec; impl skill appends to it +└── 99-key-decisions.md — D1…Dn, the *why* behind each load-bearing choice +``` + +Even on a large system, several of these are conditional: `50-cli.md` only if there is a CLI; `30-…` / `40-…` only if there are real interop/middleware surfaces; `92-rfc-*` only at a public freeze; the deferred-findings backlog (named `93-improvements-review.md` in the obs project, but pick whatever name the project prefers) is created on demand by the impl skill, not preemptively. + +Two rules about the roadmap / impl-plan split — they are different documents on purpose: + +- **`90-roadmap.md`** is organised by *user-visible feature*. M0 = "hello world emit", M1 = "schema-first authoring". Stakeholders read this to plan calendars. +- **`91-impl-plan.md`** is organised by *dependency order*. Phase 1 = the spine that nothing else can be built without. Engineers read this to know what to write next, and *why*. + +The two pair 1:1 against milestones but the order and grouping differ. Earlier drafts conflate them; do not. + +## Workflow + +1. **Capture intent** — restate the user's requirement in 1–2 paragraphs: the problem and the vision. Mirror it back before generating files. If the requirement is fuzzy ("we want better observability"), force it concrete (users, top job-to-be-done, the one metric of success). A PRD with no measurable success looks fine and ages badly. + +2. **Read what exists** — before adding files: + - `./specs/index.md` (if present) — what's already designed, what naming is used. + - `./docs/research/` — every memo. Cite their decisions; do not re-litigate. + - `./vendors/` — for prior art the design should align with or deliberately diverge from. Reference `vendors//path:LINE` directly in the spec. + - **`AGENTS.md` (project + user-global)** — engineering norms the spec **must** encode into design decisions, not just respect in spirit. The spec is allowed to set *tighter* rules; it must not silently relax AGENTS.md. See the next subsection for the binding Rust checklist. + +### 2a. Bind Rust engineering norms (anchor: AGENTS.md) + +The spec commits the project to specific Rust patterns up front; the impl skill will then match those patterns line-for-line. Before drafting any component design, **read project `AGENTS.md` and `~/.codex/AGENTS.md`** and encode their norms into the spec text — not as a footnote, not "TBD per coding standards", but as concrete shapes (error types, async surfaces, validation points, lint sets, doc requirements) that a reviewer can mechanically check. + +Do not restate AGENTS.md in the spec; **reference it** ("Errors: per AGENTS.md § Error Handling — `thiserror` enum with `#[source]`"). If a component genuinely needs to deviate, the spec must say "deviates from AGENTS.md § X because …" so reviewers can challenge it. If AGENTS.md is silent on a question the spec must answer, the spec sets the rule and `99-key-decisions.md` records why. + +A component design (`11-…`, `12-…`, …) is not done until each AGENTS.md section relevant to it (Error Handling, Async & Concurrency, Type Design & API, Safety & Security, Serialization, Testing, Logging & Observability, Performance, Documentation) is either pinned by reference or marked "N/A — ". + +3. **Run the research skill if prior art is missing** — if the design hinges on an assumption that has not been validated (a crate works under release+LTO; an API actually composes; a perf budget is achievable), invoke the research skill first. Do not bake unvalidated assumptions into a spec. + +4. **Think ultra hard about phasing** — before writing a single design doc, sketch: + - What is the smallest end-to-end slice a user can run? That is M0. + - What does each subsequent milestone *unlock*? Name it from the user's POV. + - What blocks what? Draw the build-order graph. + - Where architecture, data flow, processing flow, or subsystem relationships are load-bearing, draw a boxed ASCII diagram before writing the prose. + + Two principles that separate good phasing from plausible phasing: + + - **Land contracts before consumers.** If every sink consumes `&dyn EventSchema`, the schema registry lands in the foundation, not alongside the first sink. Otherwise the contract is provisional and gets retrofitted. + - **Pay design costs once, in the foundation.** Multi-tenant observer resolution, security classification, error envelopes, identity / context propagation — adding any of these later is a refactor of every call site. Settle them in the spine even if M0 only uses the trivial case. + +5. **Write the PRD first** (`00-prd.md`). Vision, users, goals (with measurable criteria), non-goals (explicit — non-goals prevent scope creep more than goals do), success metrics, naming conventions that will bind the rest of the spec set. + +6. **Write the data model** (`10-data-model.md`). The wire shape every downstream component sees. Naming, types, invariants, envelope vs payload distinction. Lock this early — drift here cascades. + +7. **Write component designs in build order** (`11-…`, `12-…`, `20-…`, etc.). Each spec ends with a "Cross-references" section pointing to the specs it depends on and the specs that depend on it. Use `[NN-name.md § X](./NN-name.md#x)` link form so jumps work in any markdown viewer. + +8. **Write the cross-cuts** (`60`, `61`, `70`, `71`, `72`). These are read alongside the build-order specs, not in sequence. Make them small and concrete; do not let them become philosophy essays. + +9. **Write the glossary** (`80-glossary.md`). Every overloaded term — span vs scope, sink vs layer, envelope vs event — gets a one-paragraph disambiguation. Cheap, prevents weeks of arguing. + +10. **Write the roadmap and impl-plan together** (`90`, `91`): + - Roadmap has milestones, exit criteria, and a calendar estimate. Calibrate honestly: if the spec's earlier estimate was off by 2×, say so and adjust. + - Impl-plan has Phase 0 (risk retirement), Phase 1 (spine), … Phase N (hardening). Each phase has a numbered task table with spec citations and effort estimates. Each phase has explicit *exit criteria* — a test or invariant that must hold before the next phase starts. + +11. **Write `99-key-decisions.md`** as the spec set stabilises. Each entry: D-id, decision, alternatives considered, the *why*, and a reverse pointer to the spec sections that depend on it. When a future reviewer asks "why this?" — point them here, not to a chat scrollback. + +12. **Update `index.md`** — table of every spec with type + purpose, plus a reading-order list and the build-order graph. The index is the entry point; spend real effort on it. + +## PRD template + +```markdown +# PRD — + +Status: · Owner: · Last updated: + +## 1. Problem + +What is broken today, with concrete evidence (incidents, costs, missing capability). Avoid abstractions; name the failure mode users actually hit. + +## 2. Vision + +What "good" looks like, in one paragraph plus one concrete code / UX example. The example is load-bearing — it pins the ergonomic contract. + +## 3. Goals + +| # | Goal | Measure | +| -- | ---- | ------- | +| G1 | … | … | + +Each goal must have a *measurable* success criterion. "Better DX" is not a goal; "≤ 60 s from cargo install to first event on stdout" is. + +## 4. Non-goals + +Explicit list. Non-goals prevent scope creep more than goals do. + +## 5. Users + +Primary, secondary, anti-personas. What each persona is doing when they reach for the product. + +## 6. Success metrics + +What we will measure post-launch to know we shipped the right thing. + +## 7. Naming conventions (binding) + +Public namespaces, prefixes, file layouts that the rest of the spec set must honour. Lock early; renames are expensive. +``` + +## Component design template + +```markdown +# -: + +Status: · Owner: · Depends on: + +## 1. Purpose + +One paragraph: what this subsystem owns, what it does not own, why it exists separately. + +## 2. Interface + +The public types / traits / functions / wire shapes. Code-shaped where possible. + +## 2a. Architecture / flow diagrams + +Add concise boxed ASCII-style diagrams for any non-trivial component boundary, data flow, processing pipeline, state transition, or dependency relationship this subsystem owns. Prefer diagrams with enough structure to expose reviewable decisions: nested boxes for components and ownership boundaries, labeled arrows for message/data movement, and side branches for failures, retries, shutdown, or backpressure. Use sequence-style lifelines for ordered request/protocol flows where the exact step order is the contract. + +## 3. Invariants + +The properties that must hold at every observable point. Each invariant has a test or lint that pins it. + +## 4. Behaviour + +The non-trivial cases — error paths, edge cases, concurrent / async behaviour, drop order, panic policy, cancellation. + +## 5. Cross-references + +- ← Depends on: +- → Consumed by: +- ↔ Related research: +``` + +## Roadmap template (`90-roadmap.md`) + +(Templates below use 4-backtick outer fences so the inner triple-backtick blocks render correctly when copied; CommonMark allows fences to nest as long as the outer uses more backticks than any inner block.) + +````markdown +# Roadmap — Incremental Delivery + +## 0. Principles + +- **Always shippable.** Every milestone leaves the workspace green on the standard quality gates. +- **Type-safety / contract-safety first.** Each milestone may defer features but never relaxes guarantees. +- **Honest calibration.** Estimates are realistic; pad explicitly for review/on-call/meeting overhead. + +## 1. Build-order graph + +```text +┌──────────┐ ┌────────────────┐ ┌────────────────────┐ +│ 00 PRD │───▶│ 10 Data Model │───▶│ 11 Runtime Core │ +│ goals │ │ invariants │ │ lifecycle / traits │ +└──────────┘ └───────┬────────┘ └─────────┬──────────┘ + │ │ + ▼ ▼ + ┌────────────────┐ ┌────────────────────┐ + │ 12 Foundation │───▶│ 20 Integration │ + │ contracts │ │ transport / sink │ + └───────┬────────┘ └─────────┬──────────┘ + │ │ + ▼ ▼ + ┌────────────────┐ ┌────────────────────┐ + │ 60/61 DX │ │ 70/71/72 Gates │ + │ crates/features│ │ security/perf/test │ + └────────────────┘ └────────────────────┘ +``` + +## 2. Milestones + +### M0 — + +**Specs touched**: 00, 10, 11, 12. +**Exit criteria**: a fresh user can in