Repository navigation
feat(cli): emit the command surface as data via batten spec - #45
Conversation
CLOUD-26 Create the `tools/batten/` crate and keep it repo-agnostic from line one
Why Definition of done
Acceptance
CLOUD-27 Define the CLI as data with a single usage spec as source of truth
Why Definition of done
Acceptance
CLOUD-28 Derive the agent read-only allowlist from effect annotations
Why Definition of done
Acceptance
|
|
/fast-forward Generated by Claude Code |
|
Triggered from #45 (comment) by @wenzowski. Trying to fast forward Target branch ( commit 104ad62586946d157b08052c33e2324c967686dd (HEAD -> main, origin/main)
Author: Claude <noreply@anthropic.com>
Date: Thu Aug 6 08:27:55 2026 +0000
fix(ci): authenticate git so release-plz can rebase onto main
release-plz clones the repo into a temp dir and runs `git fetch origin
main` there to rebase the release branch onto the current main. That
clone has no credentials — actions/checkout's auth lives only on the main
checkout — so the fetch failed ("could not read Username for
github.com"), release-plz gave up rebasing, and re-opened the release PR
on a stale base (the first commit after the last release). The branch
then diverged from main and could never fast-forward, so auto-release-land
kept posting /fast-forward against a non-linear branch and failing.
Add a global `url.insteadOf` credential for github.com (from the release
PAT / job token) so release-plz's internal clone can fetch main, rebase
the release branch to `main + release commit`, and land by fast-forward.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdVURXVaz6yYmrnRW35g3BPull request ( commit 22fd17e4e16fde8f2e2bdbf736869e9914f60f45 (pull_request/claude/ci-watch-handoff-3abw65)
Author: Claude <noreply@anthropic.com>
Date: Thu Aug 6 08:28:52 2026 +0000
feat(cli): emit the command surface as data via `batten spec`
Land the CLI-as-data spine validated by the CLOUD-20 spike. The command
surface is defined once as a clap tree and emitted at runtime as byte-stable
JSON by introspecting the live `clap::Command` (house-style §11), with the
§5 effect model merged in from a single table keyed by full command path.
- effect.rs: the Effect enum + one path-keyed table, fail-safe by
construction (a path absent from the table resolves to `ask`, never `read`).
- spec.rs: runtime introspection into a byte-stable spec, plus the derived
read-only allowlist (CLOUD-28) — filter(effect == read) over the same walk,
never a second hand-kept list.
- cli.rs: the `spec [--format json]` verb; the tree grows one verb at a time,
each addition kept honest by a completeness test that fails if any command
ships without an effect.
- run() now writes data output to an injected writer so the library stays
print-free and byte-stable; the binary passes stdout.
Refs CLOUD-26, CLOUD-27, CLOUD-28.Can't fast forward * 22fd17e4e16fde8f2e2bdbf736869e9914f60f45 feat(cli): emit the command surface as data via `batten spec`
| * 104ad62586946d157b08052c33e2324c967686dd fix(ci): authenticate git so release-plz can rebase onto main
|/
* a4d8e04daec2beec627ba93e12e144cc85ec2275 fix(ci): read checks with GITHUB_TOKEN in auto-release-land
commit a4d8e04daec2beec627ba93e12e144cc85ec2275
Author: Claude <noreply@anthropic.com>
Date: Thu Aug 6 08:10:39 2026 +0000
fix(ci): read checks with GITHUB_TOKEN in auto-release-land
The green-check verification called the check-runs API with
RELEASE_PLZ_TOKEN, a fine-grained PAT that lacks checks:read, so it 403'd
and the job failed. Split the tokens: read check status with the Actions
GITHUB_TOKEN (grant it checks:read), and post `/fast-forward` with
RELEASE_PLZ_TOKEN — the owner identity that actually triggers
fast-forward.yml.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdVURXVaz6yYmrnRW35g3BRebase locally, and then force push to |
Land the CLI-as-data spine validated by the CLOUD-20 spike. The command surface is defined once as a clap tree and emitted at runtime as byte-stable JSON by introspecting the live `clap::Command` (house-style §11), with the §5 effect model merged in from a single table keyed by full command path. - effect.rs: the Effect enum + one path-keyed table, fail-safe by construction (a path absent from the table resolves to `ask`, never `read`). - spec.rs: runtime introspection into a byte-stable spec, plus the derived read-only allowlist (CLOUD-28) — filter(effect == read) over the same walk, never a second hand-kept list. - cli.rs: the `spec [--format json]` verb; the tree grows one verb at a time, each addition kept honest by a completeness test that fails if any command ships without an effect. - run() now writes data output to an injected writer so the library stays print-free and byte-stable; the binary passes stdout. Refs CLOUD-26, CLOUD-27, CLOUD-28.
|
Triggered from #45 (comment) by @wenzowski. Trying to fast forward Target branch ( commit 1f814e78b08f28546333e86c8f4c13fba6a2d30e (HEAD -> main, origin/main)
Author: Alec Wenzowski <alec@button.is>
Date: Thu Aug 6 01:30:17 2026 -0700
chore: release v0.0.2Pull request ( commit 22fd17e4e16fde8f2e2bdbf736869e9914f60f45 (pull_request/claude/ci-watch-handoff-3abw65)
Author: Claude <noreply@anthropic.com>
Date: Thu Aug 6 08:28:52 2026 +0000
feat(cli): emit the command surface as data via `batten spec`
Land the CLI-as-data spine validated by the CLOUD-20 spike. The command
surface is defined once as a clap tree and emitted at runtime as byte-stable
JSON by introspecting the live `clap::Command` (house-style §11), with the
§5 effect model merged in from a single table keyed by full command path.
- effect.rs: the Effect enum + one path-keyed table, fail-safe by
construction (a path absent from the table resolves to `ask`, never `read`).
- spec.rs: runtime introspection into a byte-stable spec, plus the derived
read-only allowlist (CLOUD-28) — filter(effect == read) over the same walk,
never a second hand-kept list.
- cli.rs: the `spec [--format json]` verb; the tree grows one verb at a time,
each addition kept honest by a completeness test that fails if any command
ships without an effect.
- run() now writes data output to an injected writer so the library stays
print-free and byte-stable; the binary passes stdout.
Refs CLOUD-26, CLOUD-27, CLOUD-28.Can't fast forward * 1f814e78b08f28546333e86c8f4c13fba6a2d30e chore: release v0.0.2
* 104ad62586946d157b08052c33e2324c967686dd fix(ci): authenticate git so release-plz can rebase onto main
| * 22fd17e4e16fde8f2e2bdbf736869e9914f60f45 feat(cli): emit the command surface as data via `batten spec`
|/
* a4d8e04daec2beec627ba93e12e144cc85ec2275 fix(ci): read checks with GITHUB_TOKEN in auto-release-land
commit a4d8e04daec2beec627ba93e12e144cc85ec2275
Author: Claude <noreply@anthropic.com>
Date: Thu Aug 6 08:10:39 2026 +0000
fix(ci): read checks with GITHUB_TOKEN in auto-release-land
The green-check verification called the check-runs API with
RELEASE_PLZ_TOKEN, a fine-grained PAT that lacks checks:read, so it 403'd
and the job failed. Split the tokens: read check status with the Actions
GITHUB_TOKEN (grant it checks:read), and post `/fast-forward` with
RELEASE_PLZ_TOKEN — the owner identity that actually triggers
fast-forward.yml.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdVURXVaz6yYmrnRW35g3BRebase locally, and then force push to |
|
Triggered from #45 (comment) by @wenzowski. Trying to fast forward Target branch ( commit 1f814e78b08f28546333e86c8f4c13fba6a2d30e (HEAD -> main, origin/main)
Author: Alec Wenzowski <alec@button.is>
Date: Thu Aug 6 01:30:17 2026 -0700
chore: release v0.0.2Pull request ( commit 22fd17e4e16fde8f2e2bdbf736869e9914f60f45 (pull_request/claude/ci-watch-handoff-3abw65)
Author: Claude <noreply@anthropic.com>
Date: Thu Aug 6 08:28:52 2026 +0000
feat(cli): emit the command surface as data via `batten spec`
Land the CLI-as-data spine validated by the CLOUD-20 spike. The command
surface is defined once as a clap tree and emitted at runtime as byte-stable
JSON by introspecting the live `clap::Command` (house-style §11), with the
§5 effect model merged in from a single table keyed by full command path.
- effect.rs: the Effect enum + one path-keyed table, fail-safe by
construction (a path absent from the table resolves to `ask`, never `read`).
- spec.rs: runtime introspection into a byte-stable spec, plus the derived
read-only allowlist (CLOUD-28) — filter(effect == read) over the same walk,
never a second hand-kept list.
- cli.rs: the `spec [--format json]` verb; the tree grows one verb at a time,
each addition kept honest by a completeness test that fails if any command
ships without an effect.
- run() now writes data output to an injected writer so the library stays
print-free and byte-stable; the binary passes stdout.
Refs CLOUD-26, CLOUD-27, CLOUD-28.Can't fast forward * 1f814e78b08f28546333e86c8f4c13fba6a2d30e chore: release v0.0.2
* 104ad62586946d157b08052c33e2324c967686dd fix(ci): authenticate git so release-plz can rebase onto main
| * 22fd17e4e16fde8f2e2bdbf736869e9914f60f45 feat(cli): emit the command surface as data via `batten spec`
|/
* a4d8e04daec2beec627ba93e12e144cc85ec2275 fix(ci): read checks with GITHUB_TOKEN in auto-release-land
commit a4d8e04daec2beec627ba93e12e144cc85ec2275
Author: Claude <noreply@anthropic.com>
Date: Thu Aug 6 08:10:39 2026 +0000
fix(ci): read checks with GITHUB_TOKEN in auto-release-land
The green-check verification called the check-runs API with
RELEASE_PLZ_TOKEN, a fine-grained PAT that lacks checks:read, so it 403'd
and the job failed. Split the tokens: read check status with the Actions
GITHUB_TOKEN (grant it checks:read), and post `/fast-forward` with
RELEASE_PLZ_TOKEN — the owner identity that actually triggers
fast-forward.yml.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdVURXVaz6yYmrnRW35g3BRebase locally, and then force push to |
|
Triggered from #45 (comment) by @wenzowski. Trying to fast forward Target branch ( commit 1f814e78b08f28546333e86c8f4c13fba6a2d30e (HEAD -> main, tag: v0.0.2, origin/main)
Author: Alec Wenzowski <alec@button.is>
Date: Thu Aug 6 01:30:17 2026 -0700
chore: release v0.0.2Pull request ( commit 22fd17e4e16fde8f2e2bdbf736869e9914f60f45 (pull_request/claude/ci-watch-handoff-3abw65)
Author: Claude <noreply@anthropic.com>
Date: Thu Aug 6 08:28:52 2026 +0000
feat(cli): emit the command surface as data via `batten spec`
Land the CLI-as-data spine validated by the CLOUD-20 spike. The command
surface is defined once as a clap tree and emitted at runtime as byte-stable
JSON by introspecting the live `clap::Command` (house-style §11), with the
§5 effect model merged in from a single table keyed by full command path.
- effect.rs: the Effect enum + one path-keyed table, fail-safe by
construction (a path absent from the table resolves to `ask`, never `read`).
- spec.rs: runtime introspection into a byte-stable spec, plus the derived
read-only allowlist (CLOUD-28) — filter(effect == read) over the same walk,
never a second hand-kept list.
- cli.rs: the `spec [--format json]` verb; the tree grows one verb at a time,
each addition kept honest by a completeness test that fails if any command
ships without an effect.
- run() now writes data output to an injected writer so the library stays
print-free and byte-stable; the binary passes stdout.
Refs CLOUD-26, CLOUD-27, CLOUD-28.Can't fast forward * 1f814e78b08f28546333e86c8f4c13fba6a2d30e chore: release v0.0.2
* 104ad62586946d157b08052c33e2324c967686dd fix(ci): authenticate git so release-plz can rebase onto main
| * 22fd17e4e16fde8f2e2bdbf736869e9914f60f45 feat(cli): emit the command surface as data via `batten spec`
|/
* a4d8e04daec2beec627ba93e12e144cc85ec2275 fix(ci): read checks with GITHUB_TOKEN in auto-release-land
commit a4d8e04daec2beec627ba93e12e144cc85ec2275
Author: Claude <noreply@anthropic.com>
Date: Thu Aug 6 08:10:39 2026 +0000
fix(ci): read checks with GITHUB_TOKEN in auto-release-land
The green-check verification called the check-runs API with
RELEASE_PLZ_TOKEN, a fine-grained PAT that lacks checks:read, so it 403'd
and the job failed. Split the tokens: read check status with the Actions
GITHUB_TOKEN (grant it checks:read), and post `/fast-forward` with
RELEASE_PLZ_TOKEN — the owner identity that actually triggers
fast-forward.yml.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdVURXVaz6yYmrnRW35g3BRebase locally, and then force push to |
22fd17e to
681e42e
Compare
|
Triggered from #45 (comment) by @wenzowski. Trying to fast forward Target branch ( commit 1f814e78b08f28546333e86c8f4c13fba6a2d30e (HEAD -> main, tag: v0.0.2, origin/main)
Author: Alec Wenzowski <alec@button.is>
Date: Thu Aug 6 01:30:17 2026 -0700
chore: release v0.0.2Pull request ( commit 681e42e45250eea0930c14aaac5b93c26bbce6d0 (pull_request/claude/ci-watch-handoff-3abw65)
Author: Claude <noreply@anthropic.com>
Date: Thu Aug 6 08:28:52 2026 +0000
feat(cli): emit the command surface as data via `batten spec`
Land the CLI-as-data spine validated by the CLOUD-20 spike. The command
surface is defined once as a clap tree and emitted at runtime as byte-stable
JSON by introspecting the live `clap::Command` (house-style §11), with the
§5 effect model merged in from a single table keyed by full command path.
- effect.rs: the Effect enum + one path-keyed table, fail-safe by
construction (a path absent from the table resolves to `ask`, never `read`).
- spec.rs: runtime introspection into a byte-stable spec, plus the derived
read-only allowlist (CLOUD-28) — filter(effect == read) over the same walk,
never a second hand-kept list.
- cli.rs: the `spec [--format json]` verb; the tree grows one verb at a time,
each addition kept honest by a completeness test that fails if any command
ships without an effect.
- run() now writes data output to an injected writer so the library stays
print-free and byte-stable; the binary passes stdout.
Refs CLOUD-26, CLOUD-27, CLOUD-28.Fast forwarding $ git push origin 681e42e45250eea0930c14aaac5b93c26bbce6d0:main
remote: error: GH013: Repository rule violations found for refs/heads/main.
remote: Review all repository rules at https://github.com/button-inc/batten/rules?ref=refs%2Fheads%2Fmain
remote:
remote: - 3 of 3 required status checks have not succeeded: .
remote:
To https://github.com/button-inc/batten.git
! [remote rejected] 681e42e45250eea0930c14aaac5b93c26bbce6d0 -> main (push declined due to repository rule violations)
error: failed to push some refs to 'https://github.com/button-inc/batten.git' |
|
/fast-forward Generated by Claude Code |
Lands the CLI-as-data spine validated by the CLOUD-20 spike — the first build work off the now-cleared Phase-0 blockers (CLOUD-6).
What
The command surface is defined once as a
claptree and emitted at runtime as byte-stable JSON by introspecting the liveclap::Command(house-style §11), with the §5 effect model merged in from a single table keyed by full command path.effect.rs— theEffectenum + one path-keyed table. Fail-safe by construction: a path absent from the table resolves toask, neverread.spec.rs— runtime introspection into a byte-stableCommandSpec, plus the derived read-only allowlist (CLOUD-28):filter(effect == read)over the same walk, never a second hand-kept list.cli.rs— thespec [--format json]verb. The tree grows one verb at a time; each addition is kept honest by a completeness test that fails if any command ships without an effect.run()now writes data output to an injected writer, so the library staysprint!-free and byte-stable (the workspace lints denyprint_stdout/print_stderr); the binary passes stdout.Tests
batten specemits parseable JSON on stdout, describes itself witheffect: "read", is byte-stable across runs, and--format jsonmatches the default.effect_for(unknown) == ask), completeness (no command resolves toask), and the derived allowlist is exactly the read commands.mise run cigreen locally.Scope
Establishes the spine and the
specverb; subsequent verbs from §2 land in their own issues, each adding its effect-table entry (guarded by the completeness test).--format kdl(§2) and the completions/man/markdown generation + drift test (CLOUD-69) are follow-ups.Refs CLOUD-26, CLOUD-27, CLOUD-28.
🤖 Generated with Claude Code
Generated by Claude Code