Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
153 commits
Select commit Hold shift + click to select a range
faec67e
chore: resolve iss-2608221457227162 — pseudo-ADR note already retired
REPPL Sep 25, 2026
41c05bd
feat(lint): intent_sota warns on a planned intent with no SOTA declar…
REPPL Sep 25, 2026
9740feb
chore: resolve iss-243 — intent_sota lint and template slot built
REPPL Sep 25, 2026
dd97694
fix(lint): refuse typographic quotes in Go source outside an allowlist
REPPL Sep 25, 2026
29557d6
chore: resolve iss-2608301844363341 — typographic-quote guard armed
REPPL Sep 25, 2026
b48fd58
fix(lint): every lint read goes through containment and the guarded read
REPPL Sep 25, 2026
67e9dac
chore: resolve three guarded-read records — lint reads contained and …
REPPL Sep 25, 2026
9c238a9
fix(lint): a Sub-verbs heading with no header row is a missing table
REPPL Sep 25, 2026
4b051de
chore: resolve iss-2609250937494009 — Sub-verbs table found by its he…
REPPL Sep 25, 2026
ed4da1e
fix(lint): the join legs say only what the walk establishes
REPPL Sep 25, 2026
a1992bb
fix(lint): an unsafe admissions path names no capture refusal
REPPL Sep 25, 2026
127c507
chore: resolve two reading-report message records
REPPL Sep 25, 2026
cd7c435
fix(lint): agent_contract refuses a prompt filed below the flat layout
REPPL Sep 25, 2026
fe8b46e
chore: resolve iss-2608281948289198 — nested agent prompts refused
REPPL Sep 25, 2026
35600e9
fix(lint): record_schema refuses exactly the issue records capture re…
REPPL Sep 25, 2026
7ad7270
chore: resolve four gate-versus-reader records — one verdict per issu…
REPPL Sep 25, 2026
619b952
fix(lint): links_resolve walks the working tier through extra_roots
REPPL Sep 25, 2026
458a957
chore: resolve iss-2608230752354927 — work-tier links resolved by rec…
REPPL Sep 25, 2026
47a76a9
fix(lint): reading items and dispositions are held to their readers' …
REPPL Sep 25, 2026
caaf19e
chore: resolve iss-2608300929274006 — one filename grammar for items …
REPPL Sep 25, 2026
1a9dc21
feat(lint): changelog_unreleased_empty refuses a hand-written Unrelea…
REPPL Sep 25, 2026
879de2c
chore: resolve iss-256 — Unreleased entries refused at the record gate
REPPL Sep 25, 2026
a812db1
fix(lint): record_schema refuses an issue body the site renderer refuses
REPPL Sep 25, 2026
6f0a509
chore: resolve iss-2608301350287219 — issue bodies checked against th…
REPPL Sep 25, 2026
310a995
feat(gates): RS006 refuses a resolution naming a test that does not e…
REPPL Sep 25, 2026
1c05639
docs: the issue-resolution gate runs RS001–RS006
REPPL Sep 25, 2026
b7646ff
chore: resolve iss-2609020716579024 — resolutions name only tests tha…
REPPL Sep 25, 2026
b19c537
fix(lint): links_resolve honours its own exempt globs for mirror files
REPPL Sep 25, 2026
a2e7e15
chore: resolve iss-2609151150180583 — links_resolve exempt globs excu…
REPPL Sep 25, 2026
13519b2
fix(lint): prune gitignored paths under a lint root, and name them
REPPL Sep 25, 2026
2ddafe4
chore: resolve iss-2609151952353626 — lint prunes gitignored paths un…
REPPL Sep 25, 2026
fdb77e5
feat(lint): spec_lifecycle refuses an intent whose bucket disagrees w…
REPPL Sep 25, 2026
22ef421
chore: resolve iss-2609181121522692 — spec_lifecycle holds intent and…
REPPL Sep 25, 2026
f5366f5
fix(lint): record_provenance reports a command key spelled with a spa…
REPPL Sep 25, 2026
99b7864
chore: resolve iss-2609210748122003 — record_provenance reports a spa…
REPPL Sep 25, 2026
ee0cce3
fix(lint): persona attribution reads `says <Name>,` as well as `said …
REPPL Sep 25, 2026
147bce3
chore: resolve iss-2609231715081185 — persona attribution reads says …
REPPL Sep 25, 2026
23f1440
test(lint): the loader-parity fixture files its intent in planned/
REPPL Sep 25, 2026
dd43ce1
feat(lint): name_roots carry the names/ ban family over the whole pub…
REPPL Sep 25, 2026
eed85cf
chore: resolve iss-279 — name gate reaches the whole public surface
REPPL Sep 25, 2026
fc345f9
fix(lint): harden receipt_gate reads, refuse duplicate receipt keys, …
REPPL Sep 25, 2026
bb8a71e
chore: resolve iss-131 — receipt_gate reads guarded, duplicate keys r…
REPPL Sep 25, 2026
2b85b18
style(lint): gofmt the bucket-agreement test
REPPL Sep 25, 2026
3173348
chore: capture iss-2609252145018018 — unguarded os.ReadFile sites in …
REPPL Sep 25, 2026
4891890
fix(lint): record_schema reports a setext underline in a record body
REPPL Sep 25, 2026
24a78da
chore: resolve iss-2608221342508878 — record_schema reports a setext …
REPPL Sep 25, 2026
ea6f7a9
fix(lint): the intent-tree scan and spec-store probes part ENOENT fro…
REPPL Sep 25, 2026
94465eb
chore: resolve iss-2608261533419897 — intent-tree scan and spec-store…
REPPL Sep 25, 2026
869ccf1
fix(lint): reading walk routes unlistable dirs to Unsafe, marks illeg…
REPPL Sep 25, 2026
39dfb20
chore: resolve iss-2608300848049813 — reading walk nits: unlistable d…
REPPL Sep 25, 2026
16be45b
fix(lint): the lapsed_at block leg reads a block-scalar header as a b…
REPPL Sep 25, 2026
52f079f
chore: resolve iss-2608301221402131 — lapsed_at block leg reads a blo…
REPPL Sep 25, 2026
266c912
test(lint): pin the filename legs' judged marks and settle the protocol
REPPL Sep 25, 2026
034e16a
chore: resolve iss-2608301634520703 — judged marks kept, protocol hon…
REPPL Sep 25, 2026
85fae52
fix(lint): pin the bucketField invariants, report position and bucket…
REPPL Sep 25, 2026
e3724c8
chore: resolve iss-2608301634527391 — every bucketField store is pinn…
REPPL Sep 25, 2026
4e09184
chore: resolve iss-2608301808197261 — bucketField pinned required, bo…
REPPL Sep 25, 2026
1164538
style(lint): gofmt the bucketField test
REPPL Sep 25, 2026
6eed91a
docs(lint): correct checkRecordJoins' ordinals, the join and spelling…
REPPL Sep 25, 2026
ad2c513
chore: resolve iss-2608301813259334 — join godoc ordinals, !!null enu…
REPPL Sep 25, 2026
a6d2a2d
chore: resolve iss-2608301901260461 — negative loop scoped; capture.m…
REPPL Sep 25, 2026
57e3f44
feat(lint): link_anchors validates a link's #fragment against its tar…
REPPL Sep 25, 2026
7c7f108
chore: resolve iss-303 — link_anchors validates heading fragments, wa…
REPPL Sep 25, 2026
7a84869
fix(lint): refuse an enabled gate_lockstep or surface_coverage with a…
REPPL Sep 25, 2026
fd83baa
chore: resolve iss-336 — armed rules with a blank input path are refu…
REPPL Sep 25, 2026
379544e
chore: capture the four lintB review findings
REPPL Sep 25, 2026
ff1288f
fix(jsonstrict): refuse a key's case twin as encoding/json binds it
REPPL Sep 25, 2026
f61477b
chore: resolve iss-2609252251311346 — jsonstrict folds case twins
REPPL Sep 25, 2026
63bda92
fix: reroute the layered and preset duplicate-key walkers through jso…
REPPL Sep 25, 2026
c592884
chore: resolve iss-2609252251317108 — one duplicate-key primitive
REPPL Sep 25, 2026
d90224e
fix(lint): fail loud on a name_roots file the name gate cannot examine
REPPL Sep 25, 2026
0b52be3
chore: resolve iss-2609252251320497 — the name walk fails loud
REPPL Sep 25, 2026
1bf76c8
fix(lint): the names family reads inside code fences by default
REPPL Sep 25, 2026
93f83eb
chore: resolve iss-2609252251320133 — name bans read inside fences
REPPL Sep 25, 2026
1833680
chore: drop the lapsed deferral waiver from a resolved record
REPPL Sep 25, 2026
a37ad51
feat(credential): the abcd-only home's write, and the name check expo…
REPPL Sep 26, 2026
f0d666c
feat(openaiapi): an OpenAI-compatible chat-completions client
REPPL Sep 26, 2026
0eb7789
feat(oracle): provider blocks, the vendor denylist and the routes, re…
REPPL Sep 26, 2026
8b3ab64
feat(oracle): the call through a provider, its record, and the setup'…
REPPL Sep 26, 2026
dc6c1a1
feat(ahoy): explain the provider adapter, and wire `ahoy --providers`…
REPPL Sep 26, 2026
3e2ae2b
fix(openaiapi): name the answer unwrap in the fence allowlist, and un…
REPPL Sep 26, 2026
4996345
chore: capture the review's key-scrub, lost-update and proxy-doc find…
REPPL Sep 26, 2026
8bc4899
fix(openaiapi): scrub every representation of the key, not only its l…
REPPL Sep 26, 2026
4762bc2
fix(credential,oracle): lock the setup's writes so concurrent connect…
REPPL Sep 26, 2026
ed08d99
docs(openaiapi): say the client honours the proxy variables, not that…
REPPL Sep 26, 2026
9faabb7
chore: resolve iss-2609260904163830 — the key is scrubbed in every re…
REPPL Sep 26, 2026
a694da4
chore: resolve iss-2609260904161412 — the setup's writes hold their l…
REPPL Sep 26, 2026
c9f774b
chore: resolve iss-2609260904167076 — the doc names the proxy variabl…
REPPL Sep 26, 2026
6451420
fix(guard): read an unknown dash-word as a wrapper's operands too
REPPL Sep 26, 2026
cb509c3
chore: resolve iss-2609260543090196 — guard reads a dash-word as oper…
REPPL Sep 26, 2026
878bf1a
docs(disembark): name the pack sub-verb in the argument hint
REPPL Sep 26, 2026
f10f708
chore: resolve iss-2609260552249742 — disembark hint names pack
REPPL Sep 26, 2026
3583b3a
docs(launch): send an archive-pin refusal to release.yml's verify job
REPPL Sep 26, 2026
6c4c3f7
chore: resolve iss-2609260552247395 — launch page names the verify gate
REPPL Sep 26, 2026
d69a002
docs(history): say what the reading verbs write through the store seam
REPPL Sep 26, 2026
d08c000
chore: resolve iss-2609260552246303 — history verbs name their writes
REPPL Sep 26, 2026
1ab6439
docs(lint): name the site render the lint's site target writes
REPPL Sep 26, 2026
46ad08f
chore: resolve iss-2609260552247252 — lint page names the site render
REPPL Sep 26, 2026
7cc1c0a
docs(lint): keep the brief chapter's prose free of sub-verb spellings
REPPL Sep 26, 2026
bd2986f
fix(inbox): refuse an inbox path that is not a real directory at exit 2
REPPL Sep 26, 2026
9798697
chore: resolve iss-2609260552250826 — inbox path refusal exits 2
REPPL Sep 26, 2026
e87ffc0
fix(report): name the kept editor draft on a failure as on a refusal
REPPL Sep 26, 2026
180c812
docs(inbox): say where the untrusted line stands in the text forms
REPPL Sep 26, 2026
a4d5e8d
chore: resolve iss-2609260552256523 — report names its kept draft on …
REPPL Sep 26, 2026
b0cee1c
chore: resolve iss-2609260552256401 — inbox page places the untrusted…
REPPL Sep 26, 2026
05dab15
chore: capture the second review's escaped-key echo, localhost-proxy …
REPPL Sep 26, 2026
c6de9b4
fix(openaiapi): undo JSON escapes in an undecodable error body before…
REPPL Sep 26, 2026
0e0c49f
chore: resolve iss-2609260958588580 — an undecodable error body is un…
REPPL Sep 26, 2026
ba20610
fix(openaiapi): spell a localhost base URL in lower case so it is nev…
REPPL Sep 26, 2026
a6a8f00
chore: resolve iss-2609260958580553 — a localhost base URL is never p…
REPPL Sep 26, 2026
37dc637
fix(credential,oracle): name an unsafe lock rather than report it as …
REPPL Sep 26, 2026
22d5de3
fix(lint): the receipt gate reads its receipts and manifest inside th…
REPPL Sep 26, 2026
7ebe51b
chore: resolve iss-2609261016494611 — receipt gate reads inside the root
REPPL Sep 26, 2026
eeab4d6
fix(lint): the prose baseline and the reading walk stay inside the re…
REPPL Sep 26, 2026
c818645
chore: resolve iss-2609261019593167 — baseline and reading walk conta…
REPPL Sep 26, 2026
b3edfb3
test(lint): the unguarded-read guard parses the source instead of mat…
REPPL Sep 26, 2026
8a321f5
feat(lint): record_schema names an issue-store seam no front door reg…
REPPL Sep 26, 2026
49b8d3f
chore: capture the resolution notes that name a test no longer in the…
REPPL Sep 26, 2026
b1fd918
chore: capture three inbox refusal defects from the cutfix review
REPPL Sep 26, 2026
7170858
fix(inbox): name the refused level, and refuse it on every verb
REPPL Sep 26, 2026
00c1c65
fix(cli): name an inbox that cannot be counted at session start and o…
REPPL Sep 26, 2026
3df2a68
docs(lint): address the technical facilitator, not a maintainer
REPPL Sep 26, 2026
897836e
chore: resolve iss-2609261106286306 — the inbox refusal names its level
REPPL Sep 26, 2026
a61493d
chore: resolve iss-2609261106287078 — inbox readers refuse what write…
REPPL Sep 26, 2026
60af68d
chore: resolve iss-2609261106287627 — a refused inbox is named, not s…
REPPL Sep 26, 2026
4292bca
chore: wontfix iss-2609261108448674 — ahoy local-tier refusal level i…
REPPL Sep 26, 2026
69560fc
chore: capture record_schema skipping a symlinked declared bucket
REPPL Sep 26, 2026
f6894de
fix(lint): record_schema names a declared bucket that is a symlink
REPPL Sep 26, 2026
ba6eae5
chore: resolve iss-2609261133371466 — record_schema names a linked bu…
REPPL Sep 26, 2026
ea9fdcc
chore: capture record_schema skipping undeclared symlinked entries
REPPL Sep 26, 2026
1742cc2
fix(lint): record_schema names every undeclared link in a record store
REPPL Sep 26, 2026
426fbdb
chore: resolve iss-2609261152282753 — record_schema names undeclared …
REPPL Sep 26, 2026
ef70ca9
chore: capture the .md-named link record_schema still passes
REPPL Sep 26, 2026
a7f750f
chore: reopen iss-2609261108448674 — the refused level is reachable
REPPL Sep 26, 2026
973a73d
fix(ahoy): prove the local tier from the resolved checkout root, nami…
REPPL Sep 26, 2026
683e5ff
chore: resolve iss-2609261108448674 — the local tier is proved from t…
REPPL Sep 26, 2026
894aa1b
docs(inbox): say a link at the home or ~/.abcd with no inbox behind i…
REPPL Sep 26, 2026
99c7d45
chore: capture fix3-cutfix's two unswept follow-ups
REPPL Sep 26, 2026
901d2d9
Merge lane lintA (fix/lint-cluster-a) into the integration branch
REPPL Sep 26, 2026
8065d62
Merge lane lintB (fix/lint-cluster-b) into the integration branch
REPPL Sep 26, 2026
96cf648
chore: resolve iss-2609252145018018 — lint reads are guarded by lintA
REPPL Sep 26, 2026
ae89fe2
fix(credential): refuse a store that names one credential twice
REPPL Sep 26, 2026
907ee6b
chore: resolve iss-2609260120380520 — the credential store refuses a …
REPPL Sep 26, 2026
199658c
Merge lane cutfix (fix/cut-captures) into the integration branch
REPPL Sep 26, 2026
b13e452
Merge lane apiadapter (feat/api-adapter) into the integration branch
REPPL Sep 26, 2026
32d8e8a
chore: capture ahoy connect's config rewrite reading duplicate keys l…
REPPL Sep 26, 2026
945e883
fix(oracle): the provider-block write refuses a config naming a key t…
REPPL Sep 26, 2026
65f818c
chore: resolve iss-2609261312108500 — the provider-block write refuse…
REPPL Sep 26, 2026
d3dc346
Merge main (#724, the history and memory cluster) into the integratio…
REPPL Sep 26, 2026
e4b2e72
chore: recalibrate the reading windows at the integration tip
REPPL Sep 26, 2026
b962139
Merge main (#725, integration branch 1) into the integration branch
REPPL Sep 26, 2026
8fd646f
test(credential): give the escaped-repeat case a real JSON escape
REPPL Sep 26, 2026
34fe88b
chore: recalibrate the reading windows at the re-merged integration tip
REPPL Sep 26, 2026
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
24 changes: 12 additions & 12 deletions .abcd/config/reading-presets.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@
"test"
],
"window": {
"tokens_est": 1090000,
"measured_tokens_est": 1074501,
"measured_bytes": 4136830,
"measured_at": "50152d62171899ff645bc614ad38ee55facc7c1d"
"tokens_est": 1130000,
"measured_tokens_est": 1115292,
"measured_bytes": 4293878,
"measured_at": "8fd646fa043cd76a9d839b69ac797e1b3de3d5af"
}
},
"entailment": {
Expand Down Expand Up @@ -132,10 +132,10 @@
"intent-projection"
],
"window": {
"tokens_est": 360000,
"measured_tokens_est": 353700,
"measured_bytes": 1361748,
"measured_at": "50152d62171899ff645bc614ad38ee55facc7c1d"
"tokens_est": 370000,
"measured_tokens_est": 357546,
"measured_bytes": 1376554,
"measured_at": "8fd646fa043cd76a9d839b69ac797e1b3de3d5af"
}
},
"comparative": {
Expand Down Expand Up @@ -216,10 +216,10 @@
"test"
],
"window": {
"tokens_est": 1100000,
"measured_tokens_est": 1083537,
"measured_bytes": 4171618,
"measured_at": "50152d62171899ff645bc614ad38ee55facc7c1d"
"tokens_est": 1140000,
"measured_tokens_est": 1124328,
"measured_bytes": 4328666,
"measured_at": "8fd646fa043cd76a9d839b69ac797e1b3de3d5af"
}
}
}
Expand Down
76 changes: 68 additions & 8 deletions .abcd/development/brief/04-surfaces/01-ahoy.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ repo whose stamp says it is current.

| Verb | Bucket | Status |
|---|---|---|
| `connect` | — | shipped |
| `doctor` | — | shipped |
| `install` | — | shipped |
| `remote apply` | gate | shipped |
| `uninstall` | — | shipped |


Bare `/abcd:ahoy` shows read-only status and mutates nothing. Three read-only
modes of the same act — the dry run, the identity check and the remote report —
are flags on the bare verb rather than sub-verbs, one at a time, and the
Bare `/abcd:ahoy` shows read-only status and mutates nothing. Four read-only
modes of the same act — the dry run, the identity check, the remote report and
the provider board — are flags on the bare verb rather than sub-verbs, one at a time, and the
appendix lists them. A sub-verb is a distinct action, a flag a mode of the same
one (itd-2609212130136102). For one release each
mode's retired sub-verb spelling answers with its flag and exits non-zero, and
Expand Down Expand Up @@ -76,6 +77,17 @@ the table above is the sub-verb set, and the modes are the bare verb's flags.
machine.** See below.
- **The identity check** exits non-zero when the git commit identity does not
match the repo's identity pin. Read-only, CLI-only, for an operator or CI.
- **The provider board** explains the optional OpenAI-compatible
provider adapter (itd-2609081951381895): what an aggregator is, that abcd
would use one for decision models and cheap judgements pointed at it by name,
and that everything works without one, because with no provider configured
every delegated step runs on the host. It lists the providers configured on
this machine, whether each one's key resolves (never the key), the vendor
denylist in force, the roles and judgement types pointed at a provider, and
where a key can live, the keychain recommended in the prose and never as a
marked option. The bare board carries the same explanation as an optional,
advisory gap while no provider is configured.
- **The provider setup** sets one provider up, and writes. See below.

**Not built yet:** `destroy`, a nuclear uninstall that would remove the `.abcd/`
namespace too (itd-10), as distinct from the uninstall's reversible behaviour.
Expand Down Expand Up @@ -104,6 +116,35 @@ the API host explicitly, so an ambient host variable cannot send the write to an
endpoint the origin never named, and the call goes through the caller's own
authenticated identity: abcd never holds a token.

### The provider setup

The setup takes the provider's name, its base URL, its first allowlist (every
model it may serve) and where its key lives. It verifies the provider with one
call to the first model listed and, only when that call succeeds, writes the key
and then the provider block, both under `~/.abcd/`: the key into the owner-only
`credentials.json`, the block (base URL, the key's name, the models) into
`config.json`. A failed verification writes nothing. Nothing reaches the
repository or the harness's settings. Every fault the configuration read would
refuse (a denylisted or malformed model, a base URL that is plain HTTP to
another machine, a provider already configured, a key name already holding a
different value) is refused before the call, so a setup that cannot finish is
never billed.

The key arrives on stdin and nowhere else. A flag would leave it in the process
listing and the shell history, the install prompter echoes every answer into its
transcript, a host's question tool would put it in an agent's context, and a
terminal would echo it as it is typed, so stdin from a terminal is refused. For
the same reason the walkthrough is this sub-verb, which the person runs with the
key piped in, rather than a question the install pass asks: declining is not
running it, and changes nothing.

Of the three homes a key may live in, the setup builds the abcd-only one. The
environment-variable-or-external-tool home and the platform keychain arrive with
the credential store (itd-2609221017023290); asked for either, the setup refuses
naming it. A fourth answer, no key, sets up a local server that takes none.
No delegating verb sends a step to a configured provider until provider dispatch
lands (spc-2609251028149555), and both the board and the setup say so.

## What abcd manages — repos and `~/.abcd/`

abcd manages exactly one kind of folder, a **repository**, and keeps one
Expand All @@ -129,7 +170,11 @@ user-scope directory for machine-local state.
inbox/ reports managed repositories filed back to abcd,
<received-stamp>-<sender-key>.md; promoted/ keeps
the ones filed as captures (itd-2609221656361680)
config.json machine config defaults (a later phase)
config.json the machine layer of the layered configuration,
read-only except for the provider blocks
(oracle.api.<provider>) the provider setup writes,
and the only file a provider block may sit in;
that write holds .config.json.lock beside it
memory/ user-scope memory (personal, cross-project — a later
phase; the shipped store is repo-scope .abcd/memory/)
sources/ the local sources corpus /abcd:ingest and /abcd:consult
Expand All @@ -139,9 +184,12 @@ user-scope directory for machine-local state.
extreme-load), read-only; abcd never creates it
(itd-2609231434459890)
credentials.json external credentials by name (a hosting token for
setting up a site), mode 0600, read-only; abcd never
creates it. The interim source the credential store
replaces (itd-2609221017023290)
setting up a site, a provider's key), mode 0600;
only the provider setup writes it, one new name at
a time, never replacing a stored value, holding
.credentials.json.lock beside it across the read
and the write. The interim source the credential
store replaces (itd-2609221017023290)
rules.json the machine's rule conventions, the user layer
between the bundled domains and each repo's
.abcd/rules.json, read-only; abcd never creates it
Expand Down Expand Up @@ -536,14 +584,26 @@ _Generated from the command tree; a drift test fails `go test` when this appendi

### `abcd ahoy`

Sub-verbs: `abcd ahoy doctor`, `abcd ahoy install`, `abcd ahoy remote`, `abcd ahoy uninstall`.
Sub-verbs: `abcd ahoy connect`, `abcd ahoy doctor`, `abcd ahoy install`, `abcd ahoy remote`, `abcd ahoy uninstall`.

| Flag | Type |
|---|---|
| `--dry-run` | bool |
| `--identity` | bool |
| `--providers` | bool |
| `--remote` | bool |

### `abcd ahoy connect`

Sub-verbs: none.

| Flag | Type |
|---|---|
| `--base-url` | string |
| `--home` | string |
| `--key` | string |
| `--model` | stringArray |

### `abcd ahoy doctor`

Sub-verbs: none.
Expand Down
7 changes: 4 additions & 3 deletions .abcd/development/brief/04-surfaces/04-launch.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,10 @@ checked-out tree, into an existing directory. Bound to the tag being released,
it refuses (exit 1) unless the committed catalog pins exactly that archive's
address and digest, and unless that address lies under the releasing
repository's own release downloads for the tag — removing the archive on either
refusal, so nothing unpinned can be published. `auto-release.yml` runs it on the
pushed commit before the tag is made, and the release workflow runs it again on
the tagged commit, each run bound to the repository the workflow runs in. Bound
refusal, so nothing unpinned can be published. The release workflow runs it in
its `verify` job, which the tag job needs, so on the `auto-release` path a
refusal leaves no tag; its release job runs it again on the tagged commit before
it publishes, each run bound to the repository the workflow runs in. Bound
to the pin, the render leaves the dirty-tree gate to it — a payload file that
differs from the commit changes the digest and refuses; unbound, it runs the
gate, and an uncommitted change refuses the render.
Expand Down
12 changes: 8 additions & 4 deletions .abcd/development/brief/04-surfaces/05-intent.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,11 +440,12 @@ Both the press-release intent and the frozen PRD are immutable input artefacts p

## 6. Acceptance gates and bidirectional link verification

`internal/core/lint` (cross-cutting; its shipped wiring is the docs currency lint and the `cmd/record-lint` gate) is the record-lint over the committed intent tree — it does not run inside planning; the acceptance-criteria refusal at plan time is the intent package's own `hasAcceptanceCriteria` check (`internal/core/intent`). The armed record-lint rules that bear on the intent tree are `intent_lifecycle` (the directory/kind/`spec_id` invariants and the `status:`-key ban below), `intent_impact_valid` (the `impact:` field's legal value set), `persona_registry` (press-release quote attributions resolve to the persona roster), `record_schema` (the `itd` store's filename↔id agreement, and `superseded_by` handle validity with two-way agreement across stores), `record_provenance` (the `origin`/`production_mode` disclosure pair and the `related_issues` back-edge), `spec_lifecycle` and `spec_id_unique` (the itd↔spc bidirectional agreement below), and `delivery_state` (no CHANGELOG delivery entry, under `Added` or `Changed`, cites an intent still sitting in `drafts/`). The `IL0xx` codes per [`05-internals/06-lint.md`](../05-internals/06-lint.md) are plan-time design, a later phase.
`internal/core/lint` (cross-cutting; its shipped wiring is the docs currency lint and the `cmd/record-lint` gate) is the record-lint over the committed intent tree — it does not run inside planning; the acceptance-criteria refusal at plan time is the intent package's own `hasAcceptanceCriteria` check (`internal/core/intent`). The armed record-lint rules that bear on the intent tree are `intent_lifecycle` (the directory/kind/`spec_id` invariants and the `status:`-key ban below), `intent_impact_valid` (the `impact:` field's legal value set), `intent_sota` (a `planned/` intent carries a non-empty `## SOTA` declaration, armed at warn), `persona_registry` (press-release quote attributions resolve to the persona roster), `record_schema` (the `itd` store's filename↔id agreement, and `superseded_by` handle validity with two-way agreement across stores), `record_provenance` (the `origin`/`production_mode` disclosure pair and the `related_issues` back-edge), `spec_lifecycle` and `spec_id_unique` (the itd↔spc bidirectional agreement below, and the buckets' agreement: a planned intent has an open spec, and a shipped intent has none left open), and `delivery_state` (no CHANGELOG delivery entry, under `Added` or `Changed`, cites an intent still sitting in `drafts/`). The `IL0xx` codes per [`05-internals/06-lint.md`](../05-internals/06-lint.md) are plan-time design, a later phase.

The invariants below are the contract the tree is held to, and each names what holds it. A bullet marked **(convention)** is practice the corpus follows by hand, with no shipped check behind it:

- **Acceptance criteria present and well-formed** (per the itd-1 discipline): an intent cannot be planned without a `## Acceptance Criteria` section carrying at least one Given-When-Then bullet. The block is at plan time, not in the record-lint: the refusal is the intent package's own `hasAcceptanceCriteria` check on a draft, plus the `acceptance_criteria` row of the readiness gate. Everything in `planned/` and `shipped/` has therefore passed it. The two buckets the plan step never crosses are held by hand and are **(convention)**: a draft still on the bench may carry none, and so may a discipline, whose route into `disciplines/` does not run through planning at all. Both are true of this corpus today — four bench drafts and seven of the fourteen disciplines carry no section. No record-lint rule reads it, so a committed intent that lost one still passes the gate.
- **A planned intent declares the state of the art** (per [sota-per-intent](../../principles/sota-per-intent.md)): a `## SOTA` section naming the existing alternatives, each one's rough maturity, and the path taken. `intent_sota` flags a `planned/` intent with no such section, or with a heading and nothing under it, at warn severity — the warn-first rung of a ratchet whose next rung is blocker once the planned bucket is back-filled. It judges presence, not the path's spelling, and reads neither `drafts/` (not yet shaped) nor `shipped/` (history, most of it older than the principle).
- **`kind` is set on intents in `planned/`, `shipped/`, `disciplines/`, and `superseded/`.** Intents in `drafts/` may have `kind: null`. The shipped plan step neither infers a kind nor asks for one: it writes `standalone` wherever the draft left the field null, so `standalone` is what an unstated kind becomes. **A later phase** replaces that default with the proposal the user confirms or overrides (§ 1, "Later phase — plan grows a PRD-freeze front end and multi-kind dispatch"). What the record lint holds meanwhile is the value set per bucket: a draft's kind must be null, `standalone` or `bundle-member`, and a planned or shipped record's must be one of the latter two, non-null (`intent_lifecycle`).
- **`kind: bundle-member` requires a `bundle:` field** pointing to a bundle ID; *all* members of a bundle reference the same bundle ID, and bundles are bidirectional in their members' frontmatter. **(convention)** No shipped lint reads `bundle`: `intent_lifecycle` knows `bundle-member` only as a legal `kind` value. **Exception for superseded bundle-members:** intents in `superseded/` with `kind_at_supersession: bundle-member` carry `bundle: null` AND `bundle_at_supersession: <bundle-id>` (preserves the bundle the intent was part of when retired, while signalling the bundle is no longer active). **(convention)** `bundle_at_supersession` appears in no shipped code either.
- **Bundle invariant: all members belong to the same phase.** Planning several intents at once (multi-arg, kind=bundle-member) hard-blocks promotion when the proposed members are scoped to different phases. Lint code `IL011`. Resolution: re-scope into one phase or downgrade one member to `kind: standalone`. See § 1 "Bundle invariant" for the canonical statement and the worked example (`intent-capture-discipline` retirement on 2026-05-07).
Expand Down Expand Up @@ -618,9 +619,12 @@ agent and refuses the override. A step no configured provider can serve at its
tier goes to the harness with the tier named in its request, and one stderr line
says so. The receipt is a `route` member in the JSON and a `route:` line in the
text, carrying `tier_asked`, `connection_tried`, `connection_used`,
`fallback_reason`, `override`, `settings_sent` and `model_reported`, the last
read from the payload's own `model` field (a reading's `instrument.model`) and
empty when the payload names none. A routing table that cannot be read, an
`fallback_reason`, `override`, `settings_sent`, `model_reported` and
`provider_call`. `model_reported` is read from the payload's own `model` field (a
reading's `instrument.model`) and empty when the payload names none;
`provider_call` names the provider, the model asked for and the model it
reported when a provider adapter answered the step, and is null on the harness
leg. A routing table that cannot be read, an
override naming an agent this invocation does not dispatch, a tier outside
`local`, `economy`, `frontier` and `host-decides`, or a connection this machine
has not configured exits 2 before anything is written. With no table accepted
Expand Down
3 changes: 2 additions & 1 deletion .abcd/development/brief/04-surfaces/08-abcd.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ when reports from managed repositories wait in the user account's inbox, the tex
render carries an `inbox:` line — `3 report(s) from 2 managed repositories` — and
the JSON an `inbox` object with `reports` and `senders`. It is the same count the
session-start greeting says ([`29-report.md`](29-report.md)); it names no sender,
and it is absent when nothing waits.
and it is absent when nothing waits. An inbox that cannot be counted has no row:
one line on stderr names the refusal instead.

**The oracle lines** (itd-2609170822093401, spc-2609180535002478) show the
model-tier routing once a table is accepted, at the repository
Expand Down
Loading
Loading