Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Describe the documentation change and its source evidence.

- [ ] I followed [CLAUDE.md](../CLAUDE.md) and [STE.md](../STE.md).
- [ ] I checked new or changed behavior against product source.
- [ ] I defined new technical terms in the internal registry and on their canonical pages.
- [ ] `pnpm build` passes, including prose checks and checker tests.
- [ ] I read the rendered pages and their Markdown twins.

A maintainer must review the current commit against ASD-STE100 Issue 9, then approve with `STE review complete` in the review body. Passing automation alone does not establish compliance.
29 changes: 29 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Documentation

on:
pull_request:
push:
branches: [main]
merge_group:

permissions:
contents: read

concurrency:
group: docs-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
docs-checks:
name: Docs checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '22'
cache: pnpm
- run: pnpm install --frozen-lockfile
# Build includes prose checks, term registry validation, and checker tests.
- run: pnpm build
50 changes: 50 additions & 0 deletions .github/workflows/ste-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: STE editorial review

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
pull_request_review:
types: [submitted, edited, dismissed]

permissions:
contents: read
pull-requests: read

concurrency:
group: ste-review-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
editorial-review:
name: STE editorial review
runs-on: ubuntu-latest
steps:
# Metadata only: do not check out or execute pull request code here.
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
const { owner, repo } = context.repo;
const pull_number = context.payload.pull_request.number;
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
const reviews = await github.paginate(github.rest.pulls.listReviews, {
owner, repo, pull_number, per_page: 100,
});
const latest = new Map();
for (const review of reviews.sort((a, b) => a.id - b.id)) {
if (['APPROVED', 'CHANGES_REQUESTED', 'DISMISSED'].includes(review.state)) {
latest.set(review.user?.login, review);
}
}
for (const review of latest.values()) {
if (review.state !== 'APPROVED' || review.commit_id !== pr.head.sha) continue;
if (review.user?.type !== 'User' || review.user.login === pr.user.login) continue;
if (!/^STE review complete[.!]?\s*$/m.test(review.body ?? '')) continue;
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
owner, repo, username: review.user.login,
});
if (['admin', 'maintain', 'write'].includes(data.permission)) {
core.info(`STE review accepted from ${review.user.login} for ${pr.head.sha}.`);
return;
}
}
core.setFailed('A maintainer must approve the current commit with "STE review complete" in the review body. See STE.md.');
24 changes: 18 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ User-facing docs for Splits (app.splits.org), built with Vocs. Pages serve **two

## The standard job: update docs for a product PR

Any agent should be able to take a product PR and update these docs without a human review pass. The checklist:
An agent can prepare a complete update from a product PR. A separate STE editorial review is required before merge. The checklist:

1. Read the PR's **code diff**, not its description, and list each user-visible behavior that changed.
2. Find each fact's canonical page (map below, plus `git grep`). Edit only that page; update other pages' links if the fact moved, never restate it.
3. Verify every claim you write against the code (rules below). PR descriptions and existing docs prose are not sources.
4. If a file or heading moves: grep for the old path and old `#anchor`, retarget every inbound link, and update the sidebar in `vocs.config.ts` (URLs derive from file paths under `src/pages/`).
5. Check your work: `node scripts/check-prose.mjs <paths>` (findings are warnings needing judgment, not automatic failures), `pnpm build` (validates every internal link), and read the `.md` twin (`curl localhost:5173/<path>.md`); the twin is what agents consume.
5. Check your work: `pnpm check:docs` (findings fail), `pnpm build` (validates every internal link), and read the `.md` twin (`curl localhost:5173/<path>.md`); the twin is what agents consume.
6. Never commit without explicit approval from the human in the session.

## Accuracy
Expand All @@ -31,6 +31,7 @@ Any agent should be able to take a product PR and update these docs without a hu

| Fact | Canonical home |
| --- | --- |
| Internal terminology reference for authors and checks | `scripts/ste/terms.json` |
| Team definition, creating a team, setup steps | `/teams` |
| Roles, capability matrix, settings visibility, API key scopes, read-only members | `/teams/roles` |
| Recovery, recovery signers, verifying them | `/teams/recovery` |
Expand Down Expand Up @@ -66,7 +67,7 @@ If a change moves a fact's canonical home, update this table in the same PR.
- **"Signing key", not bare "key"**, whenever precision matters (definitions, invariants, table cells). Bare "key" is fine once the page has established context (e.g. within `/members/keys`). A **signer** is always account-relative: a signing key added to an account's signer set. Don't use "signer" for a key that isn't on an account.
- **"the Root" / "the Treasury" in prose; bare "Root" / "Treasury" in table cells.** Table cells carry no leading articles and no explanations; explanations live in surrounding prose.
- **"Wallet" means an external EOA wallet** (recovery wallets, MetaMask, hardware wallets), never a Splits account.
- **Em dashes: never, anywhere.** List items and definition lists use a colon separator (`` `command`: description ``); in prose, a colon, period, comma, semicolon, or parentheses replaces the em dash. The prose linter flags every em dash.
- **Semicolons and em dashes: never in public prose.** List items and definition lists use a colon separator (`` `command`: description ``); in prose, a colon, period, comma, or parentheses replaces the em dash. The prose linter flags every em dash.
- **"Email support"** (no address) is the phrasing for manual/support-gated processes.
- **"Team" → "workspace" rename is planned** in the product. Docs keep saying "team" until the product ships the rename, then migrate in one pass (prose + `/teams/` URLs + section name).

Expand All @@ -75,7 +76,7 @@ If a change moves a fact's canonical home, update this table in the same PR.
- **Facts in declarative present tense; procedures in second person** ("you must be an Owner", "go to…").
- **UI elements in italics**: button and control labels (*Invite member*, *Reset signers*, *Require memos*). **Settings paths with `>`**: Settings > Members. **In-page click chains with `→`**: three dots → *Verify signer*.
- **Bold** for: the term a page defines (first use), negative invariants, and scope names in command lists (**Read** scope).
- **Callouts**: `:::note` sparingly. Beta features get exactly: "This feature is in beta. Email support to enable it for your team."
- **Callouts**: `:::note` sparingly. For beta features, put "This feature is in beta." in the note. Put "Email support to enable it for your team." after the note.
- **Page titles ≤ 2 words** where possible; sidebar labels match titles.
- **No screenshots** until there's a system for generating them automatically. **No "Last updated" lines.**
- **Cut anything that can be removed without losing meaning.** No welcome fluff, no roadmap promises, no restating what a link target already says. Answer first.
Expand All @@ -91,8 +92,19 @@ If a change moves a fact's canonical home, update this table in the same PR.
## Programmatic access

- Every page whose surface the CLI/MCP covers **ends** with an H2 named exactly "Programmatic access".
- It opens with exactly: `Via the [Splits CLI / MCP](/introduction/agents):`
- It opens with exactly: `Through the [Splits CLI / MCP](/introduction/agents):`
- Commands are bullets in the form `` `splits <command> <args>` ``: description (**Scope** scope).
- If the surface has no CLI coverage and a user might expect it, say so: "X is web-only today."
- If the surface has no CLI coverage and a user might expect it, say so: "X is available only in the app."
- **CLI commands appear nowhere else on a page.** Body prose describes the app flow; conceptual links to `/introduction/agents` (e.g. "registered via the CLI") are fine, inline command names are not.
- Don't document the full command surface: the CLI is self-describing (`npx @splits/splits-cli@latest --llms`), and `/introduction/agents` owns setup, scopes, and headless signing.

## Simplified Technical English

Public prose must follow [STE.md](STE.md), which targets ASD-STE100 Issue 9. This includes titles, subtitles, metadata, tables, link labels, callouts, and image descriptions. Use at most 20 words per sentence and six sentences per paragraph. This sentence limit is stricter than the standard's descriptive limit.

- Use the official dictionary for general words and their meanings and parts of speech. The local linter is not a full dictionary checker.
- Record technical terms in `scripts/ste/terms.json` for authors and checks. Define terms for readers on their canonical feature pages. Run `pnpm check:docs` to validate the registry and public prose.
- Use one instruction per sentence in numbered procedures. State conditions first. Keep instructions out of notes.
- Use active voice and simple verb forms. Expand contractions. Preserve literal UI labels, commands, and identifiers.
- Run `pnpm build`. It runs prose checks, term registry validation, and regression tests before the Vocs build.
- A separate maintainer must review the current commit against the official standard and approve with `STE review complete`. An agent must not claim full compliance from a passing linter.
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pnpm preview # preview the build

## Rules

The full authoring ruleset lives in [CLAUDE.md](CLAUDE.md). The load-bearing ones:
The authoring rules are in [CLAUDE.md](CLAUDE.md). [STE.md](STE.md) defines the ASD-STE100 Issue 9 writing, terminology, and review process. The load-bearing ones:

- **Code is the source of truth.** Verify every behavioral claim against product source before writing it: `0xSplits/splits` (backend), `splits-teams` (web client), `splits-cli`, `splits-connect`, and `splits-contracts-monorepo`. Never extrapolate a product fact; if the code can't answer it, flag it for a human instead of guessing.
- **Every fact has exactly one canonical home.** Everywhere else links to it. Restated copies drift independently; that's how doc errors happen.
Expand All @@ -31,6 +31,20 @@ The full authoring ruleset lives in [CLAUDE.md](CLAUDE.md). The load-bearing one
How these docs get updated, by humans or agents:

1. **Verify with subagents.** Fan out read-only agents per feature area against the source repos, requiring file:line evidence and an explicit "cannot verify" for anything the code doesn't answer.
2. **Act as the single final approver.** Re-check any surprising claim yourself in the primary source before writing it.
3. **Check the output.** Run `node scripts/check-prose.mjs <paths>` on touched prose, `pnpm build` for link validation, and read the `.md` twin (`curl localhost:5173/docs/<path>.md`); the twin is what agents consume. Twins, `llms.txt`, and `llms-full.txt` all live under the base path, locally and in production.
2. **Check source evidence.** Re-check surprising claims in the primary source before writing them. A separate maintainer must complete STE editorial review before merge.
3. **Check the output.** Run `pnpm build` for mandatory prose checks, term registry validation, checker tests, and link validation, and read the `.md` twin (`curl localhost:5173/docs/<path>.md`); the twin is what agents consume. Twins, `llms.txt`, and `llms-full.txt` all live under the base path, locally and in production.
4. **Mind the URLs.** The sidebar lives in `vocs.config.ts` and URLs derive from file paths under `src/pages/`, so moving a file means grepping for inbound links first.

## STE checks

```sh
pnpm check:docs # scan all public Markdown and MDX
pnpm test:prose # test the checker and editorial review gate
pnpm build # run all checks and build the site
```

Edit technical terms in [scripts/ste/terms.json](scripts/ste/terms.json), the internal reference for authors and checks. Define terms for readers on their canonical feature pages. The checker reports file and line locations and fails on findings. New pages enter the scan automatically.

The checker covers a defined subset of STE rules. A qualified editorial review must check vocabulary, meanings, grammar, and instructions against the official standard. The reviewer approves the current commit with `STE review complete` in the review body.

CI provides `Docs checks` and `STE editorial review`. After the initial merge, an administrator must require both checks and one approval in the existing branch ruleset. See [repository enforcement](STE.md#repository-enforcement). Until that setting changes, GitHub can permit a merge with failed checks.
Loading
Loading