Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ jobs:
# Lifts the API rate limit off the runner's shared address.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run check:claims
# Downloads the pinned release and asks it what it accepts. The pull
# request that bumps the pin is the one where this matters most, which is
# why it runs here and not only on the daily schedule.
- name: Check the reference against the pinned release
run: npm run sync:product -- --check
# `npm run build` runs `tsc -b` before Vite, so this is the typecheck too.
- run: npm run build
# The deployed artifact is the image, not the directory, so the image is
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,23 @@ jobs:
cache: npm
- run: npm ci --no-audit --no-fund

- name: Check the claims that came from the product
- name: Check the claims and the reference against the product
shell: bash
env:
# Lifts the API rate limit off the runner's shared address.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Without pipefail the exit status would be tee's, which is always
# zero — the failure this job exists to report would be invisible.
set -euo pipefail
npm run check:claims 2>&1 | tee "${RUNNER_TEMP}/claims.log"
set -uo pipefail

# Both run even when the first fails: the issue this opens should
# carry everything that is wrong, not the first thing.
status=0
npm run check:claims 2>&1 | tee "${RUNNER_TEMP}/claims.log" || status=1
npm run sync:product -- --check 2>&1 \
| tee -a "${RUNNER_TEMP}/claims.log" || status=1
exit "${status}"

# A red run in a repository nobody is watching is not a notification.
# An issue is, and it survives until someone closes it.
Expand Down
43 changes: 35 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ npm run dev
```sh
npm run lint # oxlint
npm run check:claims # what this page says about the product, against the product
npm run sync:product # rewrite the generated reference from the pinned release
npm run build # verify:wallets, the llms.txt generator, tsc -b, vite build
```

Expand All @@ -21,13 +22,38 @@ The build writes `public/llms.txt` and `public/llms-full.txt` from the pages in
a second step. It also refuses to run if a sponsorship address fails its own
checksum.

`check:claims` is the one that exists because of what this repository is. It
describes a product it does not contain, so its failure mode is drift rather
than a broken build: the install prompt is compared with the product's README,
and the `gr doctor` capture with the newest published release, so a release is
what forces a re-capture rather than someone noticing. It needs the network and
fails loudly without it — a check that passes when it did not run is the promise
it was meant to replace.
## Keeping up with the product

This repository describes a product it does not contain, so its failure mode is
drift rather than a broken build. Three things hold against it.

**One release is described at a time.** `product/pin.json` names it. Bumping the
tag and running `npm run sync:product` is what pulls this site forward: the
script downloads that release, verifies it against its published checksums, asks
the binary what it accepts, and rewrites the `<!-- generated -->` blocks in
`public/docs/commands.md` from the answer. Prose around those blocks is written
by hand and never touched — the reference is derived, the explanation is not.
The diff of a pin bump is the product's changelog as far as this site is
concerned, and therefore the list of prose worth re-reading.

**Nothing new arrives unmentioned.** Every command the binary accepts must have
a section on the commands page or an entry in `product/pin.json` saying why not.
A command added to the product cannot pass through here unnoticed; leaving one
out stays allowed, leaving one out silently does not.

**Everything is read at the pin, including the prompt.** `check:claims`
compares the install prompt with the README *at the pinned tag*, not at `main`.
That was the other way round for a week, until a change landed on `main` that
rewrote the prompt for behaviour no release carries yet — and the prompt's own
first instruction is to download `releases/latest`. Copying it would have told
an agent to fetch one binary and look for a report only a different one prints.

**A clock, not a pull request.** What notices the product moving is the pin
failing to be the newest published release, and `.github/workflows/drift.yml`
runs the checks daily, because drift here is caused by the product moving rather
than by anything happening in this repository. A failure opens an issue. All of
it needs the network and fails loudly without it — a check that passes when it
did not run is the promise it was meant to replace.

## Shape

Expand All @@ -36,7 +62,8 @@ it was meant to replace.
| `src/content.ts` | every string the landing page shows |
| `src/theme/` | the Dracula/Alucard theme and the typefaces |
| `public/docs/*.md` | the documentation source, served raw and rendered by `src/Docs.tsx` |
| `scripts/` | the checks that run before a build: the claims check and the wallet verifier |
| `product/` | which release this site describes, and the surface generated from it |
| `scripts/` | the checks and the generator: claims, wallets, and the product reference |
| `nginx.conf` | how the routes are served, including the client-route fallback |
| `Dockerfile` | the deployed artifact: nginx with `dist/` inside it |

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"preview": "vite preview",
"llms": "node scripts/build-llms.mjs",
"verify:wallets": "node --experimental-strip-types scripts/verify-wallets.mjs",
"check:claims": "node --experimental-strip-types scripts/check-claims.mjs"
"check:claims": "node --experimental-strip-types scripts/check-claims.mjs",
"sync:product": "node scripts/sync-product.mjs"
},
"dependencies": {
"@astryxdesign/cli": "^0.1.9",
Expand Down
24 changes: 24 additions & 0 deletions product/pin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"$comment": [
"Which release of the product this site describes. Hand-maintained.",
"",
"Bumping this is the act that pulls the site forward: `npm run sync:product`",
"downloads that release, asks the binary what it accepts, and rewrites the",
"generated blocks from the answer. The diff of that bump is the list of what",
"changed in the product, which is also the list of prose worth re-reading.",
"",
"`undocumented` is the other half. Every command the binary accepts must",
"either have a section in public/docs/commands.md or appear here with a",
"reason, and the check fails otherwise — so a command added to the product",
"cannot pass through this repository unnoticed. Leaving one out is allowed;",
"leaving one out silently is not."
],
"tag": "v0.1.2",
"undocumented": {
"prepare": "Wrapper lifecycle, for benchmark and owner-driven runs; named as a group under 'What this page leaves out'.",
"inspect": "Wrapper lifecycle, as above.",
"start": "Wrapper lifecycle, as above.",
"finish": "Wrapper lifecycle, as above.",
"health": "The superseded name of `gr doctor`, which the doctor section already names."
}
}
172 changes: 172 additions & 0 deletions product/surface.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
{
"$comment": "Generated by scripts/sync-product.mjs from the release named in product/pin.json. Do not edit: run `npm run sync:product`.",
"tag": "v0.1.2",
"commands": [
{
"name": "init",
"flags": [
{
"flag": "--confirm-schema-switch",
"effect": "switch an OpenSpec configuration that names another custom schema"
},
{
"flag": "--fix-gitignore",
"effect": "add the ignore entries the registration and the marker need"
},
{
"flag": "--repo <string>",
"effect": "repository to initialize (default \".\")"
},
{
"flag": "--scaffold <string>",
"effect": "codex or claude-code; omit to detect"
}
]
},
{
"name": "doctor",
"flags": [
{
"flag": "--json",
"effect": "emit the diagnosis as JSON"
},
{
"flag": "--repo <string>",
"effect": "repository to diagnose (default \".\")"
},
{
"flag": "--scaffold <string>",
"effect": "codex or claude-code; omit to report every supported scaffold"
},
{
"flag": "--state-dir <string>",
"effect": "Goalrail local state directory"
}
]
},
{
"name": "update",
"flags": [
{
"flag": "--discard-local-edits",
"effect": "replace overlay files that differ from the canon, discarding local edits"
},
{
"flag": "--repo <string>",
"effect": "repository whose harness to update (default \".\")"
},
{
"flag": "--state-dir <string>",
"effect": "Goalrail local state directory"
}
]
},
{
"name": "version",
"flags": []
},
{
"name": "connect",
"flags": [
{
"flag": "--scaffold <string>",
"effect": "codex or claude-code"
},
{
"flag": "--yes",
"effect": "consent to modifying the scaffold configuration"
}
]
},
{
"name": "disconnect",
"flags": [
{
"flag": "--repo <string>",
"effect": "repository whose registration to remove (default \".\")"
},
{
"flag": "--scaffold <string>",
"effect": "codex or claude-code"
}
]
},
{
"name": "health",
"flags": [
{
"flag": "--repo <string>",
"effect": "repository to check (default \".\")"
},
{
"flag": "--scaffold <string>",
"effect": "codex or claude-code; omit to check all supported scaffolds"
}
]
},
{
"name": "prepare",
"flags": [
{
"flag": "--file <string>",
"effect": "path to one WorkSpec JSON file"
},
{
"flag": "--state-dir <string>",
"effect": "Goalrail local state directory"
}
]
},
{
"name": "inspect",
"flags": [
{
"flag": "--digest <string>",
"effect": "prepared WorkSpec digest"
},
{
"flag": "--run <string>",
"effect": "generated run ID"
},
{
"flag": "--state-dir <string>",
"effect": "Goalrail local state directory"
}
]
},
{
"name": "start",
"flags": [
{
"flag": "--adapter <string>",
"effect": "provider adapter; v0 recognizes codex but is not activated"
},
{
"flag": "--digest <string>",
"effect": "prepared WorkSpec digest"
},
{
"flag": "--state-dir <string>",
"effect": "Goalrail local state directory"
}
]
},
{
"name": "finish",
"flags": [
{
"flag": "--result <value>",
"effect": "check result: <id>=<pass|fail|unavailable>[,<evidence-ref>[,<sha256>]]"
},
{
"flag": "--run <string>",
"effect": "generated run ID"
},
{
"flag": "--state-dir <string>",
"effect": "Goalrail local state directory"
}
]
}
]
}
41 changes: 37 additions & 4 deletions public/docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ what it left alone, and the pinned invocation the repository is now driven by.
Repeating it changes nothing. Re-running it repairs a registration that is
stale, unscoped, or naming an event this arrangement supersedes.

<!-- generated: gr init --help -->
| Flag | Effect |
|---|---|
| `--repo <path>` | repository to initialize, default the working directory |
| `--scaffold <name>` | override detection |
| `--fix-gitignore` | add the ignore entries the registration and marker need |
| `--confirm-schema-switch` | adopt a configuration that names another custom schema |
| `--confirm-schema-switch` | switch an OpenSpec configuration that names another custom schema |
| `--fix-gitignore` | add the ignore entries the registration and the marker need |
| `--repo <string>` | repository to initialize (default ".") |
| `--scaffold <string>` | codex or claude-code; omit to detect |
<!-- /generated -->

## `gr doctor`

Expand Down Expand Up @@ -73,6 +75,15 @@ itself did not run. `--json` emits the same report for a machine.

`gr health` still works and names its successor.

<!-- generated: gr doctor --help -->
| Flag | Effect |
|---|---|
| `--json` | emit the diagnosis as JSON |
| `--repo <string>` | repository to diagnose (default ".") |
| `--scaffold <string>` | codex or claude-code; omit to report every supported scaffold |
| `--state-dir <string>` | Goalrail local state directory |
<!-- /generated -->

## `gr update`

Brings this repository's overlay up to what the installed binary carries.
Expand All @@ -88,6 +99,14 @@ The diagnosis is the only command that reaches the network, and only for the
update check described above; initialization, this command, the session hooks,
and the escalation loop reaching it would each violate a published requirement.

<!-- generated: gr update --help -->
| Flag | Effect |
|---|---|
| `--discard-local-edits` | replace overlay files that differ from the canon, discarding local edits |
| `--repo <string>` | repository whose harness to update (default ".") |
| `--state-dir <string>` | Goalrail local state directory |
<!-- /generated -->

## `gr connect` / `gr disconnect`

`connect` attaches a scaffold that can only register at user scope; it needs
Expand All @@ -97,6 +116,20 @@ and points at `gr init`.
`disconnect` removes every registration, in whichever scope it lives, and leaves
entries it did not add untouched.

<!-- generated: gr connect --help -->
| Flag | Effect |
|---|---|
| `--scaffold <string>` | codex or claude-code |
| `--yes` | consent to modifying the scaffold configuration |
<!-- /generated -->

<!-- generated: gr disconnect --help -->
| Flag | Effect |
|---|---|
| `--repo <string>` | repository whose registration to remove (default ".") |
| `--scaffold <string>` | codex or claude-code |
<!-- /generated -->

## `gr version`

The binary's version and the overlay it carries. Nothing about a repository is
Expand Down
Loading
Loading