docs(governance): add AGENTS.md bridge + 3 historical ADRs (#36)

Integrates OCP with Tao's cross-device development system (Phase 1 L1).

- AGENTS.md: project-level tool-agnostic instructions (read by Cursor,
  OpenCode, Copilot, etc. in addition to Claude Code). Inherits from
  ~/.cc-rules/AGENTS.md.
- CLAUDE.md: prepends @AGENTS.md + @~/.cc-rules/AGENTS.md imports.
- docs/adr/0002-alignment-constitution.md: captures why ALIGNMENT.md
  exists (2026-04-11 drift response).
- docs/adr/0003-models-json-spot.md: captures v3.11.0 SPOT refactor.
- docs/adr/0004-openclaw-auto-sync.md: captures v3.11.0 auto-sync design.

ADRs numbered 0002-0004 because an untracked 0001-cross-device-system.md
already exists locally and was out of scope for this PR.

Governance/docs only. No code change. No version bump (not a release).

Co-authored-by: Tao Deng <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dtzp555-max
2026-04-21 19:20:26 +10:00
committed by GitHub
co-authored by taodeng Claude Opus 4.7
parent 497ff1dcd2
commit 2ecc4945ad
5 changed files with 277 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
# 0003 — `models.json` as Single Source of Truth
- **Date**: 2026-04-20
- **Status**: Accepted
- **Authors**: Tao Deng, Claude Opus 4.7 (drafting)
- **Related**: PR #30, commit c6f7850; precursor to ADR 0004
## Context
OCP's model catalog (the mapping from short aliases like `sonnet` and `opus` to full model IDs with context-window metadata) had organically drifted into three independent locations:
1. `server.mjs``MODEL_MAP` and `MODELS` arrays, hardcoded at the top of the file. This was the runtime authority for `/v1/models` responses and alias resolution.
2. `setup.mjs` — a separate `MODELS` constant, unchanged since the v3.0 era. Used only at first-install time to seed user config; by v3.10 it was stale and listed no Claude 4.x models at all.
3. `~/.openclaw/openclaw.json` (on user machines) — written exactly once by `setup.mjs` during initial OCP install and never refreshed. A user who installed OCP in v3.0 and ran `ocp update` faithfully through v3.10 still had their OpenClaw config listing only three pre-Claude-4 models.
By the v3.10.0 release, Opus 4.7 was correctly present in location (1) and absent from (2) and (3). The symptom reaching users: native Claude Code saw the new model immediately (because it queries `/v1/models` live from server.mjs), but OpenClaw users saw nothing new, and new-installers via `setup.mjs` got an incomplete initial config. Three distinct bug reports in the two weeks following v3.10.0.
The drift was structural, not a bug in any one file. The files disagreed because there was no mechanism requiring them to agree.
## Decision
Extract all model metadata into `models.json` at the repo root. `server.mjs` and `setup.mjs` both read this file and derive their in-memory `MODEL_MAP`/`MODELS` structures from it. The file is committed to the repo; it is neither generated nor cached.
Shape (summarized):
- `models` — array of entries, each with `id` (full model ID), `alias` (short name), `context_window`, and flags where relevant.
- `default_alias` — which alias resolves when the client sends an unknown or empty model.
Migration approach:
1. Hand-populate `models.json` from the v3.10.0 `server.mjs` `MODEL_MAP` values.
2. Rewrite `server.mjs` to load and index `models.json` at startup.
3. Rewrite `setup.mjs` to derive its `MODELS` constant from the same file.
4. Verify byte-equivalence: the derived `MODEL_MAP` in v3.11.0 must be a byte-identical superset of the v3.10.0 hardcoded `MODEL_MAP`. This is checked by a one-shot comparison script during the refactor PR; no regression is permitted.
Post-refactor, the contract for adding a model is: edit `models.json`, open a PR, reviewer sanity-checks the `id` string against Anthropic's model announcement, merge. No other file changes.
## Consequences
**Positive**
- Single edit point eliminates the "updated one place, forgot the other" failure mode structurally.
- `setup.mjs`'s latent staleness is repaired as a side effect — new-installers now get a fresh model list.
- Opens the door to ADR 0004 (OpenClaw auto-sync), which requires a file-based SPOT to sync from.
- The `models.json` format is stable, Markdown-friendly JSON, easy to diff in code review.
**Negative**
- One additional file to load at server startup (negligible cost, but now a startup dependency).
- Schema drift risk: if anyone adds a new field to `models.json` that `server.mjs` or `setup.mjs` doesn't know about, the field is silently ignored. A future schema version tag may be warranted if the format grows.
- `models.json` parse failure is now a fatal startup error; previously, bad model config required editing source. Consider this a feature, not a regression.
**Follow-ons**
- ADR 0004 (OpenClaw auto-sync) consumes `models.json` directly in `scripts/sync-openclaw.mjs`.
- Future additions (per-model pricing, per-model capability flags, etc.) belong in `models.json`, not scattered back across `server.mjs`.
- The README "Available Models" table is now derived documentation and its source of truth should be pinned to `models.json` in the release_kit overlay.
## Alternatives considered
**(a) Keep the three locations, enforce sync by manual review discipline.** A reviewer checklist item: "did you update all three places?" Rejected: the drift had already demonstrated that manual discipline is insufficient when the three files are in unrelated sections of the diff. Human reviewers routinely miss the third file. The 2026-04-11 alignment drift had already taught the project that discipline-only approaches fail.
**(b) YAML with SOPS field-level encryption.** Some projects prefer YAML for multi-line string readability and use SOPS to encrypt sensitive fields. Rejected: OCP's model catalog contains no secrets — model IDs, aliases, and context windows are all public information published by Anthropic. YAML adds a parser dependency and SOPS adds a decryption step at startup, both for zero benefit. JSON is already native to Node, and `models.json` is easy to diff line-by-line in GitHub review UI.
**(c) Fetch the model list live from Anthropic at server start.** Rejected: `cli.js` does not perform this operation, so per `ALIGNMENT.md` Rule 2 it is out of scope for OCP. Additionally, a live fetch introduces a startup-time network dependency and an availability coupling to Anthropic that OCP is explicitly designed to avoid (OCP is the gateway, not another consumer).