From fd8e8cbbd7d1c4edfd36b7f2ed1a8d6148b69925 Mon Sep 17 00:00:00 2001 From: aygea Date: Mon, 19 Oct 2026 23:25:21 -0700 Subject: [PATCH] docs: AGENTS.md + evidence-backed scaffold (state, trials, decisions, handoff) - AGENTS.md operating rules incl. Gitea SSH port-2222 note + known_hosts incident - CURRENT_STATE / TODO / CHANGELOG / TRIALS - trials: endpoint-key pairing; config-merge safety matrix 14/14 (verify.sh + output) - docs: DECISIONS (mcode 0.6.12 bundle facts, digest-pinned), FEATURE-MATRIX, PROJECT-HANDOFF - handoffs: TEMPLATE + 2026-10-19 initial-install record --- .gitignore | 12 +++ AGENTS.md | 84 +++++++++++++++++++ CHANGELOG.md | 29 +++++++ CURRENT_STATE.md | 41 +++++++++ README.md | 9 ++ TODO.md | 27 ++++++ TRIALS.md | 10 +++ docs/DECISIONS.md | 84 +++++++++++++++++++ docs/FEATURE-MATRIX.md | 20 +++++ docs/PROJECT-HANDOFF.md | 37 ++++++++ docs/README.md | 5 ++ evidence/README.md | 7 ++ handoffs/2026-10-19-initial-install.md | 75 +++++++++++++++++ handoffs/TEMPLATE.md | 39 +++++++++ tooling/README.md | 18 ++++ trials/README.md | 11 +++ .../config-merge-safety-2026-10-19/output.txt | 15 ++++ .../config-merge-safety-2026-10-19/record.md | 19 +++++ .../config-merge-safety-2026-10-19/verify.sh | 53 ++++++++++++ .../record.md | 24 ++++++ 20 files changed, 619 insertions(+) create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 CHANGELOG.md create mode 100644 CURRENT_STATE.md create mode 100644 TODO.md create mode 100644 TRIALS.md create mode 100644 docs/DECISIONS.md create mode 100644 docs/FEATURE-MATRIX.md create mode 100644 docs/PROJECT-HANDOFF.md create mode 100644 docs/README.md create mode 100644 evidence/README.md create mode 100644 handoffs/2026-10-19-initial-install.md create mode 100644 handoffs/TEMPLATE.md create mode 100644 tooling/README.md create mode 100644 trials/README.md create mode 100644 trials/config-merge-safety-2026-10-19/output.txt create mode 100644 trials/config-merge-safety-2026-10-19/record.md create mode 100755 trials/config-merge-safety-2026-10-19/verify.sh create mode 100644 trials/mcode-endpoint-key-pairing-2026-10-19/record.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..09b9f3b --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# scratch + local outputs (never durable evidence) +tmp/ +*.log + +# editor / OS noise +.DS_Store +*.swp + +# never commit credentials or caches +credential.json +*.key +quota.json diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..7440c2e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,84 @@ +# AGENTS.md — mcode-status + +Aygea z.ai GLM usage segment for the MiniMax Code statusline. Three shipped files: +`zai-usage.sh` (the segment), `install.sh` (self-extracting installer with an embedded +copy), `README.md` (public-facing docs). No `src/` — root is the project. + +## Starting or resuming work + +1. Read `CURRENT_STATE.md`, then relevant `TODO.md` entries and the latest file in + `handoffs/`. Check `TRIALS.md` before repeating any investigation. +2. Inspect `git status` / `git log` before editing. The remote is + `git@git.itsaygea.com:admin/mcode-sl.git` (see SSH notes below). +3. Pick one bounded objective with explicit acceptance criteria; finish it before + starting another. + +## Storage and isolation + +- Scratch work goes in `tmp/` (git-ignored). Durable evidence goes in `trials/-/` + or `evidence/`. OS temp dirs are not durable evidence. +- **Never commit secrets.** The z.ai key lives in SecretVault (`zai_api_key`) and is read + at runtime via `secretvault run`; `~/.secretvault/credential.json` never enters the repo. +- Host-specific paths (e.g. `/home/aygea/.minimax-code/releases//...`) are recorded + in docs as facts about *this* machine, not portable assumptions. + +## Evidence and confidence + +Mark every technical claim in docs as `confirmed` (directly verified, scope stated), +`inferred` (supported interpretation), or `unknown` (untested). Record input paths, +SHA-256 digests, tool versions, and exact commands. Rule of thumb here: + +- Anything read out of the mcode bundle is confirmed **for that release only** + (`0.6.12`, digests in `docs/DECISIONS.md`); re-verify after every mcode update. +- Anything not run on real hardware (e.g. macOS) stays `unknown`, however portable + the code looks. +- The safety matrix in `trials/config-merge-safety-2026-10-19/` is the regression gate + for `install.sh` — run it before committing installer changes. + +## Trials + +Uncertain approach or capability question → bounded trial under +`trials/-/` with question, scope, commands, expected vs observed, +verdict (`confirmed` / `rejected` / `inconclusive` / `blocked`), and a repeat guard. +Conventions + template: `trials/README.md`. Index: `TRIALS.md`. Preserve failed runs. + +## Implementation and verification + +- `install.sh` embeds a copy of `zai-usage.sh`. Checkout installs prefer the sibling + file; after editing `zai-usage.sh`, regenerate the embedded copy (command in README) + so `curl | bash` stays identical — the S5 check in the safety matrix enforces this. +- `bash -n` both scripts, then run the safety matrix, before committing. +- The statusline contract: always `exit 0`, print nothing when unknown, never block on + the network (refresh is a detached background job). Violating this freezes the TUI. + +## Collaboration and Git + +- Commit reviewed work at stage boundaries; push to `origin main` when the work is + verified (established policy for this repo). Report push failures plainly. +- Preserve others' uncommitted work; never reset/discard what you didn't write. + +### SSH to Gitea (read before touching the remote) + +`git.itsaygea.com` runs **Gitea in Docker with SSH on port 2222**. Port 22 on that +hostname is the *host machine's own sshd* — a different server with different host keys. + +- `~/.ssh/config` carries the stanza that makes plain `git push` work: + `Host git.itsaygea.com` → `Port 2222`, `User git`, `IdentityFile ~/.ssh/id_ed25519`. +- Registered account key: **"Mewtwo Aygea"**, + `SHA256:Xc++/NLDGWbXqnzLWleNOhK8/NIgtSBN0xGxNx3gUfs` (= local `id_ed25519.pub`). +- Gitea host key (ED25519) accepted 2026-10-19: + `SHA256:VpdMjgEGpmRPyLhbOpYvrFNWNAxglINkKTgJo5T/sOQ`. +- **Incident record:** on 2026-10-19 a first probe hit port 22, produced a + "REMOTE HOST IDENTIFICATION HAS CHANGED" warning, and wrong (host) keys were briefly + appended to `~/.ssh/known_hosts` under this hostname. They were removed and replaced + with the real port-2222 keys. Repeat guard: any future host-key warning for + `git.itsaygea.com` must be checked against the fingerprint above **and** rescanned on + port 2222 (`ssh-keyscan -p 2222`) — never trust a key captured from port 22. If the + server was not reinstalled, treat it as an incident. + +## Stage completion and handoff + +At a meaningful boundary: run acceptance checks → update `CURRENT_STATE.md`, `TODO.md`, +`CHANGELOG.md`, `TRIALS.md` → write a handoff under `handoffs/` (template there) → +review the diff → commit → push → report handoff path, commit hash, push result, and +working-tree status separately. Not after every minor action. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5ed226f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,29 @@ +# CHANGELOG + +Reverse-chronological. Meaningful changes only; each entry points at evidence. + +## 2026-10-19 — initial release: segment, installer, docs scaffold + +- `zai-usage.sh` — statusline custom command: Aygea-palette `🔥 % · ()` + segment; SecretVault-first auth (`secretvault run`, key never in argv) with + `~/.secretvault/credential.json` fallback; cache-shared with the Claude Aygea + statusline (`~/.cache/aygea-sl/quota.json`, schema `{pct, reset_iso, ts}`); + detached flock-guarded background refresh (no cron/systemd); always exit 0; + GNU/BSD date + flock/setsid fallbacks for macOS. +- `install.sh` — self-extracting installer (`curl | bash`): installs to + `~/.local/bin/mcode-zai-usage`, checks SecretVault presence (never prints the secret), + surgically merges the `tui:` section into `~/.minimax/config.yaml` (atomic + temp+fsync+rename, 0600, timestamped backup before change, duplicate-structure + refusal, byte-identical outside the tui block), primes the cache, `--uninstall` mode. +- Fixed during development: EXIT trap referencing function-local vars under `set -u`; + uninstall mode-name mismatch (`uninstall` vs `remove`); TOP regex never capturing the + key name (false "duplicate top-level keys" refusals); embedded-copy forward reference + (0-byte installs in piped mode); double-newline on re-embed. +- Config merge hardening per user request: atomicity + previous-entry checks + format + safety (see `docs/DECISIONS.md` D5, trial `config-merge-safety-2026-10-19`). +- Installed on this machine (backup `~/.minimax/config.yaml.bak.20261019-231642`), + cache primed `🔥 1%`; pushed to `git.itsaygea.com/admin/mcode-sl` (`main`). +- SSH: corrected Gitea-on-2222 setup; removed wrong port-22 host keys from + `~/.ssh/known_hosts` (details in `AGENTS.md` → "SSH to Gitea"). +- Docs scaffold: AGENTS/CURRENT_STATE/TODO/CHANGELOG/TRIALS + `docs/`, `trials/`, + `handoffs/`, `tooling/`, `evidence/`. diff --git a/CURRENT_STATE.md b/CURRENT_STATE.md new file mode 100644 index 0000000..9b9eeb7 --- /dev/null +++ b/CURRENT_STATE.md @@ -0,0 +1,41 @@ +# CURRENT_STATE + +Updated: 2026-10-19 + +## Objective + +Self-contained, secret-safe z.ai GLM 5h-usage segment for the MiniMax Code statusline, +installable on 1 macOS + 2 Ubuntu systems with one `curl | bash` line. + +## Verified capabilities (this machine, mcode 0.6.12, Ubuntu-based PVE host) + +- `confirmed` — Segment renders real quota data: `🔥 1% · 4:16a(4h59m)` right after + install (cache primed through SecretVault key against `https://api.z.ai`). +- `confirmed` — Config merge safety matrix 14/14 + (`trials/config-merge-safety-2026-10-19/output.txt`): atomic write, 0600 on new files, + backup equals pre-merge original, duplicate-structure refusal, provider untouched, + piped-install embed identical, clean uninstall. +- `confirmed` — Vault key pairs with `api.z.ai` (200); old credential.json clientKey + pairs with the `vault.itsaygea.com` proxy (200); vault key against the proxy → 401. + (`trials/mcode-endpoint-key-pairing-2026-10-19/record.md`) +- `confirmed` — mcode statusline mechanics for 0.6.12: `tui.statusLine` + `tui.customStatusLine` + in `~/.minimax/config.yaml`; JSON on stdin; stdout becomes the `custom-command` item on + exit 0; `colorMode: ansi` passes ANSI through; intervalSeconds ≥10, timeoutMs 500–30000. + Evidence: bundle reads in `docs/DECISIONS.md` (release digests recorded). +- `confirmed` — Pushed to `git@git.itsaygea.com:admin/mcode-sl.git` (port 2222 SSH). + +## Active work + +None in flight. Last stage (initial install + push) completed 2026-10-19. + +## Blockers + +- Visual confirmation of the rendered segment in the live TUI requires the user to + restart MiniMax Code. Until then, ANSI/emoji rendering in the statusline is + `inferred` (config accepted by the parser; passthrough path verified in code, not on screen). + +## Exact next action + +User restarts the MiniMax Code TUI and confirms the segment renders (colors, emoji, no +misalignment). Then roll out to the two Ubuntu machines + macOS via the curl one-liner +and record results in `TODO.md` / `docs/FEATURE-MATRIX.md`. diff --git a/README.md b/README.md index 453f276..1a3dda8 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,15 @@ Installer env overrides: `MCODE_SL_ITEMS` (item list), `MCODE_SL_INTERVAL`, `MCO curl -fsSL https://git.itsaygea.com/admin/mcode-sl/raw/branch/main/install.sh | bash -s -- --uninstall ``` +## Documentation + +- `AGENTS.md` — operating instructions for humans + agents (incl. Gitea SSH notes) +- `CURRENT_STATE.md` — where the project stands and the exact next action +- `TODO.md` — prioritized work with acceptance criteria +- `CHANGELOG.md` / `TRIALS.md` — change log and experiment index +- `docs/` — decisions (ADR-style), feature matrix, handoff protocol +- `handoffs/` — stage continuation records; `tooling/` — verified toolchain + ## Development Requires `jq` + `curl`; `secretvault` optional (fallback: credential.json); `python3` for the config merge. Test locally: diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..ed7c071 --- /dev/null +++ b/TODO.md @@ -0,0 +1,27 @@ +# TODO + +## Now + +- [ ] **Visual TUI verification** — user restarts MiniMax Code; confirm the + `custom-command` segment renders with Aygea colors, emoji, and no width misalignment. + Acceptance: screenshot or user confirmation; move rendering from `inferred` to + `confirmed` in `docs/FEATURE-MATRIX.md`. +- [ ] **Ubuntu rollout ×2** — run the curl one-liner on both Ubuntu boxes; each needs the + `zai_api_key` SecretVault secret (or credential.json). Acceptance: `printf '{}' | mcode-zai-usage` + prints a segment on both; entry recorded in FEATURE-MATRIX. + +## Next + +- [ ] **macOS rollout** — same one-liner on the Mac. Script is written portable + (`date -r` fallback, no-`flock`/no-`setsid` degrade, `vm_stat` memory) but has never + run on macOS: treat as `unknown` until tested. Acceptance: install + segment on macOS. +- [ ] **mcode-update resilience check** — after the next mcode release, re-grep the new + bundle for `customStatusLine`/`statusLineItems` handling and re-check the clamps + documented in `docs/DECISIONS.md` D2; update digests there. + +## Deferred + +- Optional `AYGEA_SL_MEM` memory-segment polish on macOS (page-size assumptions in + `vm_stat` parsing are untested there). +- Consider a `--json` inspection mode for debugging cache state. Rejected for now: + scope creep against "little self-contained tool". diff --git a/TRIALS.md b/TRIALS.md new file mode 100644 index 0000000..ed5eaa2 --- /dev/null +++ b/TRIALS.md @@ -0,0 +1,10 @@ +# TRIALS — index + +Conventions and template: `trials/README.md`. Verdicts: `confirmed` / `rejected` / +`inconclusive` / `blocked`. Before repeating a rejected/inconclusive trial, cite it and +state what changed. + +| Date | Trial | Verdict | Record | +|---|---|---|---| +| 2026-10-19 | Which endpoint accepts which z.ai key (vault key vs credential.json clientKey) | confirmed | `trials/mcode-endpoint-key-pairing-2026-10-19/record.md` | +| 2026-10-19 | install.sh config-merge safety matrix (atomicity, backup, refusal, embed, uninstall) | confirmed | `trials/config-merge-safety-2026-10-19/` (14/14, `output.txt`) | diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md new file mode 100644 index 0000000..4b314e2 --- /dev/null +++ b/docs/DECISIONS.md @@ -0,0 +1,84 @@ +# DECISIONS + +Stable IDs; newest at the bottom. Each records context, choice, alternatives, consequences. + +## D1 — Vault-first credentials, `api.zai` direct; credential.json fallback + +- **Context:** the Aygea Claude statusline used `~/.secretvault/credential.json` + (`url` + `clientKey` → `vault.itsaygea.com` proxy). The user wants this repo public + and machines to need nothing but their existing SecretVault (`zai_api_key`). +- **Choice:** read `zai_api_key` via `secretvault run` (name from env, default + `zai_api_key`), hit `https://api.z.ai/api/monitor/usage/quota/limit`; fall back to + credential.json → `${url}/proxy/zai/...`. Key reaches curl via a 0600 header file + (`--header @file`), never argv. +- **Alternatives:** bake the proxy URL + require credential.json everywhere (rejected: + repo would document private infra as a requirement); store JSON {url,key} in the + vault (rejected: existing secret is a plain key). +- **Consequences:** one secret per machine is the only setup; trial + `mcode-endpoint-key-pairing-2026-10-19` pins the pairing. Proxy users still work. + +## D2 — mcode statusline mechanics (verified facts, release-pinned) + +Confirmed by reading the 0.6.12 bundle — re-verify after every mcode update. +Files (SHA-256): `chunks/launcher-AVQRYDKB.js` `2c4337e3…edfbe3`, +`chunks/chunk-X3PES5WL.js` `600c23d…09ee5` under +`~/.minimax-code/releases/0.6.12/lib/node_modules/@minimax-ai/code/`. + +- Config source: `/config.yaml` → `tui.statusLine` (array) + + `tui.customStatusLine` (`Pv()` in launcher chunk). +- Valid statusLine items: `current-dir, session-title, git-branch, review-link, + plan-mode, approval-mode, model-with-reasoning, model, context-window, subagent, + token-quota, cache-read-ratio, context-remaining, context-meter, custom-command`. +- Custom command runner: only active when `custom-command` is in `statusLine` **and** + `build-mode` is not; command required (non-empty). Schema: + `display: inline|block`, `position: above|below`, `colorMode: plain|ansi`, + `intervalSeconds` (default 0 = off, clamp ≥10), `timeoutMs` (default 5000, + clamp 500–30000), block `maxLines` default 3 (clamp 1–5). +- Invocation: `{command}` parsed + spawned with `cwd = workspace_dir`, JSON on stdin + (`{protocol, event: startup|interval|session-change|workspace-change, session_id, + workspace_dir, model, session_title, tui_version}`), stdout capped ~8 KiB + (exact cap expression `Q1` not disambiguated: `8*1024` vs `8e3` — inferred). + stdout becomes the `custom-command` item **only on exit 0 without timeout**; + inline mode renders the first line; `colorMode: ansi` keeps escape codes when the + terminal color level > 0, strips otherwise. +- **Consequence:** our script must be silent-fail (`exit 0`, empty output when unknown) + and must not rely on stdin content. + +## D3 — mcode is the scheduler; refresh decoupled in-process + +- **Context:** the Claude statusline needed a systemd timer because Claude Code has no + interval hook. mcode's `customStatusLine.intervalSeconds` re-runs the command itself. +- **Choice:** no cron/systemd. On each call: fresh cache (≤150s) → print; stale → spawn + detached (`setsid`, fallback `& disown`) flock-guarded refresh (`--refresh-bg`) and + show the still-valid value (≤360s) or nothing. +- **Consequences:** zero extra services; segment self-heals; offline machines just hide + the segment after 6 min. Timer coexistence is harmless (same cache file). + +## D4 — Shared cache with the Claude Aygea statusline + +- **Choice:** keep schema `{pct, reset_iso, ts}` at `~/.cache/aygea-sl/quota.json` + exactly as the Claude refresher writes it (reset written as local ISO; epoch + conversions have GNU/BSD branches). +- **Consequence:** both ecosystems interop; any writer refreshes both. Constrained the + parser to ISO strings instead of the internally simpler `reset_ms`. + +## D5 — Config merge safety rails + +- **Context:** user requirement: atomic, previous-entry aware, must never break a config + holding API keys. Two early bugs (in-place write; backup taken after merge) proved the point. +- **Choice:** python3 stdlib line surgery limited to the `tui:` block; refuses multiple + `tui:` blocks or duplicate keys; validates result (structural + PyYAML when available); + writes temp + fsync + `os.replace`; preserves mode (0600 for new); timestamped backup + copied **before** first modification; byte-exact elsewhere (incl. trailing newline). +- **Alternatives:** PyYAML full round-trip (rejected: reformats/comments lost); yq + (rejected: extra dependency on every machine). +- **Consequences:** merge is monotonic and reviewable; `docs/FEATURE-MATRIX.md` gates + remaining platform risk. + +## D6 — Public repo + Gitea over SSH port 2222 + +- **Choice:** repo `git.itsaygea.com/admin/mcode-sl` (`main`); remote via SSH; the + curl one-liner points at `…/raw/branch/main/install.sh`. No secrets in the repo by + design (D1). +- **Consequences:** see `AGENTS.md` → "SSH to Gitea" for the port-22 incident record, + accepted host-key fingerprint, and the repeat guard. diff --git a/docs/FEATURE-MATRIX.md b/docs/FEATURE-MATRIX.md new file mode 100644 index 0000000..f8b0eb7 --- /dev/null +++ b/docs/FEATURE-MATRIX.md @@ -0,0 +1,20 @@ +# FEATURE-MATRIX + +Status: `confirmed` (verified within stated coverage) / `inferred` / `unknown`. +Evidence links point at trials, digests, or recorded commands. + +| Capability | Status | Coverage / limits | Evidence | +|---|---|---|---| +| Quota fetch via SecretVault key → `api.z.ai` | confirmed | this machine; key `zai_api_key` | `trials/mcode-endpoint-key-pairing-2026-10-19/record.md` | +| Quota fetch via credential.json → `vault.itsaygea.com` proxy | confirmed | code path exercised in dev; falls back only | same record | +| Statusline segment output (value, clock, remaining, colors, thresholds) | confirmed | plain + 256 + truecolor modes exercised with mock caches | session commands, `CHANGELOG` 2026-10-19 | +| Stale/hidden behavior (≤150s fresh; ≤360s stale shown; >360s hidden) | confirmed | mock-cache tests, exit 0 always | session commands | +| mcode config schema + clamps (0.6.12) | confirmed | release-pinned; re-check on updates | `docs/DECISIONS.md` D2 | +| Config merge: atomic write, 0600, backup-before-change, refusal, byte-preservation, uninstall | confirmed | Linux host, 14/14 matrix | `trials/config-merge-safety-2026-10-19/` | +| Piped (`curl \| bash`) install with embedded copy | confirmed | embed byte-identical (S5) | same | +| Segment renders in live mcode TUI (ANSI + emoji) | **inferred** | passthrough verified in code; not yet seen on screen | D2; pending user restart | +| macOS end-to-end (install, date -r, no flock/setsid, `install -m`, vm_stat) | **unknown** | written portable, never run on macOS | TODO | +| Ubuntu rollout ×2 | **unknown** | not yet executed | TODO | +| secretvault CLI present + secret readable on other machines | **unknown** | assumed per user statement; verify at rollout | TODO | +| Background refresh survives mcode process-group kills | confirmed (by construction) | `setsid` detach; not adversarially tested | D3 rationale | +| mcode update resilience | **unknown** | bundle re-read required each release | D2 repeat guard | diff --git a/docs/PROJECT-HANDOFF.md b/docs/PROJECT-HANDOFF.md new file mode 100644 index 0000000..f625958 --- /dev/null +++ b/docs/PROJECT-HANDOFF.md @@ -0,0 +1,37 @@ +# PROJECT-HANDOFF + +How to resume work in this repo. + +## Entry sequence + +1. `CURRENT_STATE.md` — objective, what's confirmed, exact next action. +2. `TODO.md` — prioritized work with acceptance criteria. +3. Latest file in `handoffs/` — where the last stage stopped and why. +4. `TRIALS.md` — don't repeat what a verdict already settled. +5. `git status` + `git log` — see what's in flight. + +## Authoritative records + +- Decisions + verified mcode internals: `docs/DECISIONS.md` (D2 is release-pinned — + re-verify after mcode updates). +- Capability truth table: `docs/FEATURE-MATRIX.md` (update status as evidence lands). +- Regression gate for the installer: `trials/config-merge-safety-2026-10-19/verify.sh` + (must pass 14/14 before committing installer changes). +- Host-specific facts (Gitea SSH on 2222, key fingerprints): `AGENTS.md` → "SSH to Gitea". + +## Handoff protocol + +At a meaningful stage boundary write `handoffs/-.md` from +`handoffs/TEMPLATE.md`: stopping point, verified results + evidence links, corrected +assumptions, blockers, exact next action with acceptance criteria, reproduction +commands, and git state (branch, commit, push result). Preserve prior handoffs; link +artifacts instead of duplicating logs. + +## Environment assumptions (this project) + +- Linux host `mewtwo` (Ubuntu-based, PVE); MiniMax Code 0.6.12 at + `~/.minimax-code/releases/0.6.12/`; data dir `~/.minimax/`. +- `secretvault` CLI at `~/.local/bin/secretvault`; secret `zai_api_key` (production). +- Remote: `git@git.itsaygea.com:admin/mcode-sl.git` — port 2222, see `AGENTS.md`. + +Nothing above is portable to other machines without re-verification (see FEATURE-MATRIX). diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..e470a34 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,5 @@ +# docs + +- `PROJECT-HANDOFF.md` — how to resume work here; where authoritative records live. +- `DECISIONS.md` — indexed decisions (ADR-style) with evidence. +- `FEATURE-MATRIX.md` — capability × verification status; the honest state of the world. diff --git a/evidence/README.md b/evidence/README.md new file mode 100644 index 0000000..0cba9f3 --- /dev/null +++ b/evidence/README.md @@ -0,0 +1,7 @@ +# evidence + +Shared evidence that does not belong to a single trial (captured command outputs, +environment snapshots, digest manifests). Trial-specific evidence stays inside its +`trials/-/` directory. + +Currently empty — evidence for the initial stage lives in the trial directories. diff --git a/handoffs/2026-10-19-initial-install.md b/handoffs/2026-10-19-initial-install.md new file mode 100644 index 0000000..0ed615f --- /dev/null +++ b/handoffs/2026-10-19-initial-install.md @@ -0,0 +1,75 @@ +# Handoff: 2026-10-19 — initial release, install, push, docs scaffold + +## Objective and stopping point + +Build a self-contained z.ai GLM usage segment for the MiniMax Code statusline +(`zai-usage.sh` + self-extracting `install.sh`), install it on this machine, publish to +`git.itsaygea.com/admin/mcode-sl`, and scaffold the evidence-backed docs structure. +Stopped at the stage boundary: installed + pushed; TUI visual check and cross-machine +rollout deliberately left for next stages. + +## Verified results and evidence + +- `confirmed` — Safety matrix 14/14 on Linux: `trials/config-merge-safety-2026-10-19/output.txt` + (atomic write, 0600, backup == pre-merge original, duplicate-tui refusal untouched, + piped-install embed byte-identical, uninstall clean). +- `confirmed` — Key/endpoint pairing: `trials/mcode-endpoint-key-pairing-2026-10-19/record.md` + (vault key → api.z.ai 200; proxy 401; credential.json clientKey → proxy 200). +- `confirmed` — Live install on this machine: secret found, backup + `~/.minimax/config.yaml.bak.20261019-231642`, cache primed (`🔥 1% · 4:16a(4h59m)`), + provider/apiKey intact in `~/.minimax/config.yaml`. +- `confirmed` — Push: `main` → `git@git.itsaygea.com:admin/mcode-sl.git`; raw URL serves + a valid installer whose embedded copy matches the installed script. +- `inferred` — TUI rendering (colors/emoji): passthrough verified in bundle code + (`docs/DECISIONS.md` D2), not yet observed on screen. +- File digests at stage start: `zai-usage.sh` `ca2141a5…fa63c61`, + `install.sh` `a6c433da…4989a1`, `README.md` `d0e5bc42…576d5fb`. + +## Corrected assumptions and limitations + +- Assumed the user's Gitea answered SSH on 22 → actually Docker on **2222**; port 22 is + the host sshd. Wrong host keys were briefly written to `~/.ssh/known_hosts` and then + replaced (incident + repeat guard: `AGENTS.md` → "SSH to Gitea"). +- `credential.json`'s clientKey is NOT the same credential as vault `zai_api_key`. +- macOS portability is designed-in but unproven (FEATURE-MATRIX `unknown`). +- mcode facts are pinned to 0.6.12 bundle digests; any update invalidates D2 until re-read. + +## Unresolved questions and blockers + +- Does the segment render correctly in the live TUI? (needs user restart) +- Do the other machines (2× Ubuntu, 1× macOS) have `secretvault` + `zai_api_key`? +- Does `zai_api_key` survive rotation without endpoint changes? + +## Exact next action + +User restarts MiniMax Code and confirms rendering; then run the curl one-liner on the +two Ubuntu boxes. Acceptance: segment visible with colors; matrix rerun green on each +Linux box; FEATURE-MATRIX rows updated from `unknown`. + +## Reproduction + +```bash +# installer (any machine) +curl -fsSL https://git.itsaygea.com/admin/mcode-sl/raw/branch/main/install.sh | bash +# segment preview / refresh +printf '{}' | ~/.local/bin/mcode-zai-usage +~/.local/bin/mcode-zai-usage --refresh +# regression gate +bash trials/config-merge-safety-2026-10-19/verify.sh +``` + +Requires: bash, jq, curl, python3; secretvault + `zai_api_key` for the primary path. + +## Local artifacts + +- `~/.minimax/config.yaml` — live config (backups `~/.minimax/config.yaml.bak.*`). +- `~/.cache/aygea-sl/quota.json` — quota cache (safe to delete; self-heals). +- `~/.secretvault/credential.json` — legacy proxy credential (never committed). + +## Git state + +- Branch: `main` +- Commit: see `git log --oneline -1` (docs-scaffold commit follows the `first commit` + `9ad073d`; final handoff commit reported in the stage summary, not here) +- Push: pushed to `git@git.itsaygea.com:admin/mcode-sl.git` +- Working tree: expected clean after the docs-scaffold commit diff --git a/handoffs/TEMPLATE.md b/handoffs/TEMPLATE.md new file mode 100644 index 0000000..0a19b0c --- /dev/null +++ b/handoffs/TEMPLATE.md @@ -0,0 +1,39 @@ +# Handoff: — + +## Objective and stopping point + + + +## Verified results and evidence + + + +## Corrected assumptions and limitations + + + +## Unresolved questions and blockers + + + +## Exact next action + + + +## Reproduction + +```bash + +``` + +## Local artifacts + + + +## Git state + +- Branch: +- Commit: +- Push: / failed: > +- Working tree: diff --git a/tooling/README.md b/tooling/README.md new file mode 100644 index 0000000..88535bc --- /dev/null +++ b/tooling/README.md @@ -0,0 +1,18 @@ +# tooling + +Verified tools for this project (host `mewtwo`, 2026-10-19): + +| Tool | Version/notes | Required for | +|---|---|---| +| bash | system | everything | +| jq | system | `zai-usage.sh` parsing | +| curl | system | quota fetch | +| python3 | stdlib; PyYAML present locally (optional, adds YAML validation) | `install.sh` merge | +| git | SSH remote | pushes | +| secretvault | `~/.local/bin/secretvault` CLI; MCP `create_secret` to provision | key resolution (fallback: credential.json) | + +Setup on a new machine: `sudo`-install `jq curl python3` if missing, create the +`zai_api_key` SecretVault secret, then the one-liner from `README.md`. + +macOS caveats (designed for, untested): no `flock`/`setsid` → script degrades to plain +background refresh; `date -r` fallback path; BSD `install` supports `-m 755`. diff --git a/trials/README.md b/trials/README.md new file mode 100644 index 0000000..56f0cdd --- /dev/null +++ b/trials/README.md @@ -0,0 +1,11 @@ +# trials + +Bounded experiments. One directory per trial: `trials/-/` containing +`record.md` and, where possible, a re-runnable `verify.sh` plus its captured `output.txt`. + +Required sections: question/hypothesis, scope + acceptance criteria, inputs (paths, +hashes, tool versions), procedure (exact commands), expected vs observed, evidence +paths, verdict (`confirmed` / `rejected` / `inconclusive` / `blocked`), and a repeat +guard (what would justify another attempt). Preserve failed runs. + +Index lives in `TRIALS.md`. Routine edits and ordinary test runs do not need a trial. diff --git a/trials/config-merge-safety-2026-10-19/output.txt b/trials/config-merge-safety-2026-10-19/output.txt new file mode 100644 index 0000000..1f5a0b4 --- /dev/null +++ b/trials/config-merge-safety-2026-10-19/output.txt @@ -0,0 +1,15 @@ +PASS S1 fresh-install rc +PASS S1 created-tui message +PASS S1 new config mode 0600 +PASS S1 no tmp leftovers +PASS S2 idempotent rerun +PASS S3 update rc +PASS S3 backup equals pre-merge original +PASS S3 provider intact + keys updated +PASS S4 duplicate-tui refused +PASS S4 file untouched on refusal +PASS S4 refusal reason reported +PASS S5 embedded copy identical +PASS S6 uninstall rc +PASS S6 keys removed, items kept +== 14 passed, 0 failed == diff --git a/trials/config-merge-safety-2026-10-19/record.md b/trials/config-merge-safety-2026-10-19/record.md new file mode 100644 index 0000000..5ae33d0 --- /dev/null +++ b/trials/config-merge-safety-2026-10-19/record.md @@ -0,0 +1,19 @@ +# Trial: install.sh config-merge safety matrix + +- **Date:** 2026-10-19 +- **Question / hypothesis:** the `~/.minimax/config.yaml` surgery is atomic, idempotent, + backs up before change, refuses ambiguous input, keeps everything outside the `tui:` + block byte-identical, and works identically from a checkout or a piped install. +- **Scope / acceptance:** the 14 checks in `verify.sh` (S1–S6) all pass. +- **Inputs:** `install.sh` `a6c433da2cde4d92387c4de5845f6770ed71df55548499654e579869d84989a1`, + `zai-usage.sh` `ca2141a50b528072d7ca2a4842cd9d6c535fc036e2ff34f816fafc713fa63c61`. +- **Environment:** bash, GNU coreutils, python3 (PyYAML present → YAML validation active), + mktemp sandboxes with overridden `$HOME` (no live config touched). +- **Procedure:** `bash trials/config-merge-safety-2026-10-19/verify.sh` +- **Expected vs observed:** expected 14/14; observed 14/14 (`output.txt`). + First recorded run also caught two runner-script typos (`T1b`/`T2u` under `set -u`), + fixed before the clean run — both were test-harness bugs, not installer bugs. +- **Verdict:** confirmed (Linux, this host). +- **Repeat guard / limits:** rerun after any change to `install.sh` (required by + `AGENTS.md`), after mcode updates that change config.yaml's generated shape, and once + on macOS — pass/fail there is currently `unknown` (BSD stat/date/`install` differences). diff --git a/trials/config-merge-safety-2026-10-19/verify.sh b/trials/config-merge-safety-2026-10-19/verify.sh new file mode 100755 index 0000000..cb9e918 --- /dev/null +++ b/trials/config-merge-safety-2026-10-19/verify.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# Trial: config-merge safety matrix for install.sh +# +# Re-runnable acceptance check for the ~/.minimax/config.yaml surgery: +# fresh create, idempotency, backup-before-change, byte preservation, +# duplicate-structure refusal, piped/embedded install, uninstall. +# +# Usage: bash verify.sh (from anywhere; uses mktemp sandboxes) +# Exit 0 when every check passes. +set -u +export LC_ALL=C +REPO="$(cd "$(dirname "$0")/../.." && pwd)" +pass=0; fail=0 +ok(){ if [ "$2" = "0" ]; then pass=$((pass+1)); printf 'PASS %s\n' "$1"; else fail=$((fail+1)); printf 'FAIL %s\n' "$1"; fi; } + +# S1 fresh install: creates tui block, 0600 +T1=$(mktemp -d); HOME=$T1 bash "$REPO/install.sh" >"$T1.log" 2>&1; ok "S1 fresh-install rc" $? +grep -q created-tui "$T1.log"; ok "S1 created-tui message" $? +[ "$(stat -c '%a' "$T1/.minimax/config.yaml" 2>/dev/null)" = 600 ]; ok "S1 new config mode 0600" $? +ls "$T1"/.minimax/config.yaml.tmp.* >/dev/null 2>&1; [ $? -ne 0 ]; ok "S1 no tmp leftovers" $? + +# S2 idempotent rerun +HOME=$T1 bash "$REPO/install.sh" >"$T1.b.log" 2>&1 +grep -q already-configured "$T1.b.log"; ok "S2 idempotent rerun" $? + +# S3 existing config: update in place, backup == pre-merge original +T2=$(mktemp -d); mkdir -p "$T2/.minimax" +printf 'logLevel: info\nprovider:\n x:\n apiKey: keepme\ntui:\n statusLine:\n - current-dir\n customStatusLine:\n command: /old/path\n intervalSeconds: 30\n' > "$T2/.minimax/config.yaml" +cp "$T2/.minimax/config.yaml" "$T2/orig.yaml" +HOME=$T2 bash "$REPO/install.sh" >"$T2.log" 2>&1; ok "S3 update rc" $? +cmp -s "$(ls -t "$T2"/.minimax/config.yaml.bak.* | head -1)" "$T2/orig.yaml"; ok "S3 backup equals pre-merge original" $? +grep -q "apiKey: keepme" "$T2/.minimax/config.yaml" && grep -q "colorMode: ansi" "$T2/.minimax/config.yaml"; ok "S3 provider intact + keys updated" $? + +# S4 duplicate top-level tui blocks: refuse, file untouched +T3=$(mktemp -d); mkdir -p "$T3/.minimax" +printf 'a: 1\ntui:\n statusLine:\n - current-dir\nb: 2\ntui:\n statusLine:\n - model\nc: 3\n' > "$T3/.minimax/config.yaml" +cp "$T3/.minimax/config.yaml" "$T3/orig.yaml" +HOME=$T3 bash "$REPO/install.sh" >"$T3.log" 2>&1; [ $? -ne 0 ]; ok "S4 duplicate-tui refused" $? +cmp -s "$T3/.minimax/config.yaml" "$T3/orig.yaml"; ok "S4 file untouched on refusal" $? +grep -q merge-refused "$T3.log"; ok "S4 refusal reason reported" $? + +# S5 piped/embedded install (only install.sh present) -> embedded == zai-usage.sh +T4=$(mktemp -d); cp "$REPO/install.sh" "$T4/" +HOME=$T4 bash "$T4/install.sh" >"$T4.log" 2>&1 +cmp -s "$T4/.local/bin/mcode-zai-usage" "$REPO/zai-usage.sh"; ok "S5 embedded copy identical" $? + +# S6 uninstall: removes keys, keeps other items +HOME=$T2 bash "$REPO/install.sh" --uninstall >"$T2.u.log" 2>&1; ok "S6 uninstall rc" $? +! grep -q customStatusLine "$T2/.minimax/config.yaml" && ! grep -q custom-command "$T2/.minimax/config.yaml" && grep -q "current-dir" "$T2/.minimax/config.yaml"; ok "S6 keys removed, items kept" $? + +printf '== %s passed, %s failed ==\n' "$pass" "$fail" +rm -rf "$T1" "$T2" "$T3" "$T4" +[ "$fail" -eq 0 ] diff --git a/trials/mcode-endpoint-key-pairing-2026-10-19/record.md b/trials/mcode-endpoint-key-pairing-2026-10-19/record.md new file mode 100644 index 0000000..e7e4ce8 --- /dev/null +++ b/trials/mcode-endpoint-key-pairing-2026-10-19/record.md @@ -0,0 +1,24 @@ +# Trial: mcode endpoint / key pairing + +- **Date:** 2026-10-19 +- **Question / hypothesis:** the SecretVault secret `zai_api_key` (plain 48–49 char + string) is the direct z.ai API key, not the `vault.itsaygea.com` proxy clientKey; + therefore the statusline should default to `https://api.z.ai`. +- **Scope / acceptance:** three HTTP probes return codes consistent with exactly one + pairing per key; no key material printed. +- **Inputs / environment:** host `mewtwo` (Ubuntu, PVE), curl with `--max-time 8`, + key fetched via `secretvault run --secret zai_api_key -- bash -c 'printf %s "$zai_api_key"'`; + legacy key from `~/.secretvault/credential.json` (`.clientKey`, 51 chars). +- **Procedure:** + ```bash + # codes only; -o /dev/null -w '%{http_code}' + vault-key @ https://vault.itsaygea.com/proxy/zai/api/monitor/usage/quota/limit + vault-key @ https://api.z.ai/api/monitor/usage/quota/limit + cred-key @ https://vault.itsaygea.com/proxy/zai/api/monitor/usage/quota/limit + ``` +- **Expected vs observed:** expected one 200; observed + `401 (vault@proxy) / 200 (vault@zai) / 200 (cred@proxy)`. +- **Verdict:** confirmed — vault key is the direct z.ai credential; proxy clientKey is + separate. `zai-usage.sh` implements vault→`api.z.ai` first, credential.json→proxy fallback. +- **Repeat guard:** revisit if the vault secret is rotated to a proxy clientKey, or if + `api.z.ai` starts rejecting it (401 after rotation).