From 03817c72acef85cb06f15c7ddfa7c3bb16331d02 Mon Sep 17 00:00:00 2001 From: Ryan Wolfe Date: Thu, 25 Jun 2026 15:40:16 -0400 Subject: [PATCH 1/2] feat: roll up to Agent CLI Guidelines v0.4.0 Add a machine-verifiable conformance block to `rivr schema` and pin the README conformance to v0.4.0 Full. - version: add `const Spec = "0.4.0"` - schema: emit `conformance` { spec, version, level: Full } - README: pin badge + add a Conformance statement - regenerate schema golden Backpressure for the scraped Amazon backend is already present and wired: internal/throttle is a persistent, cross-process circuit-breaker (load/block/clear via internal/provider/common.go), so no throttle work is needed in this PR. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_012UFrhC6bXVpoiiL3yhj2HH --- README.md | 9 ++++++++- internal/cli/misc.go | 3 +++ internal/cli/testdata/schema.golden.json | 5 +++++ internal/version/version.go | 3 +++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ae036b2..7146a14 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ fencing, and stdin/keyring secrets. [![ci](https://github.com/rnwolfe/rivr/actions/workflows/ci.yml/badge.svg)](https://github.com/rnwolfe/rivr/actions/workflows/ci.yml) [![release](https://img.shields.io/github/v/release/rnwolfe/rivr?sort=semver)](https://github.com/rnwolfe/rivr/releases/latest) [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) -[![Agent CLI Guidelines: Full](https://aclig.dev/badge/agent-cli-guidelines-full.svg)](https://aclig.dev/conformance/) +[![Agent CLI Guidelines v0.4.0: Full](https://aclig.dev/badge/agent-cli-guidelines-full.svg)](https://aclig.dev/conformance/) ![rivr demo](./demo/rivr.gif) @@ -133,6 +133,13 @@ Global flags: `--json`/`--format json|plain|tsv`, `--select a,b.c`, `--limit N`, `9` upstream / schema drift · `10` config · `11` unsupported by provider · `13` input required. Full table: `rivr schema`. +## Conformance + +rivr conforms to the [Agent CLI Guidelines](https://aclig.dev/) **v0.4.0** at the **Full** +level. The contract version is machine-verifiable from the binary — `rivr schema` emits a +`conformance` block (`{ spec: "agent-cli-guidelines", version: "0.4.0", level: "Full" }`), +so an agent can confirm the standard it was built against without trusting this README. + ## Affiliate attribution (how rivr is funded) Product deep links are tagged with an Amazon Associates ID by default — if a referred link diff --git a/internal/cli/misc.go b/internal/cli/misc.go index 64af690..4f7863f 100644 --- a/internal/cli/misc.go +++ b/internal/cli/misc.go @@ -141,6 +141,9 @@ func (c *SchemaCmd) Run(rt *Runtime) error { "tool": "rivr", "version": version.String(), "schemaVersion": provider.SchemaVersion, + "conformance": map[string]any{ + "spec": "agent-cli-guidelines", "version": version.Spec, "level": "Full", + }, "commands": nodeToMap(k.Model.Node), "exit_codes": errs.Table(), "providers": provider.Names(), diff --git a/internal/cli/testdata/schema.golden.json b/internal/cli/testdata/schema.golden.json index 26b2d9d..10ae2ba 100644 --- a/internal/cli/testdata/schema.golden.json +++ b/internal/cli/testdata/schema.golden.json @@ -239,6 +239,11 @@ } ] }, + "conformance": { + "level": "Full", + "spec": "agent-cli-guidelines", + "version": "0.4.0" + }, "exit_codes": { "auth_required": 4, "cancelled": 130, diff --git a/internal/version/version.go b/internal/version/version.go index 1de7c8c..35d4581 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -2,6 +2,9 @@ package version import "runtime/debug" +// Spec is the Agent CLI Guidelines version this tool conforms to (declared in `schema`). +const Spec = "0.4.0" + // version is a plain literal so -ldflags "-X .../version.version=vX" can override it. // It MUST NOT be initialized from a function call (golang/go#64246). var version = "dev" From 7aa3eff52d19473f5a840f921cf530275086f1ec Mon Sep 17 00:00:00 2001 From: Ryan Wolfe Date: Thu, 25 Jun 2026 16:03:28 -0400 Subject: [PATCH 2/2] fix: address PR review (v0.4.0 rollout) - README: rewrite the conformance example as a valid JSON fenced block (was a JS object literal with bare keys), matching `rivr schema` output. - update: send a User-Agent on the version-check request (GitHub's REST API rejects UA-less requests) and surface non-200 responses as errors; aligns with the examplectl Go version-check idiom. Add a test asserting the User-Agent is sent. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_012UFrhC6bXVpoiiL3yhj2HH --- README.md | 14 ++++++++++++-- internal/update/update.go | 5 +++++ internal/update/update_test.go | 20 ++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7146a14..644bb7f 100644 --- a/README.md +++ b/README.md @@ -137,8 +137,18 @@ Full table: `rivr schema`. rivr conforms to the [Agent CLI Guidelines](https://aclig.dev/) **v0.4.0** at the **Full** level. The contract version is machine-verifiable from the binary — `rivr schema` emits a -`conformance` block (`{ spec: "agent-cli-guidelines", version: "0.4.0", level: "Full" }`), -so an agent can confirm the standard it was built against without trusting this README. +`conformance` block, so an agent can confirm the standard it was built against without +trusting this README: + +```json +{ + "conformance": { + "level": "Full", + "spec": "agent-cli-guidelines", + "version": "0.4.0" + } +} +``` ## Affiliate attribution (how rivr is funded) diff --git a/internal/update/update.go b/internal/update/update.go index 2d49e8e..e696987 100644 --- a/internal/update/update.go +++ b/internal/update/update.go @@ -7,6 +7,7 @@ package update import ( "context" "encoding/json" + "fmt" "net/http" "os" "path/filepath" @@ -65,11 +66,15 @@ func fetchLatest(ctx context.Context) (string, error) { defer cancel() req, _ := http.NewRequestWithContext(ctx, http.MethodGet, apiURL(), nil) req.Header.Set("Accept", "application/vnd.github+json") + req.Header.Set("User-Agent", "rivr-version-check") // GitHub's REST API rejects requests with no UA resp, err := http.DefaultClient.Do(req) if err != nil { return "", err } defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("release source: %s", resp.Status) + } var body struct { TagName string `json:"tag_name"` } diff --git a/internal/update/update_test.go b/internal/update/update_test.go index c78240f..5f75dae 100644 --- a/internal/update/update_test.go +++ b/internal/update/update_test.go @@ -57,3 +57,23 @@ func TestCheckUsesEndpointAndCache(t *testing.T) { t.Fatalf("force should re-fetch; hits=%d", hits) } } + +// TestFetchSetsUserAgent guards the GitHub-API contract: requests with no User-Agent are +// rejected (HTTP 403), so the version check must always send one. +func TestFetchSetsUserAgent(t *testing.T) { + t.Setenv("XDG_STATE_HOME", t.TempDir()) + var gotUA string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotUA = r.Header.Get("User-Agent") + w.Write([]byte(`{"tag_name":"v0.9.0"}`)) + })) + defer srv.Close() + t.Setenv("RIVR_UPDATE_URL", srv.URL) + + if _, _, err := Check(context.Background(), "v0.2.0", true, time.Unix(1_750_000_000, 0)); err != nil { + t.Fatal(err) + } + if gotUA == "" { + t.Fatal("version check sent no User-Agent; GitHub's REST API rejects such requests") + } +}