Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions .agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ This decides where things go, so it is worth getting right:
| Repo-root stub (tools / humans) | [`AGENTS.md`](../AGENTS.md) → this README |
| Verify each step (gates) | [`skills/verify-after-each-step`](skills/verify-after-each-step/SKILL.md) |
| Docs governance, comparison claims | [`skills/docs-governance`](skills/docs-governance/SKILL.md) |
| Docs drift audit and factual refresh | [`skills/docs-sync`](skills/docs-sync/SKILL.md) |
| Docs-site voice and build order | [`skills/docs-voice`](skills/docs-voice/SKILL.md) |
| Past corrections | [`lessons.md`](lessons.md) |
| Writing style (every prose surface) | [`skills/unslop`](skills/unslop/SKILL.md) |
Expand Down
65 changes: 37 additions & 28 deletions .agents/skills/docs-governance/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
---
name: docs-governance
description: Doc lanes for this repo. Use when creating or editing README.md, docs/roadmap.md, CHANGELOG.md, COMPARISON.md, a package README, a changeset, or any file under .agents/; each doc has one job and content never gets copied between them.
description: Doc lanes for this repo. Use when creating or editing README.md, docs/roadmap.md, CHANGELOG.md, the comparison sources, a package README, a changeset, or any file under .agents/; each doc has one job and content never gets copied between them.
---

# Docs governance

Each doc has exactly one job, keep content in its lane:

| File | Is for | Never contains |
| ------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `README.md` | Repo map: the two packages, where to work, the gates, doc links | Install, config or usage sections; version history; roadmap; internal rationale |
| `packages/pi/README.md` | The adapter's npm landing: what it does, install, commands, config pointers | Version history, roadmap, repo map, engine internals |
| `packages/*/CHANGELOG.md` | Each package's version history, written by changesets | Marketing prose, roadmap |
| `apps/docs/COMPARISON.md` | Peer comparison with verified cells, the source the site's comparison page generates from | Feature marketing |
| `packages/core/README.md` | The engine's API: the entry, the two ports, the boundary rule | Pi-specific behaviour, the split's rationale |
| `docs/roadmap.md` | Forward-looking work, evidence gates, rejected items | Shipped-feature history |
| `.agents/**` | Agent rules, skills, lessons | Product docs |
| File | Is for | Never contains |
| ----------------------------------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `README.md` | Repo map: the three packages, where to work, the gates, doc links | Install, config or usage sections; version history; roadmap; internal rationale |
| `packages/pi/README.md` | The adapter's npm landing: what it does, install, commands, config pointers | Version history, roadmap, repo map, engine internals |
| `packages/opencode/README.md` | The OpenCode adapter's npm landing: what it does, install, commands, tools, live loop | Version history, roadmap, repo map, engine internals |
| `packages/*/CHANGELOG.md` | Each package's version history, written by changesets | Marketing prose, roadmap |
| `apps/docs/content/reference/pi/comparison.mdx` | Audited Pi peer comparison; the page and the source are one file | Feature marketing, unverified cells |
| `apps/docs/content/reference/opencode/comparison.mdx` | Audited OpenCode v2 peer comparison; the page and the source are one file | Feature marketing, unverified cells |
| `apps/docs/content/_snippets/**` | Shared Markdown or MDX fragments, spliced into the per-harness wrapper pages with `<include>` | Frontmatter, a second full copy of a page, or the other harness's content |
| `packages/core/README.md` | The engine's API: the entry, the two ports, the boundary rule | Pi-specific behaviour, the split's rationale |
| `docs/roadmap.md` | Forward-looking work, evidence gates, rejected items | Shipped-feature history |
| `.agents/**` | Agent rules, skills, lessons | Product docs |

## Rules

1. **Never duplicate content across these docs**, package READMEs included, link
instead.
instead. The per-harness guide and reference pages are the one exception in
form, not in content: `apps/docs/content/_snippets/**` holds the shared
fragments, plus one partial per harness where the page differs. The wrappers
under `apps/docs/content/{guides,reference}/{pi,opencode}/*.mdx` hold
frontmatter and `<include>` statements only. Edit the snippet, never the
wrapper body.
2. **Version bumps flow through changesets**, run `bun run changeset` with
your change; `bun run version` generates the CHANGELOG entry. Every changeset
names the package it bumps in the frontmatter, the engine included: both
packages publish, so both take changesets. Never hand-bump `package.json`
names the package it bumps in the frontmatter, the engine included: all
three packages publish, so all three take changesets. Never hand-bump `package.json`
version for shipped work. The generator in
`.changeset/config.json` must stay `@changesets/cli/changelog`: the
`changelog-github` generator aborts `bun run version` without a
Expand All @@ -39,31 +47,32 @@ Each doc has exactly one job, keep content in its lane:
never cut. `apps/docs` is private and ships nothing to npm, so a site-only
change takes no changeset.
3. **Comparison claims are verified against tarballs, dated, and peer-named
only in `COMPARISON.md`.** Check a peer package against its published
only in the comparison sources.** Check a peer package against its published
tarball and npm metadata (`npm view <pkg> peerDependencies dependencies
time.modified`), never against its README, and stamp `COMPARISON.md` with
time.modified`), never against its README, and stamp each source with
"Last verified: …" before treating a cell as settled. Credit a peer's win in
the cell: a comparison that shows only our wins is marketing.
Peer package names appear in `COMPARISON.md` and in the page generated
from it (`apps/docs/content/reference/comparison.mdx`, written by
`apps/docs/scripts/build-comparison.ts`), and nowhere else in this repo or
on the site (owner policy). The generated page restates no cell
and is never hand-edited: `COMPARISON.md` is the only writer's source. There
are no inspiration credits: the design cites the LCM paper (algorithmic
Peer package names appear in
`apps/docs/content/reference/{pi,opencode}/comparison.mdx`, and nowhere else
in this repo or on the site (owner policy). Those two pages are both the
audited source and the rendered page: edit a cell there, with its
verification note and date, never in a second copy. There are no inspiration
credits: the design cites the LCM paper (algorithmic
spec) and the smart-zone framing (Matt Pocock) only, because the code is an
original implementation. The docs site carries no credit line; a concept page
cites the paper where a mechanism comes from, as
[how it works](../../../apps/docs/content/concepts/how-it-works.mdx) does.
Attribution lives in `packages/*/README.md`, `apps/docs/COMPARISON.md`, and
Attribution lives in `packages/*/README.md`, the comparison sources, and
the licence preamble (owner decision).
`COMPARISON.md` is not a spec: a design decision cites a paper section or a
The comparison sources are not a spec: a design decision cites a paper section or a
measured result, never a comparison cell, and a cell that scores a
mechanism as a peer's cost is not a reason to lack it.
4. **Each published package owns its landing docs.** `packages/pi/README.md` is
the landing npm shows, `packages/pi/CHANGELOG.md` is the version history
changesets writes in place, and `packages/pi/LICENSE` is a copy of the root
licence. The comparison lives beside the docs site (`apps/docs/COMPARISON.md`)
and generates the site's comparison page, so the tarball no longer ships it. The
4. **Each published package owns its landing docs.** `packages/<name>/README.md` is
the landing npm shows, `packages/<name>/CHANGELOG.md` is the version history
changesets writes in place, and `packages/<name>/LICENSE` is a copy of the root
licence. The comparisons live in
`apps/docs/content/reference/{pi,opencode}/comparison.mdx`, so the tarball
no longer ships them. The
holder named there is the org brand, `stainless-code`, as in every other
stainless-code package, never a personal name. npm
always includes `README` and `LICENSE` from the package directory, so the
Expand Down
51 changes: 51 additions & 0 deletions .agents/skills/docs-sync/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
name: docs-sync
description: Audit documentation against shipped behavior and update only factually stale pages. Use after a release or a command, config, CLI, API, default, path, or workflow change; when asked to check docs for drift, refresh stale docs, or run a scheduled docs audit.
---

# Docs sync

Keep `apps/docs`, the package READMEs, and the root docs true to what shipped. This is maintenance, not authorship: find claims the code no longer supports, fix exactly those, and verify the docs site. [`docs-governance`](../docs-governance/SKILL.md) owns which doc holds what; [`docs-voice`](../docs-voice/SKILL.md) owns voice, anchors, and the site build order.

## Ground rules

- Document only behavior that is in the repository now. Work behind a disabled flag is not public documentation.
- Facts over polish: a wrong default, flag, path, version, limit, provider, or required step is a docs bug; a wording preference is not.
- Copy exact identifiers and values from code. Do not paraphrase a command, key, default, or environment variable.
- Touch the fewest pages that remove the drift. Preserve the surrounding structure, components, and anchors.
- Do not edit generated output (`dist/`, `.blume/`). Do not overwrite unrelated local changes.
- A run that finds nothing actionable ends with a short report and no commit.

## Workflow

1. **Set the scope.** Read `AGENTS.md`, [`docs-governance`](../docs-governance/SKILL.md), and [`docs-voice`](../docs-voice/SKILL.md). Honor a lookback window, docs path, or report-only request from the user. With no window, compare against changes since the last docs update or the last stable milestone.
Sources: `git log`, `.changeset/**`, `packages/*/CHANGELOG.md`, package entry points and config schemas, CLI help, environment variables, routes, and the docs under `apps/docs/content/**`, `_snippets/**`, package READMEs, `README.md`, and `docs/roadmap.md`.
Done when every changed public fact has a source and either a docs target or a recorded reason it is internal.

2. **Find drift.** Compare facts, not prose:
- A command, flag, config key, environment variable, route, prop, exported API, default, path, or version changed.
- A shipped capability is absent from the page that should describe it.
- A page promises a provider, adapter, integration, or workflow the code no longer supports.
- A required step disappeared, or an example no longer runs.
- A linked page or heading moved, so the link or anchor is stale.
- An external link the page depends on points at a dead or superseded primary source.
- A release or changeset needs a user-facing entry.

Skip subjective rewording, voice work, speculative future work, duplicated content, and formatting churn. Send wording-only changes through [`docs-voice`](../docs-voice/SKILL.md).

3. **Edit the owning surface.** Update the snippet or source file, never a generated wrapper. Keep package READMEs in their own lane. Do not copy the same fact into several docs; link instead. Preserve published anchors by pinning the old slug when a linked heading must change.

4. **Verify.**
- From the repo root: `vp check`.
- From `apps/docs`: `bun run check --isolated` while a dev server may be running. A missing `GITHUB_TOKEN` warning is an environment warning, not a docs failure; report it as such.
- If the change adds, removes, or renames a page or heading, or changes site navigation, follow the full build, validate, and audit order in [`docs-voice`](../docs-voice/SKILL.md).
- Fix failures caused by this edit. Report pre-existing failures separately.

5. **Deliver.** This repo commits on `main`, one commit per stable milestone, with a changeset for user-visible package change. A report-only audit or a no-op creates no branch and no commit. When edits are needed, make one focused commit and state what was checked, what changed, what was verified, what was skipped, and what risk remains.

## Done means

- Every changed public fact is either corrected in its owning doc or explicitly recorded as internal.
- The diff is the smallest set of factual corrections.
- `vp check` passes and the docs check passes, or the remaining failure is named and shown to predate the edit.
- A no-op run has no edits and reports the areas checked.
21 changes: 11 additions & 10 deletions .agents/skills/docs-voice/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ description: Voice and pipeline for the published docs site (apps/docs): heading

## Surfaces and their modes

| Surface | Mode | Boundary |
| ------------------------------------ | ----------- | ------------------------------------------------------------------------- |
| `pages/_home/*`, `pages/index.astro` | copy | Opinion and pitch are allowed. No claim the page cannot show. |
| `content/concepts/**` | explanation | Opinion allowed. A heading tolerates "About ..." in front. |
| `content/guides/**` | how-to | Commands, conditions, expected output. No teaching. |
| `content/reference/**` | reference | Dry. No "you", no persuasion, spec tables only. |
| `content/reference/comparison.mdx` | generated | Never hand-edited; `apps/docs/COMPARISON.md` is the only writer's source. |
| `content/**/index.mdx` | routing | Help the reader choose, do not summarize. |
| Surface | Mode | Boundary |
| ------------------------------------------------ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pages/_home/*`, `pages/index.astro` | copy | Opinion and pitch are allowed. No claim the page cannot show. |
| `content/concepts/**` | explanation | Opinion allowed. A heading tolerates "About ..." in front. |
| `content/guides/**` | how-to | Commands, conditions, expected output. No teaching. |
| `content/reference/**` | reference | Dry. No "you", no persuasion, spec tables only. |
| `content/reference/{pi,opencode}/comparison.mdx` | reference | Audited peer comparison; the page is the source, so the verification note and date live with the cells. |
| `apps/docs/content/_snippets/**` | source | Shared fragments, plus one partial per harness where the page differs. The wrapper pages under `content/{guides,reference}/` hold frontmatter and includes only. |
| `content/**/index.mdx` | routing | Help the reader choose, do not summarize. |

## Headings carry the point

Expand Down Expand Up @@ -65,8 +66,8 @@ If anything links to it, take the new text and pin the slug.
`blume audit` reads the built `apps/docs/dist`, and an isolated build omits `robots.txt` and `llms.txt`, so an isolated build cannot be audited. A non-isolated build refuses to run while `blume dev` is up.

1. Stop the dev server.
2. From `apps/docs`: `rm -rf dist && bunx blume build`.
3. `bunx blume validate --strict`.
2. From `apps/docs`: `rm -rf dist && bun run build`.
3. `bun run validate --strict`.
4. `bunx blume audit --fail-on error`.
5. Restart `bunx blume dev`.

Expand Down
4 changes: 3 additions & 1 deletion .agents/skills/typescript-best-practices/PATTERNS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ type DiffState = { loading: boolean; diff?: GitDiff; error?: string };

// Do. Only valid states exist.
type DiffState =
{ kind: "loading" } | { kind: "ready"; diff: GitDiff } | { kind: "error"; error: string };
| { kind: "loading" }
| { kind: "ready"; diff: GitDiff }
| { kind: "error"; error: string };
```

Pick one discriminant name (`kind`, `type`, `tag`) and stick to it.
Expand Down
Loading
Loading