From 93c6553b00d7d7377962753263168fd097d4831b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Villase=C3=B1or=20Montfort?= <195970+montfort@users.noreply.github.com> Date: Wed, 5 Aug 2026 23:28:05 -0600 Subject: [PATCH 1/2] =?UTF-8?q?feat(framework+cli):=20fw-4.42.0=20/=20cli-?= =?UTF-8?q?3.43.0=20=E2=80=94=20Antigravity=20CLI=20succeeds=20Gemini=20CL?= =?UTF-8?q?I?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Google retired Gemini CLI; its successor is Antigravity CLI (agy). Verified against agy 1.1.10 and agy-customizations — the spec Google ships inside the binary — the obvious reading of "discontinue Gemini CLI" is half wrong: - GEMINI.md is NOT retired. Antigravity reads it as a first-class Rules file alongside AGENTS.md, and its global config dir is ~/.gemini/ (the binary carries a resolve_gemini_dir symbol). Deleting it would have removed a rules source from the very CLI we are adding support for. Kept, retitled to the Antigravity lineage, identity antigravity-v{version}, with a note explaining why the filename stays so nobody deletes it as a leftover. - /.gemini/skills/ IS dead: not a discovery location for agy, whose workspace roots are .agents/ .agent/ _agents/ _agent/. - .agent/workflows/ is read by nothing. Right root, wrong shape — agy wants skills//SKILL.md, and the binary has no `agent/workflows` string. It had been advertised in the README as the Antigravity channel regardless. New channel: dist/.agent/skills/, generated from the Claude source rather than hand-mirrored. That choice came from the data — .gemini/skills/ had drifted behind .claude/ in 7 of 15 skills because nothing regenerated or gated it, while the generated .codex/ channel was byte-perfect. gen_codex_skills becomes gen_minimal_skills and emits both under the existing CI gate. Retiring a distributed path was previously impossible to complete: update_files only copies, so a directory dropped from files: survived in every existing installation until someone ran `straymark remove`. New declarative `retired:` manifest key, honored by update-framework and repair. Deletion is provenance-gated — a file goes only when its hash still matches what .checksums.json recorded; operator-edited and operator-authored files are kept and reported distinctly, because telling someone they "modified" a file they wrote themselves erodes trust in the report. The manual e2e caught two defects before they shipped: repair's early return skipped the sweep on a healthy installation, and the first report conflated "you edited this" with "this was never mine". A unit test caught that only the retired root was cleaned, leaving emptied skill subdirectories behind. Gemini MODEL ids are deliberately untouched: the CLI was retired, the models were not, and the audit skills already require auditor: to name the backend model rather than the CLI. Historical records — Sentinel telemetry, the Charter-template rule justified by an observed Gemini-auditor behavior across 2 cycles — are left as written; rewriting the actor would falsify the evidence. NOT READY TO TAG: the .agent/ vs .agents/ customization root is not empirically confirmed. Google's doc lists .agent/ as an accepted alias; the binary's path templates only build .agents/. Three headless probes could not settle it. Operator verifies interactively; if .agent/ loses it is a git mv plus two manifest lines. Everything else here is root-independent. Decision in AIDEC-2026-08-05-002, work in AILOG-2026-08-05-004. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 18 +- ...026-08-05-004-antigravity-agent-surface.md | 160 +++++++++ ...-05-002-antigravity-succeeds-gemini-cli.md | 157 +++++++++ .straymark/follow-ups-backlog.md | 21 +- CHANGELOG.md | 38 +++ Cargo.lock | 2 +- README.md | 25 +- cli/Cargo.toml | 6 +- cli/README.md | 6 +- ..._codex_skills.rs => gen_minimal_skills.rs} | 35 +- cli/src/commands/charter/audit.rs | 4 +- cli/src/commands/install_skills.rs | 12 +- cli/src/commands/repair.rs | 41 ++- cli/src/commands/update_framework.rs | 264 +++++++++++++++ cli/src/main.rs | 10 +- cli/src/manifest.rs | 9 + cli/tests/architecture_skill_test.rs | 65 ++-- cli/tests/audit_skill_test.rs | 133 ++------ cli/tests/retired_paths_test.rs | 50 +++ .../skills/straymark-adr/SKILL.md | 4 +- .../skills/straymark-aidec/SKILL.md | 4 +- .../skills/straymark-ailog/SKILL.md | 4 +- .../straymark-architecture-sync/SKILL.md | 0 .../skills/straymark-architecture/SKILL.md | 0 .../skills/straymark-audit-execute/SKILL.md | 14 +- .../skills/straymark-audit-prompt/SKILL.md | 4 +- .../skills/straymark-audit-review/SKILL.md | 2 +- .../skills/straymark-charter-new/SKILL.md | 4 +- .../skills/straymark-followups/SKILL.md | 0 .../skills/straymark-loom/SKILL.md | 0 .../skills/straymark-mcard/SKILL.md | 4 +- .../skills/straymark-new/SKILL.md | 6 +- .../skills/straymark-sec/SKILL.md | 2 +- .../skills/straymark-status/SKILL.md | 18 +- dist/.agent/workflows/straymark-adr.md | 113 ------- dist/.agent/workflows/straymark-aidec.md | 92 ----- dist/.agent/workflows/straymark-ailog.md | 92 ----- .../workflows/straymark-architecture-sync.md | 78 ----- .../workflows/straymark-architecture.md | 97 ------ .../workflows/straymark-audit-execute.md | 155 --------- .../workflows/straymark-audit-prompt.md | 89 ----- .../workflows/straymark-audit-review.md | 257 -------------- .../.agent/workflows/straymark-charter-new.md | 90 ----- dist/.agent/workflows/straymark-followups.md | 100 ------ dist/.agent/workflows/straymark-loom.md | 74 ---- dist/.agent/workflows/straymark-mcard.md | 319 ------------------ dist/.agent/workflows/straymark-new.md | 186 ---------- dist/.agent/workflows/straymark-sec.md | 298 ---------------- dist/.agent/workflows/straymark-status.md | 130 ------- dist/.claude/skills/straymark-adr/SKILL.md | 2 +- dist/.claude/skills/straymark-aidec/SKILL.md | 2 +- dist/.claude/skills/straymark-ailog/SKILL.md | 2 +- .../skills/straymark-audit-execute/SKILL.md | 14 +- .../skills/straymark-audit-prompt/SKILL.md | 4 +- .../skills/straymark-audit-review/SKILL.md | 2 +- dist/.claude/skills/straymark-mcard/SKILL.md | 2 +- dist/.claude/skills/straymark-new/SKILL.md | 2 +- dist/.claude/skills/straymark-sec/SKILL.md | 2 +- dist/.codex/skills/straymark-adr/SKILL.md | 2 +- dist/.codex/skills/straymark-aidec/SKILL.md | 2 +- dist/.codex/skills/straymark-ailog/SKILL.md | 2 +- .../skills/straymark-audit-execute/SKILL.md | 14 +- .../skills/straymark-audit-prompt/SKILL.md | 4 +- .../skills/straymark-audit-review/SKILL.md | 2 +- dist/.codex/skills/straymark-mcard/SKILL.md | 2 +- dist/.codex/skills/straymark-new/SKILL.md | 2 +- dist/.codex/skills/straymark-sec/SKILL.md | 2 +- dist/.qoder/skills/straymark-adr/SKILL.md | 2 +- dist/.qoder/skills/straymark-aidec/SKILL.md | 2 +- dist/.qoder/skills/straymark-ailog/SKILL.md | 2 +- .../skills/straymark-audit-execute/SKILL.md | 14 +- .../skills/straymark-audit-prompt/SKILL.md | 4 +- .../skills/straymark-audit-review/SKILL.md | 2 +- dist/.qoder/skills/straymark-mcard/SKILL.md | 2 +- dist/.qoder/skills/straymark-new/SKILL.md | 2 +- dist/.qoder/skills/straymark-sec/SKILL.md | 2 +- dist/.qwen/skills/straymark-adr/SKILL.md | 2 +- dist/.qwen/skills/straymark-aidec/SKILL.md | 2 +- dist/.qwen/skills/straymark-ailog/SKILL.md | 2 +- .../skills/straymark-audit-execute/SKILL.md | 14 +- .../skills/straymark-audit-prompt/SKILL.md | 4 +- .../skills/straymark-audit-review/SKILL.md | 2 +- dist/.qwen/skills/straymark-mcard/SKILL.md | 2 +- dist/.qwen/skills/straymark-new/SKILL.md | 2 +- dist/.qwen/skills/straymark-sec/SKILL.md | 2 +- dist/.straymark/00-governance/AGENT-RULES.md | 6 +- .../00-governance/AI-GOVERNANCE-POLICY.md | 2 +- .../00-governance/C4-DIAGRAM-GUIDE.md | 2 +- .../00-governance/DOCUMENTATION-POLICY.md | 2 +- .../FOLLOW-UPS-BACKLOG-PATTERN.md | 2 +- .../00-governance/QUICK-REFERENCE.md | 2 +- .../00-governance/SPECKIT-CHARTER-BRIDGE.md | 2 +- .../00-governance/i18n/es/AGENT-RULES.md | 6 +- .../i18n/es/AI-GOVERNANCE-POLICY.md | 2 +- .../00-governance/i18n/es/C4-DIAGRAM-GUIDE.md | 2 +- .../i18n/es/DOCUMENTATION-POLICY.md | 2 +- .../i18n/es/FOLLOW-UPS-BACKLOG-PATTERN.md | 2 +- .../00-governance/i18n/es/QUICK-REFERENCE.md | 2 +- .../i18n/es/SPECKIT-CHARTER-BRIDGE.md | 2 +- .../00-governance/i18n/zh-CN/AGENT-RULES.md | 6 +- .../i18n/zh-CN/AI-GOVERNANCE-POLICY.md | 2 +- .../i18n/zh-CN/C4-DIAGRAM-GUIDE.md | 2 +- .../i18n/zh-CN/DOCUMENTATION-POLICY.md | 2 +- .../i18n/zh-CN/FOLLOW-UPS-BACKLOG-PATTERN.md | 2 +- .../i18n/zh-CN/QUICK-REFERENCE.md | 2 +- .../i18n/zh-CN/SPECKIT-CHARTER-BRIDGE.md | 2 +- .../schemas/audit-output.schema.v0.json | 2 +- .../templates/charter/charter-template.md | 2 +- .../charter/i18n/es/charter-template.md | 2 +- .../charter/i18n/zh-CN/charter-template.md | 2 +- dist/STRAYMARK.md | 4 +- dist/dist-manifest.yml | 18 +- dist/dist-templates/directives/AGENTS.md | 4 +- dist/dist-templates/directives/GEMINI.md | 10 +- docs/adopters/ADOPTION-GUIDE.md | 6 +- docs/adopters/CLI-REFERENCE.md | 29 +- docs/adopters/WORKFLOWS.md | 6 +- docs/contributors/TRANSLATION-GUIDE.md | 4 +- docs/i18n/es/README.md | 23 +- docs/i18n/es/adopters/ADOPTION-GUIDE.md | 6 +- docs/i18n/es/adopters/CLI-REFERENCE.md | 27 +- docs/i18n/es/adopters/WORKFLOWS.md | 6 +- docs/i18n/zh-CN/README.md | 23 +- docs/i18n/zh-CN/adopters/ADOPTION-GUIDE.md | 6 +- docs/i18n/zh-CN/adopters/CLI-REFERENCE.md | 29 +- docs/i18n/zh-CN/adopters/WORKFLOWS.md | 6 +- website/features/agent-governance.mdx | 2 +- website/features/multi-model-audit.mdx | 4 +- website/features/skills.mdx | 2 +- website/i18n/es/code.json | 4 +- .../current/agent-governance.mdx | 2 +- .../current/multi-model-audit.mdx | 4 +- .../current/skills.mdx | 2 +- .../quickstart.mdx | 4 +- website/i18n/zh-CN/code.json | 4 +- .../current/agent-governance.mdx | 2 +- .../current/multi-model-audit.mdx | 4 +- .../current/skills.mdx | 2 +- .../quickstart.mdx | 4 +- website/src/components/FeatureGrid/index.tsx | 2 +- .../components/WorkflowDiagram/diagrams.tsx | 2 +- .../src/components/WorkflowDiagram/index.tsx | 2 +- website/src/pages/quickstart.mdx | 4 +- 143 files changed, 1119 insertions(+), 2620 deletions(-) create mode 100644 .straymark/07-ai-audit/agent-logs/AILOG-2026-08-05-004-antigravity-agent-surface.md create mode 100644 .straymark/07-ai-audit/decisions/AIDEC-2026-08-05-002-antigravity-succeeds-gemini-cli.md rename cli/src/bin/{gen_codex_skills.rs => gen_minimal_skills.rs} (81%) create mode 100644 cli/tests/retired_paths_test.rs rename dist/{.gemini => .agent}/skills/straymark-adr/SKILL.md (94%) rename dist/{.gemini => .agent}/skills/straymark-aidec/SKILL.md (92%) rename dist/{.gemini => .agent}/skills/straymark-ailog/SKILL.md (92%) rename dist/{.gemini => .agent}/skills/straymark-architecture-sync/SKILL.md (100%) rename dist/{.gemini => .agent}/skills/straymark-architecture/SKILL.md (100%) rename dist/{.gemini => .agent}/skills/straymark-audit-execute/SKILL.md (86%) rename dist/{.gemini => .agent}/skills/straymark-audit-prompt/SKILL.md (95%) rename dist/{.gemini => .agent}/skills/straymark-audit-review/SKILL.md (97%) rename dist/{.gemini => .agent}/skills/straymark-charter-new/SKILL.md (95%) rename dist/{.gemini => .agent}/skills/straymark-followups/SKILL.md (100%) rename dist/{.gemini => .agent}/skills/straymark-loom/SKILL.md (100%) rename dist/{.gemini => .agent}/skills/straymark-mcard/SKILL.md (98%) rename dist/{.gemini => .agent}/skills/straymark-new/SKILL.md (95%) rename dist/{.gemini => .agent}/skills/straymark-sec/SKILL.md (98%) rename dist/{.gemini => .agent}/skills/straymark-status/SKILL.md (89%) delete mode 100644 dist/.agent/workflows/straymark-adr.md delete mode 100644 dist/.agent/workflows/straymark-aidec.md delete mode 100644 dist/.agent/workflows/straymark-ailog.md delete mode 100644 dist/.agent/workflows/straymark-architecture-sync.md delete mode 100644 dist/.agent/workflows/straymark-architecture.md delete mode 100644 dist/.agent/workflows/straymark-audit-execute.md delete mode 100644 dist/.agent/workflows/straymark-audit-prompt.md delete mode 100644 dist/.agent/workflows/straymark-audit-review.md delete mode 100644 dist/.agent/workflows/straymark-charter-new.md delete mode 100644 dist/.agent/workflows/straymark-followups.md delete mode 100644 dist/.agent/workflows/straymark-loom.md delete mode 100644 dist/.agent/workflows/straymark-mcard.md delete mode 100644 dist/.agent/workflows/straymark-new.md delete mode 100644 dist/.agent/workflows/straymark-sec.md delete mode 100644 dist/.agent/workflows/straymark-status.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39256b70..d32529d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,9 +5,10 @@ on: paths: - 'dist/.claude/skills/**' - 'dist/.codex/skills/**' + - 'dist/.agent/skills/**' - 'dist/.qoder/skills/**' - 'dist/.qwen/skills/**' - - 'cli/src/bin/gen_codex_skills.rs' + - 'cli/src/bin/gen_minimal_skills.rs' - 'cli/tests/qoder_skills_test.rs' - 'cli/tests/qwen_skills_test.rs' - '.github/workflows/ci.yml' @@ -16,9 +17,10 @@ on: paths: - 'dist/.claude/skills/**' - 'dist/.codex/skills/**' + - 'dist/.agent/skills/**' - 'dist/.qoder/skills/**' - 'dist/.qwen/skills/**' - - 'cli/src/bin/gen_codex_skills.rs' + - 'cli/src/bin/gen_minimal_skills.rs' - 'cli/tests/qoder_skills_test.rs' - 'cli/tests/qwen_skills_test.rs' - '.github/workflows/ci.yml' @@ -30,8 +32,8 @@ env: CARGO_TERM_COLOR: always jobs: - codex-skills-sync: - name: Codex skills in sync with Claude source + minimal-skills-sync: + name: Codex + Antigravity skills generated from Claude source runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 @@ -42,13 +44,13 @@ jobs: - name: Install OpenSSL (Linux) run: sudo apt-get update && sudo apt-get install -y libssl-dev pkg-config - - name: Verify .codex/skills is regenerated from .claude/skills + - name: Verify .codex/skills and .agent/skills are regenerated from .claude/skills working-directory: cli run: | - # Fails if dist/.codex/skills/ drifted from what gen_codex_skills would + # Fails if dist/.codex/skills/ or dist/.agent/skills/ drifted from what gen_minimal_skills would # produce from dist/.claude/skills/. Fix locally with: - # cd cli && cargo run --bin gen_codex_skills --features dev-tools - cargo run --quiet --bin gen_codex_skills --features dev-tools -- --check + # cd cli && cargo run --bin gen_minimal_skills --features dev-tools + cargo run --quiet --bin gen_minimal_skills --features dev-tools -- --check skill-mirror-parity: name: Qoder/Qwen skills mirror the Claude source diff --git a/.straymark/07-ai-audit/agent-logs/AILOG-2026-08-05-004-antigravity-agent-surface.md b/.straymark/07-ai-audit/agent-logs/AILOG-2026-08-05-004-antigravity-agent-surface.md new file mode 100644 index 00000000..53144323 --- /dev/null +++ b/.straymark/07-ai-audit/agent-logs/AILOG-2026-08-05-004-antigravity-agent-surface.md @@ -0,0 +1,160 @@ +--- +id: AILOG-2026-08-05-004 +title: Antigravity CLI replaces Gemini CLI — two dead channels retired, GEMINI.md kept, and a retirement mechanism built to make it land +status: accepted +created: 2026-08-05 +agent: claude-opus-5-v1.0 +confidence: high +review_required: false +risk_level: medium +eu_ai_act_risk: not_applicable +nist_genai_risks: [] +iso_42001_clause: [] +lines_changed: 695 +files_modified: + - dist/dist-manifest.yml + - dist/.agent/skills/ + - dist/dist-templates/directives/GEMINI.md + - dist/.straymark/00-governance/AGENT-RULES.md + - dist/.claude/skills/ + - cli/src/manifest.rs + - cli/src/commands/update_framework.rs + - cli/src/commands/repair.rs + - cli/src/commands/install_skills.rs + - cli/src/commands/charter/audit.rs + - cli/src/main.rs + - cli/src/bin/gen_minimal_skills.rs + - cli/tests/retired_paths_test.rs + - cli/tests/architecture_skill_test.rs + - cli/tests/audit_skill_test.rs + - .github/workflows/ci.yml + - README.md + - docs/adopters/ + - website/ + - CHANGELOG.md +observability_scope: none +tags: [multi-agent, antigravity, gemini-cli, deprecation, update-path, ci, i18n] +related: + - AIDEC-2026-08-05-002 + - AILOG-2026-08-05-003 +--- + +# AILOG: Antigravity CLI replaces Gemini CLI + +## Summary + +Gemini CLI was retired by Google in favour of Antigravity CLI (`agy`). Two of +StrayMark's Gemini-era surfaces turned out to be dead and are retired; +`GEMINI.md` turned out to be alive and is kept, re-framed. Along the way the +framework gained the piece that makes retiring a distributed path possible at +all — without it, "discontinuing" a channel would have meant new installations +stop getting it while every existing one keeps it forever. + +## Context + +The task looked like a straightforward deprecation. Checking the runtime first +changed the shape of it. + +`agy` 1.1.10 is installed on this machine, and Google ships the authoritative +spec of its customization system *inside the binary* as a builtin skill +(`agy-customizations`). Reading it: + +- **`GEMINI.md` is a first-class Rules file**, listed alongside `AGENTS.md` and + `.agents/rules/*.md`. `~/.gemini/` is Antigravity's own global config + directory (the binary carries a `resolve_gemini_dir` symbol). The product was + retired; the on-disk contract was kept. **Deleting `GEMINI.md` would have + removed a rules source from the very CLI we were adding support for.** +- **`/.gemini/skills/` is not a discovery location.** Workspace roots + are `.agents/`, `.agent/`, `_agents/`, `_agent/`; the global one is + `~/.gemini/config/`. +- **`/.agent/workflows/` is read by nothing.** The root is valid but + the subdirectory Antigravity looks for is `skills//SKILL.md`; the binary + contains no `agent/workflows` string. That channel had been advertised in the + README as the Antigravity surface since before this release. + +Which left the retirement problem: `update_files` only copies. See §Changes. + +## Changes + +**Framework** + +- `dist/.agent/skills/` — 15 skills, `skills//SKILL.md`, minimal + frontmatter. Discovered from the project tree; no install step. +- `dist/.gemini/skills/` and `dist/.agent/workflows/` removed from `files:` and + declared under the new `retired:` key. +- `GEMINI.md` directive retitled to the Antigravity lineage, identity + `antigravity-v{version}`, plus a note explaining why the filename stays — + without it the next reader deletes the file as a leftover. +- Auditor-CLI prose moved to `agy` across the skills, governance docs and + templates. **Gemini model ids were deliberately left alone** (see §Decisions). + +**CLI** + +- `manifest.rs`: `retired: Vec` with `#[serde(default)]` — load-bearing, + since every pre-4.42.0 `.straymark/dist-manifest.yml` lacks the key and + `repair`/`remove` re-read those copies. +- `update_framework.rs`: `prune_retired()`, provenance-gated. A file is deleted + only when its hash still matches `.checksums.json`. Operator-edited files and + files StrayMark never installed are kept and reported. +- `repair.rs`: same sweep, plus retired leftovers now count toward + `total_issues` — otherwise the early return on a healthy installation would + have skipped the sweep exactly where it was needed. +- `install-skills --agent gemini` → `--agent agy`. +- `gen_codex_skills` → `gen_minimal_skills`, emitting `.codex/skills/` **and** + `.agent/skills/` under the existing CI gate. + +**Docs/website** — README, CLI-REFERENCE, ADOPTION-GUIDE, WORKFLOWS, +TRANSLATION-GUIDE, React components, features and `code.json` (EN/es/zh-CN). +"6 parallel forms" → 5. The zh-CN CLI-REFERENCE, two releases behind, resynced. + +## Decisions + +Recorded in full in [AIDEC-2026-08-05-002]. Two worth restating here because +they are the ones a reader will second-guess: + +**Why `GEMINI.md` survives a "discontinue Gemini CLI" task.** Because the +runtime reads it. The name is stale; the file is not. + +**Why Gemini *model* ids were not renamed.** The CLI product was retired; the +models were not, and `agy` serves them. The audit skills already state that +`auditor:` must name the backend model rather than the CLI, so `gemini-3-pro` +stays valid while `gemini-cli` as "a CLI to open" does not. Historical records — +Sentinel telemetry, the Charter-template rule justified by an observed +Gemini-auditor behavior across 2 cycles — were left exactly as written. +Rewriting the actor in a piece of evidence would falsify the evidence. + +## Verification + +- `cargo test`: **953 passed, 0 failed**. +- New: `retired_paths_test.rs` (the shipped manifest actually retires the dead + channels and does not distribute them simultaneously) plus four unit tests in + `update_framework::tests` covering the three provenance outcomes, full-subtree + cleanup, the no-op case, and the pre-4.42.0 manifest parse. +- Manual e2e on a simulated fw-4.41.0 installation: two pristine files pruned, + one operator-edited file kept and flagged as modified, one operator-authored + file kept and flagged as *not installed by StrayMark*, parent directories + cleaned only when empty. + +The e2e caught two real defects before they shipped: `repair`'s early return +skipped the sweep on a healthy installation, and the first version of the report +told the operator they had "modified" files they had authored themselves. A unit +test also caught that only the retired root was being cleaned, leaving emptied +skill subdirectories behind. + +## Risk + +| Id | Risk | Handling | +|----|------|----------| +| R1 | The `.agent/` vs `.agents/` root is **not empirically confirmed**. Google's shipped doc lists `.agent/` as an accepted alias; the binary's path templates only ever build `.agents/`. | Three headless `agy -p` probes could not settle it — workspace customizations did not surface in print mode at all, even in a trusted directory with a git root, so the probe could not distinguish the roots rather than showing one failing. Operator verifies interactively in `/tmp/straymark-agy-probe` (one probe skill under each root). If `.agent/` loses, the fix is a `git mv` plus two manifest lines; everything else here is root-independent. **This release must not be tagged before that check.** | +| R2 | `prune_retired` is the first code path that deletes adopter files outside `straymark remove`. | Provenance-gated on the checksum store, conservative by default (when in doubt, keep), and every kept file is named in the report. | +| R3 (new, not in Charter) | `.gemini/skills/` had drifted behind `.claude/skills/` in 7 of 15 skills, undetected, because nothing regenerated or gated it — while the generated `.codex/` channel was byte-perfect. | Fixed by construction: the replacement channel is generated, not hand-mirrored, and CI gates it. The general lesson — a hand-maintained mirror without a gate *will* drift — is why `.qoder/` and `.qwen/` got their own CI job last release. | +| R4 (new, not in Charter) | Attempting the probe required touching `~/.gemini/trustedFolders.json`; the write was blocked and I asked instead of forcing it. | Correct outcome, noted because it will recur: verifying agent-runtime behavior often needs config the agent should not silently grant itself. | + +## Follow-ups + +- Confirm which customization root Antigravity discovers (`.agent/` vs + `.agents/`) before tagging `fw-4.42.0`, and flip the channel if needed. +- After the tag: verify on a real `straymark update` from fw-4.41.0 that both + retired directories disappear and the summary names anything kept — chained + with the `QWEN.md` init/update verification still pending from + [AILOG-2026-08-05-003]. diff --git a/.straymark/07-ai-audit/decisions/AIDEC-2026-08-05-002-antigravity-succeeds-gemini-cli.md b/.straymark/07-ai-audit/decisions/AIDEC-2026-08-05-002-antigravity-succeeds-gemini-cli.md new file mode 100644 index 00000000..1ead06b0 --- /dev/null +++ b/.straymark/07-ai-audit/decisions/AIDEC-2026-08-05-002-antigravity-succeeds-gemini-cli.md @@ -0,0 +1,157 @@ +--- +id: AIDEC-2026-08-05-002 +title: Antigravity CLI succeeds Gemini CLI — retire the channels, keep GEMINI.md, and build a retirement mechanism +status: accepted +created: 2026-08-05 +agent: claude-opus-5-v1.0 +confidence: high +review_required: false +risk_level: medium +eu_ai_act_risk: not_applicable +nist_genai_risks: [] +iso_42001_clause: [] +tags: [multi-agent, antigravity, gemini-cli, deprecation, dist-manifest, update-path] +related: + - AILOG-2026-08-05-004 + - AIDEC-2026-08-05-001 +--- + +# AIDEC: Antigravity CLI succeeds Gemini CLI + +## Context + +Google retired Gemini CLI. The operator asked to discontinue StrayMark's support +for it and prepare support for its successor, **Antigravity CLI** (`agy`). + +The obvious reading of "discontinue Gemini CLI support" — delete `GEMINI.md`, +delete `.gemini/skills/` — turns out to be half wrong. Verified against `agy` +1.1.10 installed on this machine and against `agy-customizations`, the skill +Google ships *inside the binary* as the authoritative spec of its customization +system: + +| Surface | What Antigravity actually does | +|---|---| +| `GEMINI.md` | **Reads it.** Listed as a first-class Rules file alongside `AGENTS.md` and `.agents/rules/*.md`. | +| `~/.gemini/` | **Its own global config directory.** The binary contains a `resolve_gemini_dir` symbol; `~/.gemini/skills/`, `~/.gemini/settings.json` and `~/.gemini/GEMINI.md` are live. | +| `/.gemini/skills/` | **Not a discovery location.** Workspace roots are `.agents/`, `.agent/`, `_agents/`, `_agent/`; the global one is `~/.gemini/config/`. | +| `/.agent/workflows/` | **Not read.** The root is valid, but the subdirectory it looks for is `skills//SKILL.md`. The binary contains no `agent/workflows` string. | + +So the product was retired while the on-disk contract was kept. Two of +StrayMark's four Gemini-era surfaces were dead; one was alive and mis-labeled; +and the fourth — `.agent/workflows/` — had been advertised in the README as the +Antigravity channel while being read by nothing at all. + +## Problem + +Three decisions, and one of them turns out to gate the others. + +1. **`GEMINI.md`**: retire it with the product, or keep it? +2. **The skills channel**: where does the Antigravity-readable channel live, and + what happens to the two dead ones? +3. **How does a retirement reach anyone?** `update_files` only ever copies. + Dropping a directory from `files:` leaves it in every existing installation + until someone runs `straymark remove`. Without solving this, "discontinuing" + a channel means new installations stop getting it while every existing + installation keeps it forever — the worst of both. + +## Alternatives Considered + +### Alternative 1: Delete `GEMINI.md` along with the product + +**Pros**: Consistent with the headline ("discontinue Gemini CLI"); one fewer +file in the adopter's project root. + +**Cons**: Directly contradicted by the runtime. Antigravity loads `GEMINI.md` +as Rules; deleting it removes a governance source from the very CLI we are +adding support for. The name is stale, the file is not. + +### Alternative 2: Keep `GEMINI.md`, re-framed to the Antigravity lineage + +**Pros**: No regression. The template retitles to Antigravity, the identity +becomes `antigravity-v{version}`, and a short note explains *why* the file keeps +the `GEMINI.md` name — which matters, because the next person to read the tree +will otherwise conclude it is a leftover and delete it. + +**Cons**: A file named after a retired product persists. Accepted: the filename +is Google's contract, not ours. + +### Alternative 3: Add `ANTIGRAVITY.md` next to it + +**Cons**: Verified against the binary — no `ANTIGRAVITY.md` or `AGY.md` string +exists. It would be a file nothing reads. Rejected on evidence. + +### Alternative 4 (channel): `.agents/skills/` (canonical) vs `.agent/skills/` (alias) + +Google's shipped doc names both: *"Path: `.agents/` (or `.agent/`, `_agents/`, +`_agent/`)"*. The binary's error templates hardcode `.agents/`. `.agent/` keeps +the root StrayMark already advertises. **This one is not yet closed** — see +§Risks R1. + +### Alternative 5 (retirement): document `straymark repair` instead of building a mechanism + +**Pros**: No new code. + +**Cons**: Makes every future retirement depend on adopters reading a release +note and running a second command. The failure is silent — the dead directory +just sits there. And this is the second release in a row where the update path +turned out to be the thing standing between a decision and the adopters +(see [[AIDEC-2026-08-05-001]], where `update-framework` refused to create new +injection targets). Fixing the shape once beats documenting around it twice. + +## Decision + +**Chosen**: keep `GEMINI.md` re-framed (Alt 2); move the skills channel to +`.agent/skills/` generated from the Claude source; retire `.gemini/skills/` and +`.agent/workflows/` through a new declarative `retired:` mechanism (rejecting +Alt 5). + +**Justification**: The runtime evidence settles (1) and (2) with no room for +preference — one surface is alive, two are dead. For (3), the mechanism is +small, declarative, and provenance-gated: a file is deleted only when its hash +still matches what `.checksums.json` recorded, so a retirement notice from +upstream never becomes a licence to delete work the operator did inside the +path. Files the operator edited and files StrayMark never installed are kept +*and reported separately*, because telling someone they "modified" a file they +wrote themselves is wrong in a way that erodes trust in the tool's reports. + +A secondary finding pushed the channel from hand-mirrored to generated: +`.gemini/skills/` had **drifted behind `.claude/skills/` in 7 of 15 skills**, +precisely because nothing regenerated or gated it — while `.codex/skills/`, +which is generated and CI-checked, was byte-perfect. So `gen_codex_skills` +became `gen_minimal_skills` and now emits both minimal-frontmatter channels +under the existing CI gate. A `git mv` would have imported the stale files. + +## Consequences + +### Positive +- Antigravity users get the skills from the project tree with no install step, + plus `GEMINI.md` and `AGENTS.md` as Rules. +- The framework can now retire *any* distributed path and have it actually + disappear from existing installations — reusable, not a one-off. +- One less hand-maintained channel; the new one cannot drift. +- StrayMark stops advertising Antigravity support via a directory Antigravity + does not read. + +### Negative +- A file named `GEMINI.md` persists after the product's death, which will look + wrong to every reader until they hit the note explaining it. +- `.agent/` is now described as an Antigravity customization root rather than a + vendor-agnostic standard. That claim was aspirational anyway — the channel it + described was read by nothing — but the README loses a tidy story. + +### Risks +- **R1 — the `.agent/` vs `.agents/` question is not empirically closed.** + Google's shipped doc lists `.agent/` as an accepted alias; the binary's path + templates only ever build `.agents/`. Three headless `agy -p` probes failed to + settle it: workspace customizations did not surface in print mode at all, + in a trusted directory with a git root, so the probe could not distinguish the + two roots rather than showing one failing. **Mitigation**: the operator + verifies interactively in `/tmp/straymark-agy-probe`, which holds one probe + skill under each root. If `.agent/` is not discovered, the fix is a `git mv` + plus two manifest lines — the rest of this release is root-independent. +- **R2 — pruning deletes files.** Gated on hash provenance and reported in full, + but it is the first code path in StrayMark that removes adopter files outside + `straymark remove`. The conservative default is deliberate: when in doubt, keep. +- **R3 (new, not in Charter) — `AGENTS.md` remains the fallback for both.** + If Antigravity ever drops `GEMINI.md`, adopters degrade to `AGENTS.md` rather + than to nothing. No action needed; noted so the coupling is visible. diff --git a/.straymark/follow-ups-backlog.md b/.straymark/follow-ups-backlog.md index c58aa034..4b399b56 100644 --- a/.straymark/follow-ups-backlog.md +++ b/.straymark/follow-ups-backlog.md @@ -1,7 +1,7 @@ --- last_scan: 2026-08-05 schema_version: v1 -total_open: 2 +total_open: 4 total_promoted: 0 total_closed_in_session: 0 total_phase_blocked: 0 @@ -15,6 +15,7 @@ buckets: fully_extracted_ailogs: - AILOG-2026-08-04-003 - AILOG-2026-08-05-003 + - AILOG-2026-08-05-004 --- # Follow-ups Backlog @@ -59,6 +60,24 @@ Entry shape (v1 — optional fields marked): - **Cost**: TBD - **Notes**: Auto-appended by `straymark followups drift --apply` 2026-08-05. +### FU-003 — Confirm which customization root Antigravity discovers (`.agent/` vs `.agents/`) before tagging `fw-4.42.0`, and flip… +- **Origin**: AILOG-2026-08-05-004 §Follow-ups +- **Source-hash**: 9055de213adb +- **Status**: open +- **Trigger**: TBD +- **Destination**: TBD +- **Cost**: TBD +- **Notes**: Auto-appended by `straymark followups drift --apply` 2026-08-05. + +### FU-004 — After the tag: verify on a real `straymark update` from fw-4.41.0 that both retired directories disappear and the… +- **Origin**: AILOG-2026-08-05-004 §Follow-ups +- **Source-hash**: 4a131ad2ba05 +- **Status**: open +- **Trigger**: TBD +- **Destination**: TBD +- **Cost**: TBD +- **Notes**: Auto-appended by `straymark followups drift --apply` 2026-08-05. + ## Bucket: time-triggered ## Bucket: charter-triggered diff --git a/CHANGELOG.md b/CHANGELOG.md index 658a1e8f..85ac609b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,44 @@ and this project uses [independent versioning](README.md#versioning) for Framewo --- +## Framework 4.42.0 / CLI 3.43.0 — 2026-08-05 + +Google retired Gemini CLI; its successor is **Antigravity CLI** (`agy`). StrayMark's Gemini-era surfaces are retired with it — and the framework gains the mechanism that makes retiring a distributed path possible at all. + +**`GEMINI.md` is deliberately *not* retired.** Verified against `agy` 1.1.10 and the `agy-customizations` skill Google ships inside the binary: Antigravity reads `GEMINI.md` and `AGENTS.md` as first-class Rules files, and its global configuration lives in `~/.gemini/`. The product was retired; the on-disk contract was kept. Deleting the file would have removed a rules source Antigravity actively loads. + +### Added (Framework) + +- **`dist/.agent/skills/`**: 15 skills at `skills//SKILL.md` with the minimal frontmatter Antigravity expects. `.agent/` is one of its workspace customization roots (`.agents/`, `.agent/`, `_agents/`, `_agent/`), so the channel is discovered from the project tree with no install step. +- **`retired:` key in `dist-manifest.yml`**: declares paths a release no longer distributes. `update-framework` and `repair` delete them from existing installations; `init` ignores the key. + +### Changed (Framework) + +- **`GEMINI.md` directive re-framed to the Antigravity lineage**: title, `antigravity-v{version}` identity, and a note explaining why the file keeps the `GEMINI.md` name so nobody deletes it as a leftover. `gemini-cli-v1.0` is replaced by `antigravity-v1.0` across `AGENT-RULES.md` (EN/es/zh-CN), the `AGENTS.md` template and `STRAYMARK.md`. +- **Auditor-CLI prose points at `agy`** across the audit skills, governance docs, CLI output and website. **Gemini *model* ids are untouched** — the CLI was retired, the models were not, and the audit skills already require `auditor:` to name the backend model rather than the CLI. Historical records (Sentinel telemetry, the Charter-template rule justified by an observed Gemini-auditor behavior across 2 cycles) are left as written. + +### Removed (Framework) + +- **`dist/.gemini/skills/`** — `/.gemini/skills/` is not a discovery location for `agy`; it only ever served the retired product. Content lives on in `.agent/skills/`. +- **`dist/.agent/workflows/`** — `.agent/` was the right root but `workflows/.md` was never a shape Antigravity reads (the binary contains no `agent/workflows` string). It had been advertised as the Antigravity channel while being read by nothing. + +Both are declared under `retired:`, so `straymark update` removes them from existing installations instead of leaving them behind forever. + +### Fixed (CLI) + +- **Retiring a distributed path was previously impossible to complete.** `update_files` only ever copies, so a directory dropped from `files:` survived in every existing installation until someone ran `straymark remove`. Deletion is provenance-gated: a file goes only when its hash still matches the one `.checksums.json` recorded. Operator-edited files and files StrayMark never installed are kept and reported — and reported *distinctly*, because telling someone they "modified" a file they wrote themselves is simply wrong. +- **`repair` returned early on a healthy installation**, so the retirement sweep would never have run where it mattered. Leftover retired paths now count as repairable work. +- **`.gemini/skills/` had drifted behind `.claude/skills/` in 7 of 15 skills** — nothing regenerated or gated it. The replacement channel is generated, not hand-mirrored. + +### Changed (CLI) + +- `straymark install-skills --agent gemini` → `--agent agy`. The per-agent guidance no longer derives the source directory from the agent name (Antigravity reads `.agent/skills/`, not `.agy/skills/`). +- `gen_codex_skills` → **`gen_minimal_skills`**, now emitting both `.codex/skills/` and `.agent/skills/` from the Claude source. The existing CI job gates both. + +### Changed (Docs) + +- README, CLI-REFERENCE, ADOPTION-GUIDE, WORKFLOWS and TRANSLATION-GUIDE (EN/es/zh-CN) announce Antigravity CLI in place of Gemini CLI; "6 parallel forms" → 5. The zh-CN CLI-REFERENCE, which still documented `--agent ` and "4 parallel forms", is resynced. + ## Framework 4.41.0 / CLI 3.42.0 — 2026-08-05 Qwen Code becomes a first-class agent surface, and the "does a later `update` reach me?" gap that would have silently kept it away from existing installations is closed. Also corrects a documented claim about Qoder that the runtime contradicts. diff --git a/Cargo.lock b/Cargo.lock index 9060b7b2..f9c15478 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2574,7 +2574,7 @@ dependencies = [ [[package]] name = "straymark-cli" -version = "3.42.0" +version = "3.43.0" dependencies = [ "anyhow", "arborist-metrics", diff --git a/README.md b/README.md index f0e61a75..10945959 100644 --- a/README.md +++ b/README.md @@ -123,11 +123,11 @@ Sixteen document types covering the full development lifecycle (twelve core + fo Pre-configured for popular AI coding assistants: -- **Universal (AGENTS.md standard)** → `AGENTS.md` — read by Claude Code, OpenAI Codex CLI, Cursor, Aider, Devin, Sourcegraph Amp, Google Jules, Zed AI, Continue, Roo Code, Factory Droids, GitHub Copilot, Gemini CLI, Windsurf, Amazon Q and others +- **Universal (AGENTS.md standard)** → `AGENTS.md` — read by Claude Code, OpenAI Codex CLI, Cursor, Aider, Devin, Sourcegraph Amp, Google Jules, Zed AI, Continue, Roo Code, Factory Droids, GitHub Copilot, Antigravity CLI, Windsurf, Amazon Q and others - **Claude Code** (Anthropic) → `CLAUDE.md` - **Cursor** → `.cursorrules` - **GitHub Copilot CLI** → `.github/copilot-instructions.md` -- **Gemini CLI** (Google) → `GEMINI.md` +- **Antigravity CLI** (`agy`, Google) → `GEMINI.md` - **Qwen Code** (Alibaba) → `QWEN.md` Each configuration instructs the AI to: @@ -278,8 +278,8 @@ StrayMark uses independent version tags for each component: | Component | Tag prefix | Example | Includes | | --- | --- | --- | --- | -| Framework | `fw-` | `fw-4.41.0` | Templates (12 types), governance, directives, Charter template + schema | -| CLI | `cli-` | `cli-3.42.0` | The `straymark` binary | +| Framework | `fw-` | `fw-4.42.0` | Templates (12 types), governance, directives, Charter template + schema | +| CLI | `cli-` | `cli-3.43.0` | The `straymark` binary | | Loom (EXPERIMENTAL) | `loom-` | `loom-0.4.2` | The `straymark-loom` visualization server, downloaded on demand by `straymark loom serve` | Check installed versions with `straymark status` or `straymark about`. @@ -490,7 +490,7 @@ StrayMark includes skills for AI agents that enable **active documentation creat ### Available Skills -| Skill | Purpose | Claude | Gemini | Codex | +| Skill | Purpose | Claude | Antigravity | Codex | | --- | --- | --- | --- | --- | | `/straymark-status` | Check documentation compliance | ✅ | ✅ | ✅ | | `/straymark-new` | Create any document type (unified) | ✅ | ✅ | ✅ | @@ -554,11 +554,7 @@ StrayMark provides native skill support for multiple AI agents through a layered ``` your-project/ -├── .agent/workflows/ # 🌐 Agnostic (Antigravity, future agents) -│ ├── straymark-new.md -│ ├── straymark-status.md -│ └── ... -├── .gemini/skills/ # 🔵 Gemini CLI (Google) +├── .agent/skills/ # 🔵 Antigravity CLI (`agy`) — a customization root │ ├── straymark-new/SKILL.md │ └── ... ├── .claude/skills/ # 🟣 Claude Code (Anthropic) @@ -577,16 +573,15 @@ your-project/ | Directory | Agent | Product | Format | | --- | --- | --- | --- | -| `.agent/workflows/` | Antigravity, generic | VS Code/Cursor extensions | `skill-name.md` with YAML frontmatter | -| `.gemini/skills/` | Gemini CLI | Google's terminal CLI | `skill-name/SKILL.md` | +| `.agent/skills/` *(fw-4.42.0+)* | Antigravity CLI (`agy`) | Google's terminal coding agent | `skill-name/SKILL.md` (minimal frontmatter) — read from the project tree; `.agent/` is one of Antigravity's workspace customization roots | | `.claude/skills/` | Claude Code | Anthropic's coding agent | `skill-name/SKILL.md` | | `.codex/skills/` *(fw-4.19.0+)* | Codex CLI | OpenAI's coding agent | `skill-name/SKILL.md` (minimal frontmatter) — **must** be installed to `~/.codex/skills/` via `straymark install-skills --agent codex` | | `.qoder/skills/` | Qoder CLI | Qoder's terminal coding agent | `skill-name/SKILL.md` (full frontmatter, same as Claude) — read from the project tree; `straymark install-skills --agent qoder` optionally also populates `~/.qoder/skills/` | | `.qwen/skills/` *(fw-4.41.0+)* | Qwen Code | Alibaba's terminal coding agent | `skill-name/SKILL.md` (full frontmatter, same as Claude) — read from the project tree; `straymark install-skills --agent qwen` optionally also populates `~/.qwen/skills/` | -> **Note**: `.agent/` is the **vendor-agnostic** standard. Agent-specific directories (`.gemini/`, `.claude/`) provide compatibility for those platforms while following their native conventions. +> **Note**: `.agent/` is a workspace **customization root** Antigravity discovers by convention; the other directories follow each vendor's own layout. > -> **User-level vs project-level.** Only Codex *requires* `install-skills`: it resolves skills exclusively from `$CODEX_HOME/skills/`. Claude, Gemini, Qoder and Qwen Code all discover a project-scoped skills directory, so for Qoder and Qwen the user-level install is a convenience — it makes the StrayMark skills available in every project, not just the ones where the framework is installed. +> **User-level vs project-level.** Only Codex *requires* `install-skills`: it resolves skills exclusively from `$CODEX_HOME/skills/`. Claude, Antigravity, Qoder and Qwen Code all discover a project-scoped skills directory, so for Qoder and Qwen the user-level install is a convenience — it makes the StrayMark skills available in every project, not just the ones where the framework is installed. All skill implementations are **functionally identical**—only the format differs to match each agent's requirements. @@ -602,7 +597,7 @@ All skill implementations are **functionally identical**—only the format diffe | Claude Code | `CLAUDE.md` | ✅ Full support | | Cursor | `.cursorrules` | ✅ Full support | | GitHub Copilot CLI | `.github/copilot-instructions.md` | ✅ Full support | -| Gemini CLI | `GEMINI.md` | ✅ Full support | +| Antigravity CLI (`agy`) *(fw-4.42.0+)* | `GEMINI.md` + `.agent/skills/` | ✅ Full support | | Codex CLI (OpenAI) *(fw-4.19.0+)* | `AGENTS.md` + `~/.codex/skills/` | ✅ Full support (run `straymark install-skills --agent codex`) | | Qoder CLI | `AGENTS.md` + `.qoder/skills/` | ✅ Full support | | Qwen Code (Alibaba) *(fw-4.41.0+)* | `QWEN.md` + `.qwen/skills/` | ✅ Full support | diff --git a/cli/Cargo.toml b/cli/Cargo.toml index a9156dc0..64c8d519 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "straymark-cli" -version = "3.42.0" +version = "3.43.0" edition = "2021" description = "CLI for StrayMark — the cognitive discipline your AI-assisted projects need" license = "MIT" @@ -20,8 +20,8 @@ path = "src/main.rs" # Gated behind the non-default `dev-tools` feature so `cargo install straymark-cli` # does NOT install it — only the `straymark` binary ships to users. [[bin]] -name = "gen_codex_skills" -path = "src/bin/gen_codex_skills.rs" +name = "gen_minimal_skills" +path = "src/bin/gen_minimal_skills.rs" required-features = ["dev-tools"] [dependencies] diff --git a/cli/README.md b/cli/README.md index 1541d2f5..eceef391 100644 --- a/cli/README.md +++ b/cli/README.md @@ -56,7 +56,7 @@ The full subcommand reference (`init`, `update`, `remove`, `status`, `repair`, ` ## What StrayMark does - **Versioned governance artifacts** — 12 base document types (`AILOG`, `AIDEC`, `ETH`, `ADR`, `REQ`, `TES`, `INC`, `TDE`, `SEC`, `MCARD`, `SBOM`, `DPIA`) + 4 China-scope types + the `Charter` unit of work, each with schemas and lifecycle. -- **Multi-CLI agent directives injected** — keeps `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `.github/copilot-instructions.md`, `.cursorrules` and `.cursor/rules/straymark.md` in sync from a single `STRAYMARK.md` source of truth. +- **Multi-CLI agent directives injected** — keeps `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `QWEN.md`, `.github/copilot-instructions.md`, `.cursorrules` and `.cursor/rules/straymark.md` in sync from a single `STRAYMARK.md` source of truth. - **Charter drift check** — verifies declared files against `git diff` so the implementation cannot silently diverge from the ex-ante scope. - **External multi-CLI audit orchestration** — generates unified audit prompts and consolidates reports from multiple auditor CLIs into Charter telemetry. - **Multi-regulatory mapping** — output artifacts satisfy ISO/IEC 42001, EU AI Act, NIST AI RMF, ISO/IEC 25010, ISO/IEC/IEEE 29148, ISO/IEC/IEEE 29119-3, GDPR. @@ -66,8 +66,8 @@ The full subcommand reference (`init`, `update`, `remove`, `status`, `repair`, ` The CLI reads (and writes injection markers into) the dominant standards for AI coding agents: -- **`AGENTS.md`** — the open standard donated to the Agentic AI Foundation (Linux Foundation, December 2025), read by Claude Code, OpenAI Codex CLI, Cursor, Aider, Devin, Sourcegraph Amp, Google Jules, Zed AI, Continue, Roo Code, Factory Droids, GitHub Copilot, Gemini CLI, Windsurf, Amazon Q and others. -- **CLI-specific files** — `CLAUDE.md`, `GEMINI.md`, `.github/copilot-instructions.md`, `.cursorrules`, `.cursor/rules/straymark.md` for platform-specific identity strings. +- **`AGENTS.md`** — the open standard donated to the Agentic AI Foundation (Linux Foundation, December 2025), read by Claude Code, OpenAI Codex CLI, Cursor, Aider, Devin, Sourcegraph Amp, Google Jules, Zed AI, Continue, Roo Code, Factory Droids, GitHub Copilot, Antigravity CLI, Windsurf, Amazon Q and others. +- **CLI-specific files** — `CLAUDE.md`, `GEMINI.md` (read by Antigravity CLI), `QWEN.md`, `.github/copilot-instructions.md`, `.cursorrules`, `.cursor/rules/straymark.md` for platform-specific identity strings. All targets stay synchronized from a single `STRAYMARK.md` file maintained by `straymark update`. diff --git a/cli/src/bin/gen_codex_skills.rs b/cli/src/bin/gen_minimal_skills.rs similarity index 81% rename from cli/src/bin/gen_codex_skills.rs rename to cli/src/bin/gen_minimal_skills.rs index 7f9e95e3..b8ba2ac0 100644 --- a/cli/src/bin/gen_codex_skills.rs +++ b/cli/src/bin/gen_minimal_skills.rs @@ -1,12 +1,19 @@ -// Generator: transforms dist/.claude/skills/*/SKILL.md → dist/.codex/skills/*/SKILL.md -// with a minimal frontmatter (only `name` + `description`). +// Generator: transforms dist/.claude/skills/*/SKILL.md into every channel that +// wants the minimal frontmatter (`name` + `description` only): +// +// .codex/skills/ Codex CLI (OpenAI) +// .agent/skills/ Antigravity CLI (`agy`) — a workspace customization root // // Usage: -// cargo run --bin gen_codex_skills [--check] [] +// cargo run --bin gen_minimal_skills [--check] [] // // Default is `../dist` relative to CWD (i.e. run from `cli/`). -// With --check, exits 1 if the destination tree differs from what would be -// generated. Used in CI to keep `.codex/skills/` in sync with `.claude/skills/`. +// With --check, exits 1 if any destination tree differs from what would be +// generated. Used in CI to keep both channels in sync with `.claude/skills/`. +// +// Generating rather than hand-mirroring is the point: `.gemini/skills/`, the +// channel `.agent/skills/` replaces, had drifted behind `.claude/` in 7 of 15 +// skills precisely because nothing regenerated or gated it. use std::env; use std::fs; @@ -33,9 +40,19 @@ fn main() { } } +/// Channels generated from `.claude/skills/`: (label, root directory). +const TARGETS: &[(&str, &str)] = &[("Codex", ".codex"), ("Antigravity", ".agent")]; + fn run(dist: &Path, check_only: bool) -> Result<(), String> { + for (label, root) in TARGETS { + run_target(dist, check_only, label, root)?; + } + Ok(()) +} + +fn run_target(dist: &Path, check_only: bool, label: &str, root: &str) -> Result<(), String> { let src = dist.join(".claude").join("skills"); - let dst = dist.join(".codex").join("skills"); + let dst = dist.join(root).join("skills"); if !src.is_dir() { return Err(format!("source not found: {}", src.display())); @@ -90,10 +107,10 @@ fn run(dist: &Path, check_only: bool) -> Result<(), String> { } } if drift.is_empty() { - println!("Codex skills are in sync ({} skills).", produced.len()); + println!("{label} skills are in sync ({} skills).", produced.len()); return Ok(()); } - eprintln!("Codex skills out of sync. Run: cargo run --bin gen_codex_skills"); + eprintln!("{label} skills out of sync. Run: cargo run --bin gen_minimal_skills"); for p in drift { eprintln!(" - {}", p.display()); } @@ -112,7 +129,7 @@ fn run(dist: &Path, check_only: bool) -> Result<(), String> { } fs::write(out, content).map_err(|e| format!("write {}: {e}", out.display()))?; } - println!("Generated {} Codex skills in {}", produced.len(), dst.display()); + println!("Generated {} {label} skills in {}", produced.len(), dst.display()); for n in &names { println!(" - {n}"); } diff --git a/cli/src/commands/charter/audit.rs b/cli/src/commands/charter/audit.rs index 4eee50c9..938bdbc9 100644 --- a/cli/src/commands/charter/audit.rs +++ b/cli/src/commands/charter/audit.rs @@ -4,7 +4,7 @@ //! the operator's auditor responses, validates outputs against the schema, //! and prints the consolidated findings ready to paste into the Charter //! telemetry. The CLI does NOT invoke any LLM API directly — the operator -//! runs the prompts in their auditor of choice (Copilot, Gemini, Claude, etc.) +//! runs the prompts in their auditor of choice (Copilot, Antigravity, Claude, etc.) //! and saves the responses to canonical paths. //! //! Three steps, each invokable independently: @@ -367,7 +367,7 @@ fn run_prepare(args: PrepareArgs<'_>) -> Result<()> { println!(); println!(" {}", "Next:".bold()); println!( - " 1. Open one or more auditor CLIs (gemini-cli, claude-cli, copilot-cli, etc.)" + " 1. Open one or more auditor CLIs (agy, claude-cli, copilot-cli, etc.)" ); let round_arg = round.map(|r| format!(" --round {r}")).unwrap_or_default(); println!(" in this repo and invoke {} in each.", diff --git a/cli/src/commands/install_skills.rs b/cli/src/commands/install_skills.rs index d38142e0..f10ad661 100644 --- a/cli/src/commands/install_skills.rs +++ b/cli/src/commands/install_skills.rs @@ -18,8 +18,8 @@ use crate::utils; /// convenience: it makes the StrayMark skills available in every project, /// not just the ones where the framework is installed. /// -/// Claude and Gemini consume skills exclusively from the project tree -/// (`.claude/skills/`, `.gemini/skills/`); for those agents this command +/// Claude and Antigravity (`agy`) consume skills exclusively from the project +/// tree (`.claude/skills/`, `.agent/skills/`); for those agents this command /// exits with an explanatory error. pub fn run(agent: &str, project_path: &str, dry_run: bool, symlink: bool) -> Result<()> { match agent { @@ -47,9 +47,13 @@ pub fn run(agent: &str, project_path: &str, dry_run: bool, symlink: bool) -> Res dry_run, symlink, ), - "claude" | "gemini" => { + // Project-tree-only agents. The source directory is not derivable from + // the agent name — Antigravity reads `.agent/skills/`, not `.agy/` — + // so each one names its own path. + "claude" | "agy" => { + let dir = if agent == "claude" { ".claude/skills/" } else { ".agent/skills/" }; bail!( - "Skills for {agent} are read directly from the project tree (.{agent}/skills/). \ + "Skills for {agent} are read directly from the project tree ({dir}). \ No user-level install is required. Run `straymark init` or `straymark update` \ to refresh them in the project." ) diff --git a/cli/src/commands/repair.rs b/cli/src/commands/repair.rs index cc925a3f..cfacbb0b 100644 --- a/cli/src/commands/repair.rs +++ b/cli/src/commands/repair.rs @@ -7,6 +7,7 @@ use crate::config::Checksums; use crate::download; use crate::inject; use crate::manifest::{DistManifest, Injection}; +use crate::commands::update_framework; use crate::utils; /// Expected directories inside .straymark/ (same as init.rs) @@ -63,8 +64,23 @@ pub fn run(path: &str) -> Result<()> { // Check for missing framework files that require download let needs_download = check_needs_download(&target); + // Paths the installed release retired but that are still on disk. An + // otherwise-healthy installation has nothing *missing*, so without counting + // these the early return below would skip the sweep entirely. + let local_manifest = DistManifest::load(&target.join(".straymark/dist-manifest.yml")).ok(); + let has_retired_leftovers = local_manifest + .as_ref() + .map(|m| { + m.retired + .iter() + .any(|p| target.join(p.trim_end_matches('/')).exists()) + }) + .unwrap_or(false); + let missing_dir_count = missing_dirs.len(); - let total_issues = missing_dir_count + if needs_download { 1 } else { 0 }; + let total_issues = missing_dir_count + + if needs_download { 1 } else { 0 } + + if has_retired_leftovers { 1 } else { 0 }; if total_issues == 0 { utils::success("StrayMark structure is healthy, nothing to repair."); @@ -113,6 +129,29 @@ pub fn run(path: &str) -> Result<()> { restore_missing_files(&zip_path, &target)?; } + // Phase 3b: drop paths the installed release no longer distributes. Reads + // the local manifest, so a project that never updated past the retirement + // simply finds no `retired:` key and this is a no-op. + if has_retired_leftovers { + if let Some(manifest) = &local_manifest { + let checksums = Checksums::load(&target).unwrap_or_default(); + let prune = update_framework::prune_retired(&target, manifest, &checksums)?; + if !prune.removed.is_empty() { + utils::info(&format!("Removed {} retired file(s)", prune.removed.len())); + } + for path in &prune.kept_modified { + utils::warn(&format!( + "{path} is retired upstream but you modified it — kept" + )); + } + for path in &prune.kept_foreign { + utils::info(&format!( + "{path} is under a retired path but StrayMark did not install it — kept" + )); + } + } + } + // Phase 4: Recalculate checksums utils::info("Updating checksums..."); let version = load_current_version(&target); diff --git a/cli/src/commands/update_framework.rs b/cli/src/commands/update_framework.rs index 28492d7c..ac556456 100644 --- a/cli/src/commands/update_framework.rs +++ b/cli/src/commands/update_framework.rs @@ -79,6 +79,11 @@ pub fn run() -> Result<()> { utils::info("Updating AI agent directives..."); inject_directives(&target, &source_root, &manifest)?; + // Drop paths this release no longer distributes. Without this, retiring an + // agent surface would leave it in every existing installation forever — + // update_files() only ever copies, and only `straymark remove` deletes. + let prune = prune_retired(&target, &manifest, ¤t_checksums)?; + // Save manifest locally for future remove operations save_local_manifest(&target, &manifest)?; @@ -96,6 +101,15 @@ pub fn run() -> Result<()> { println!(" - {} (kept your version)", path.dimmed()); } println!(" Files added: {}", stats.added); + if !prune.removed.is_empty() { + println!(" Files retired: {}", prune.removed.len()); + } + for path in &prune.kept_modified { + println!(" - {} (retired upstream, kept — you modified it)", path.dimmed()); + } + for path in &prune.kept_foreign { + println!(" - {} (retired upstream, kept — not installed by StrayMark)", path.dimmed()); + } Ok(()) } @@ -239,6 +253,133 @@ fn update_files( Ok(stats) } +/// Outcome of a retired-path sweep. +pub struct PruneStats { + /// Relative paths deleted — files StrayMark installed and the operator + /// never touched. + pub removed: Vec, + /// Paths StrayMark installed but the operator has since edited. + pub kept_modified: Vec, + /// Paths absent from the checksum store: operator-authored, or put there by + /// something other than StrayMark. Reported separately because telling + /// someone they "modified" a file they wrote themselves is just wrong. + pub kept_foreign: Vec, +} + +/// Delete the paths a release declares under `retired:`. +/// +/// Deletion is gated on provenance, not on the path pattern: a file goes only +/// when its current hash equals the one `.checksums.json` recorded for it — +/// i.e. StrayMark put it there and nobody has edited it since. Operator-edited +/// files and files absent from the store (operator-authored, or dropped in by +/// something else) are kept and named in the report, because a retirement +/// notice from upstream is not a licence to delete someone's work. +pub fn prune_retired( + target: &Path, + manifest: &DistManifest, + checksums: &Checksums, +) -> Result { + let mut stats = PruneStats { + removed: Vec::new(), + kept_modified: Vec::new(), + kept_foreign: Vec::new(), + }; + + for entry in &manifest.retired { + let entry_path = target.join(entry.trim_end_matches('/')); + if !entry_path.exists() { + continue; + } + + let files = if entry_path.is_dir() { + walkdir(entry_path.clone())? + } else { + vec![entry_path.clone()] + }; + + for file in files { + let relative = file + .strip_prefix(target) + .unwrap_or(&file) + .display() + .to_string() + .replace('\\', "/"); + + let current = utils::file_hash(&file); + match checksums.files.get(&relative) { + Some(stored) if current.as_deref() == Some(stored.as_str()) => { + std::fs::remove_file(&file) + .with_context(|| format!("Failed to remove {}", file.display()))?; + stats.removed.push(relative); + } + Some(_) => stats.kept_modified.push(relative), + None => stats.kept_foreign.push(relative), + } + } + + // Sweep bottom-up: a skill directory whose only file was pruned is now + // empty even when its parent still holds files the operator kept. + prune_empty_subtree(&entry_path); + remove_empty_dirs(&entry_path, target); + } + + Ok(stats) +} + +/// Remove every empty directory inside `root` (and `root` itself if it ends up +/// empty), deepest first. Best-effort: anything still holding a file stays. +fn prune_empty_subtree(root: &Path) { + if !root.is_dir() { + return; + } + let mut dirs = Vec::new(); + let mut stack = vec![root.to_path_buf()]; + while let Some(dir) = stack.pop() { + let entries = match std::fs::read_dir(&dir) { + Ok(e) => e, + Err(_) => continue, + }; + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + stack.push(path.clone()); + dirs.push(path); + } + } + } + // Deepest first, so a parent is only considered once its children are gone. + dirs.sort_by_key(|p| std::cmp::Reverse(p.components().count())); + for dir in dirs { + if std::fs::read_dir(&dir).map(|mut e| e.next().is_none()).unwrap_or(false) { + let _ = std::fs::remove_dir(&dir); + } + } +} + +/// Remove `dir` and any parent left empty, stopping at `stop_at` (exclusive). +/// Best-effort: a non-empty directory simply ends the walk. +fn remove_empty_dirs(dir: &Path, stop_at: &Path) { + let mut current = dir.to_path_buf(); + while current.starts_with(stop_at) && current != stop_at { + if !current.is_dir() { + // Not a directory (or already gone) — climb to the parent anyway, + // which is the case where `retired:` named a single file. + } else { + let empty = match std::fs::read_dir(¤t) { + Ok(mut entries) => entries.next().is_none(), + Err(_) => return, + }; + if !empty || std::fs::remove_dir(¤t).is_err() { + return; + } + } + match current.parent() { + Some(parent) => current = parent.to_path_buf(), + None => return, + } + } +} + /// Inject directives based on manifest and templates from the release fn inject_directives(target: &Path, source_root: &Path, manifest: &DistManifest) -> Result<()> { for injection in &manifest.injections { @@ -409,6 +550,129 @@ fn walkdir(dir: PathBuf) -> Result> { #[cfg(test)] mod tests { use super::matches_manifest; + use crate::config::Checksums; + use crate::manifest::DistManifest; + + fn manifest_with_retired(retired: &str) -> DistManifest { + DistManifest::from_str(&format!( + "version: \"4.42.0\"\ndescription: \"test\"\nrepository: \"x\"\n\ + files: []\ninjections: []\nretired:\n - {retired}\n" + )) + .unwrap() + } + + fn seed(root: &std::path::Path, rel: &str, body: &str) -> String { + let path = root.join(rel); + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + std::fs::write(&path, body).unwrap(); + crate::utils::file_hash(&path).unwrap() + } + + // Retiring a distributed path used to be impossible to finish: update_files + // only ever copies, so a directory dropped from `files:` survived in every + // existing installation until someone ran `straymark remove`. Deletion is + // provenance-gated — a retirement notice upstream is not a licence to + // delete work the operator did inside the path. + #[test] + fn retired_directory_is_pruned_but_operator_work_survives() { + let tmp = tempfile::tempdir().unwrap(); + let target = tmp.path(); + + // Three files under the retired path, three different provenances. + let pristine = seed(target, ".gemini/skills/straymark-new/SKILL.md", "shipped\n"); + let edited = seed(target, ".gemini/skills/straymark-adr/SKILL.md", "shipped\n"); + seed(target, ".gemini/skills/my-own/SKILL.md", "the operator's own\n"); + + let mut checksums = Checksums::default(); + checksums + .files + .insert(".gemini/skills/straymark-new/SKILL.md".into(), pristine); + checksums + .files + .insert(".gemini/skills/straymark-adr/SKILL.md".into(), edited); + // `my-own` is deliberately absent from the store: never ours. + + // The operator edits one of the shipped files after installation. + std::fs::write( + target.join(".gemini/skills/straymark-adr/SKILL.md"), + "shipped, then edited by me\n", + ) + .unwrap(); + + let manifest = manifest_with_retired(".gemini/skills/"); + let stats = super::prune_retired(target, &manifest, &checksums).unwrap(); + + assert_eq!( + stats.removed, + vec![".gemini/skills/straymark-new/SKILL.md".to_string()], + "only the untouched shipped file may be deleted" + ); + assert!( + !target.join(".gemini/skills/straymark-new").exists(), + "the emptied skill directory should be cleaned up too" + ); + + assert_eq!( + stats.kept_modified, + vec![".gemini/skills/straymark-adr/SKILL.md".to_string()], + "a file we shipped and the operator edited is kept as *modified*" + ); + assert_eq!( + stats.kept_foreign, + vec![".gemini/skills/my-own/SKILL.md".to_string()], + "a file we never installed is kept, but must not be reported as \"you modified it\"" + ); + assert!(target.join(".gemini/skills/straymark-adr/SKILL.md").exists()); + assert!(target.join(".gemini/skills/my-own/SKILL.md").exists()); + } + + #[test] + fn fully_pruned_directory_disappears_including_its_parents() { + let tmp = tempfile::tempdir().unwrap(); + let target = tmp.path(); + + let mut checksums = Checksums::default(); + for rel in [ + ".agent/workflows/straymark-new.md", + ".agent/workflows/straymark-adr.md", + ] { + checksums.files.insert(rel.into(), seed(target, rel, "x\n")); + } + + let manifest = manifest_with_retired(".agent/workflows/"); + let stats = super::prune_retired(target, &manifest, &checksums).unwrap(); + + assert_eq!(stats.removed.len(), 2); + assert!(stats.kept_modified.is_empty() && stats.kept_foreign.is_empty()); + assert!( + !target.join(".agent").exists(), + "an emptied parent must go too, or the adopter keeps a bare .agent/" + ); + } + + #[test] + fn retiring_a_path_that_is_already_gone_is_a_no_op() { + let tmp = tempfile::tempdir().unwrap(); + let manifest = manifest_with_retired(".gemini/skills/"); + let stats = + super::prune_retired(tmp.path(), &manifest, &Checksums::default()).unwrap(); + assert!(stats.removed.is_empty() && stats.kept_modified.is_empty()); + } + + /// Every `.straymark/dist-manifest.yml` written before fw-4.42.0 lacks the + /// key, and `repair` / `remove` re-read those copies. Without + /// `#[serde(default)]` this turns every pre-4.42.0 installation into a + /// parse error. + #[test] + fn manifest_without_the_retired_key_still_parses() { + let manifest = DistManifest::from_str( + "version: \"4.41.0\"\ndescription: \"test\"\nrepository: \"x\"\n\ + files:\n - STRAYMARK.md\ninjections: []\n", + ) + .unwrap(); + assert!(manifest.retired.is_empty()); + assert_eq!(manifest.version, "4.41.0"); + } fn manifest_files() -> Vec { // Matches `dist/dist-manifest.yml` (fw-4.3.0). diff --git a/cli/src/main.rs b/cli/src/main.rs index fc2b2b31..788b7d57 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -94,12 +94,12 @@ enum Commands { /// `--agent qwen` targets `$QWEN_HOME/skills/` or `$HOME/.qwen/skills/`). /// Required only for Codex: Qoder and Qwen Code also read the project-scoped /// `.qoder/skills/` / `.qwen/skills/`, so there the user-level install just - /// makes the skills available outside this project. Claude and Gemini read - /// skills exclusively from the project tree (`.claude/skills/`, - /// `.gemini/skills/`) and do not accept this command. + /// makes the skills available outside this project. Claude and Antigravity + /// (`agy`) read skills exclusively from the project tree (`.claude/skills/`, + /// `.agent/skills/`) and do not accept this command. InstallSkills { /// AI agent whose user-level skills directory we should populate. - #[arg(long, value_parser = ["codex", "qoder", "qwen", "claude", "gemini"])] + #[arg(long, value_parser = ["codex", "qoder", "qwen", "claude", "agy"])] agent: String, /// Project directory (default: current directory). The source of the /// skills is `/.codex/skills/` (or `/.qoder/skills/`, @@ -688,7 +688,7 @@ enum CharterCommands { /// calibrate, finalize). Phase 3 v0 is orchestration-only — the CLI /// resolves prompts, validates auditor outputs, and prints findings /// for telemetry. It does NOT invoke LLM APIs; the operator runs the - /// prompts in their auditor of choice (Copilot, Gemini, Claude, etc.) + /// prompts in their auditor of choice (Copilot, Antigravity, Claude, etc.) /// and saves responses to canonical paths. Audit { /// Charter identifier (CHARTER-NN, CHARTER-NN-slug, or just NN) diff --git a/cli/src/manifest.rs b/cli/src/manifest.rs index e163a3cf..870251a9 100644 --- a/cli/src/manifest.rs +++ b/cli/src/manifest.rs @@ -10,6 +10,15 @@ pub struct DistManifest { pub files: Vec, #[serde(default)] pub injections: Vec, + /// Paths this release no longer distributes. `update-framework` and + /// `repair` delete them from an existing installation; `init` ignores the + /// key entirely (nothing to retire in a fresh tree). + /// + /// `#[serde(default)]` is load-bearing: every `.straymark/dist-manifest.yml` + /// written by a release before fw-4.42.0 lacks the key, and those copies are + /// re-read by `repair` and `remove`. + #[serde(default)] + pub retired: Vec, } #[derive(Debug, Deserialize, Serialize, Clone)] diff --git a/cli/tests/architecture_skill_test.rs b/cli/tests/architecture_skill_test.rs index e332880f..481894b5 100644 --- a/cli/tests/architecture_skill_test.rs +++ b/cli/tests/architecture_skill_test.rs @@ -1,10 +1,9 @@ //! Sanity tests for the architecture / Loom skills shipped under `dist/`. //! //! These verify that each skill file exists with the expected frontmatter -//! shape (Claude/Qoder/Qwen have `allowed-tools`, Gemini and Codex have `name` -//! but no `allowed-tools`, agent workflow has only `description`) and that all -//! six surfaces carry the load-bearing guidance. They run against the source -//! tree, not against an +//! shape (Claude/Qoder/Qwen carry `allowed-tools`; Codex and Antigravity carry +//! `name` + `description` only) and that all five surfaces carry the +//! load-bearing guidance. They run against the source tree, not against an //! `init`-ed project, because the manifest already includes the parent //! directories recursively — if the files exist in `dist/`, `init` copies them. @@ -25,8 +24,8 @@ fn claude(skill: &str) -> String { read(dist_root().join(".claude").join("skills").join(skill).join("SKILL.md")) } -fn gemini(skill: &str) -> String { - read(dist_root().join(".gemini").join("skills").join(skill).join("SKILL.md")) +fn antigravity(skill: &str) -> String { + read(dist_root().join(".agent").join("skills").join(skill).join("SKILL.md")) } fn codex(skill: &str) -> String { @@ -41,25 +40,22 @@ fn qwen(skill: &str) -> String { read(dist_root().join(".qwen").join("skills").join(skill).join("SKILL.md")) } -fn agent(skill: &str) -> String { - read(dist_root().join(".agent").join("workflows").join(format!("{skill}.md"))) -} - -/// The six-variant frontmatter contract every shipped skill must honor. +/// The five-variant frontmatter contract every shipped skill must honor. /// Qoder and Qwen Code parse the full Claude-format frontmatter, so their -/// variants are byte-for-byte mirrors of the Claude one. -fn assert_six_variant_shape(skill: &str) { +/// variants are byte-for-byte mirrors of the Claude one; Codex and Antigravity +/// take the minimal frontmatter and are generated by `gen_minimal_skills`. +fn assert_five_variant_shape(skill: &str) { let c = claude(skill); assert!(c.starts_with("---\n"), "{skill}: claude missing YAML frontmatter"); assert!(c.contains(&format!("name: {skill}")), "{skill}: claude missing name field"); assert!(c.contains("allowed-tools:"), "{skill}: claude must declare allowed-tools"); - let g = gemini(skill); - assert!(g.starts_with("---\n"), "{skill}: gemini missing YAML frontmatter"); - assert!(g.contains(&format!("name: {skill}")), "{skill}: gemini missing name field"); + let g = antigravity(skill); + assert!(g.starts_with("---\n"), "{skill}: antigravity missing YAML frontmatter"); + assert!(g.contains(&format!("name: {skill}")), "{skill}: antigravity missing name field"); assert!( !g.contains("allowed-tools:"), - "{skill}: gemini must not declare allowed-tools" + "{skill}: antigravity must not declare allowed-tools" ); let x = codex(skill); @@ -77,33 +73,22 @@ fn assert_six_variant_shape(skill: &str) { ); } - let a = agent(skill); - assert!(a.starts_with("---\n"), "{skill}: agent workflow missing YAML frontmatter"); - assert!( - !a.contains("name:"), - "{skill}: agent workflow must not declare a name field (description-only)" - ); - assert!( - !a.contains("allowed-tools:"), - "{skill}: agent workflow must not declare allowed-tools" - ); - assert!(a.contains("description:"), "{skill}: agent workflow must declare description"); } // ── straymark-architecture ────────────────────────────────────────────────── #[test] -fn architecture_skill_has_six_variant_shape() { - assert_six_variant_shape("straymark-architecture"); +fn architecture_skill_has_five_variant_shape() { + assert_five_variant_shape("straymark-architecture"); } #[test] fn architecture_skill_shares_core_guidance() { for body in [ &claude("straymark-architecture"), - &gemini("straymark-architecture"), + &antigravity("straymark-architecture"), &codex("straymark-architecture"), - &agent("straymark-architecture"), + &antigravity("straymark-architecture"), ] { // Wraps the CLI commands it drives. assert!( @@ -143,17 +128,17 @@ fn architecture_skill_shares_core_guidance() { // ── straymark-loom ────────────────────────────────────────────────────────── #[test] -fn loom_skill_has_six_variant_shape() { - assert_six_variant_shape("straymark-loom"); +fn loom_skill_has_five_variant_shape() { + assert_five_variant_shape("straymark-loom"); } #[test] fn loom_skill_shares_core_guidance() { for body in [ &claude("straymark-loom"), - &gemini("straymark-loom"), + &antigravity("straymark-loom"), &codex("straymark-loom"), - &agent("straymark-loom"), + &antigravity("straymark-loom"), ] { assert!( body.contains("straymark loom serve"), @@ -184,17 +169,17 @@ fn loom_skill_shares_core_guidance() { // ── straymark-architecture-sync ───────────────────────────────────────────── #[test] -fn architecture_sync_skill_has_six_variant_shape() { - assert_six_variant_shape("straymark-architecture-sync"); +fn architecture_sync_skill_has_five_variant_shape() { + assert_five_variant_shape("straymark-architecture-sync"); } #[test] fn architecture_sync_skill_shares_core_guidance() { for body in [ &claude("straymark-architecture-sync"), - &gemini("straymark-architecture-sync"), + &antigravity("straymark-architecture-sync"), &codex("straymark-architecture-sync"), - &agent("straymark-architecture-sync"), + &antigravity("straymark-architecture-sync"), ] { assert!( body.contains("straymark architecture sync"), diff --git a/cli/tests/audit_skill_test.rs b/cli/tests/audit_skill_test.rs index b63c7f25..a479510e 100644 --- a/cli/tests/audit_skill_test.rs +++ b/cli/tests/audit_skill_test.rs @@ -1,8 +1,8 @@ //! Sanity tests for the audit-related skills shipped under `dist/`. //! //! These tests verify that the skill files exist and have the expected -//! frontmatter shape (Claude has `allowed-tools`, Gemini has `name` but no -//! `allowed-tools`, agent workflow has only `description`). They run +//! frontmatter shape (Claude has `allowed-tools`; Antigravity, generated by +//! `gen_minimal_skills`, has `name` + `description` only). They run //! against the source tree, not against an `init`-ed project, because the //! manifest already includes the parent directories recursively — if the //! files exist in `dist/`, `init` will copy them. @@ -45,10 +45,10 @@ fn straymark_audit_prompt_claude_skill_exists_and_has_allowed_tools() { } #[test] -fn straymark_audit_prompt_gemini_skill_exists_without_allowed_tools() { +fn straymark_audit_prompt_antigravity_skill_exists_without_allowed_tools() { let body = read( dist_root() - .join(".gemini") + .join(".agent") .join("skills") .join("straymark-audit-prompt") .join("SKILL.md"), @@ -60,35 +60,12 @@ fn straymark_audit_prompt_gemini_skill_exists_without_allowed_tools() { ); assert!( !body.contains("allowed-tools:"), - "Gemini skill must not declare allowed-tools (no such field in Gemini skill schema)" - ); -} - -#[test] -fn straymark_audit_prompt_agent_workflow_exists_with_description_only() { - let body = read( - dist_root() - .join(".agent") - .join("workflows") - .join("straymark-audit-prompt.md"), - ); - assert!(body.starts_with("---\n"), "missing YAML frontmatter"); - assert!( - !body.contains("name:"), - "agent workflow must not declare a name field (description-only frontmatter)" - ); - assert!( - !body.contains("allowed-tools:"), - "agent workflow must not declare allowed-tools" - ); - assert!( - body.contains("description:"), - "agent workflow must declare description" + "Antigravity skills take the minimal frontmatter: `name` + `description` only" ); } #[test] -fn straymark_audit_prompt_three_platforms_share_core_guidance() { +fn straymark_audit_prompt_both_surfaces_share_core_guidance() { let claude = read( dist_root() .join(".claude") @@ -96,24 +73,18 @@ fn straymark_audit_prompt_three_platforms_share_core_guidance() { .join("straymark-audit-prompt") .join("SKILL.md"), ); - let gemini = read( + let antigravity = read( dist_root() - .join(".gemini") + .join(".agent") .join("skills") .join("straymark-audit-prompt") .join("SKILL.md"), ); - let agent = read( - dist_root() - .join(".agent") - .join("workflows") - .join("straymark-audit-prompt.md"), - ); // v1: skill no longer surfaces prompts inline. It runs --prepare and // points the operator at /straymark-audit-execute in N CLIs. The // wait-for-all warning is the load-bearing UX guarantee. - for body in [&claude, &gemini, &agent] { + for body in [&claude, &antigravity] { assert!( body.contains("/straymark-audit-execute"), "skill must point operator at the auditor-side execute skill" @@ -170,10 +141,10 @@ fn straymark_audit_review_claude_skill_exists_and_has_allowed_tools() { } #[test] -fn straymark_audit_review_gemini_skill_exists_without_allowed_tools() { +fn straymark_audit_review_antigravity_skill_exists_without_allowed_tools() { let body = read( dist_root() - .join(".gemini") + .join(".agent") .join("skills") .join("straymark-audit-review") .join("SKILL.md"), @@ -185,35 +156,12 @@ fn straymark_audit_review_gemini_skill_exists_without_allowed_tools() { ); assert!( !body.contains("allowed-tools:"), - "Gemini skill must not declare allowed-tools" - ); -} - -#[test] -fn straymark_audit_review_agent_workflow_exists_with_description_only() { - let body = read( - dist_root() - .join(".agent") - .join("workflows") - .join("straymark-audit-review.md"), - ); - assert!(body.starts_with("---\n"), "missing YAML frontmatter"); - assert!( - !body.contains("name:"), - "agent workflow must not declare a name field" - ); - assert!( - !body.contains("allowed-tools:"), - "agent workflow must not declare allowed-tools" - ); - assert!( - body.contains("description:"), - "agent workflow must declare description" + "Antigravity skills take the minimal frontmatter: `name` + `description` only" ); } #[test] -fn straymark_audit_review_three_platforms_share_core_guidance() { +fn straymark_audit_review_both_surfaces_share_core_guidance() { let claude = read( dist_root() .join(".claude") @@ -221,21 +169,15 @@ fn straymark_audit_review_three_platforms_share_core_guidance() { .join("straymark-audit-review") .join("SKILL.md"), ); - let gemini = read( + let antigravity = read( dist_root() - .join(".gemini") + .join(".agent") .join("skills") .join("straymark-audit-review") .join("SKILL.md"), ); - let agent = read( - dist_root() - .join(".agent") - .join("workflows") - .join("straymark-audit-review.md"), - ); - for body in [&claude, &gemini, &agent] { + for body in [&claude, &antigravity] { // v1: review consolidates N reports + writes review.md + // optionally merges YAML. No more --calibrate / --finalize // round-trip. @@ -326,10 +268,10 @@ fn straymark_audit_execute_claude_skill_exists_and_has_allowed_tools() { } #[test] -fn straymark_audit_execute_gemini_skill_exists_without_allowed_tools() { +fn straymark_audit_execute_antigravity_skill_exists_without_allowed_tools() { let body = read( dist_root() - .join(".gemini") + .join(".agent") .join("skills") .join("straymark-audit-execute") .join("SKILL.md"), @@ -341,35 +283,12 @@ fn straymark_audit_execute_gemini_skill_exists_without_allowed_tools() { ); assert!( !body.contains("allowed-tools:"), - "Gemini skill must not declare allowed-tools" - ); -} - -#[test] -fn straymark_audit_execute_agent_workflow_exists_with_description_only() { - let body = read( - dist_root() - .join(".agent") - .join("workflows") - .join("straymark-audit-execute.md"), - ); - assert!(body.starts_with("---\n"), "missing YAML frontmatter"); - assert!( - !body.contains("name:"), - "agent workflow must not declare a name field" - ); - assert!( - !body.contains("allowed-tools:"), - "agent workflow must not declare allowed-tools" - ); - assert!( - body.contains("description:"), - "agent workflow must declare description" + "Antigravity skills take the minimal frontmatter: `name` + `description` only" ); } #[test] -fn straymark_audit_execute_three_platforms_share_core_guidance() { +fn straymark_audit_execute_both_surfaces_share_core_guidance() { let claude = read( dist_root() .join(".claude") @@ -377,21 +296,15 @@ fn straymark_audit_execute_three_platforms_share_core_guidance() { .join("straymark-audit-execute") .join("SKILL.md"), ); - let gemini = read( + let antigravity = read( dist_root() - .join(".gemini") + .join(".agent") .join("skills") .join("straymark-audit-execute") .join("SKILL.md"), ); - let agent = read( - dist_root() - .join(".agent") - .join("workflows") - .join("straymark-audit-execute.md"), - ); - for body in [&claude, &gemini, &agent] { + for body in [&claude, &antigravity] { // Canonical paths the skill uses. assert!( body.contains(".straymark/audits/"), diff --git a/cli/tests/retired_paths_test.rs b/cli/tests/retired_paths_test.rs new file mode 100644 index 00000000..763da064 --- /dev/null +++ b/cli/tests/retired_paths_test.rs @@ -0,0 +1,50 @@ +//! `retired:` — the declarative retirement mechanism (fw-4.42.0). +//! +//! Behavioral coverage of the sweep itself lives next to the code, in +//! `commands::update_framework::tests` (this crate has no lib target, so +//! integration tests can only reach the filesystem). What is pinned here is the +//! *shipped manifest*: the mechanism is inert unless the release actually +//! declares the channels it retires. + +use std::fs; + +fn manifest() -> String { + let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .join("dist/dist-manifest.yml"); + fs::read_to_string(&path).expect("dist-manifest.yml must exist") +} + +#[test] +fn shipped_manifest_retires_the_dead_channels() { + let m = manifest(); + let retired_block = m + .split("retired:") + .nth(1) + .expect("dist-manifest.yml must declare a `retired:` key"); + + for path in [".gemini/skills/", ".agent/workflows/"] { + assert!( + retired_block.contains(&format!("- {path}")), + "dist-manifest.yml must retire {path}" + ); + } +} + +#[test] +fn retired_channels_are_not_also_distributed() { + let m = manifest(); + let files_block = m + .split("files:") + .nth(1) + .and_then(|s| s.split("injections:").next()) + .expect("dist-manifest.yml must declare `files:`"); + + for path in [".gemini/skills/", ".agent/workflows/"] { + assert!( + !files_block.contains(&format!("- {path}")), + "{path} cannot be distributed and retired at the same time" + ); + } +} diff --git a/dist/.gemini/skills/straymark-adr/SKILL.md b/dist/.agent/skills/straymark-adr/SKILL.md similarity index 94% rename from dist/.gemini/skills/straymark-adr/SKILL.md rename to dist/.agent/skills/straymark-adr/SKILL.md index 03da8b1d..9949bc1f 100644 --- a/dist/.gemini/skills/straymark-adr/SKILL.md +++ b/dist/.agent/skills/straymark-adr/SKILL.md @@ -75,7 +75,7 @@ Fill template with: - `status`: **draft** (always for AI-created ADRs) - `created`: Current date - `updated`: Current date -- `agent`: your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `gemini-cli-v1.0`, `codex-cli-v1.0`; do not assume Claude) +- `agent`: your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `antigravity-v1.0`, `codex-cli-v1.0`; do not assume Claude) - `confidence`: based on research done - `review_required`: **true** (always for ADRs) - `risk_level`: minimum `medium` for architectural decisions @@ -112,3 +112,5 @@ StrayMark: Created ADR-YYYY-MM-DD-NNN-description.md (review required) - Select authentication strategy (JWT, OAuth, etc.) - Define module boundaries and dependencies - Establish caching strategy + +> **Terminal compatibility**: If the terminal does not support box-drawing characters (Unicode), use plain-text formatting with dashes and pipes instead (e.g., `+--+` instead of `╔══╗`). diff --git a/dist/.gemini/skills/straymark-aidec/SKILL.md b/dist/.agent/skills/straymark-aidec/SKILL.md similarity index 92% rename from dist/.gemini/skills/straymark-aidec/SKILL.md rename to dist/.agent/skills/straymark-aidec/SKILL.md index 5e655fb3..9f4507fc 100644 --- a/dist/.gemini/skills/straymark-aidec/SKILL.md +++ b/dist/.agent/skills/straymark-aidec/SKILL.md @@ -62,7 +62,7 @@ Fill template with: - `id`: AIDEC-YYYY-MM-DD-NNN - `title`: Decision title from user - `created`: Current date -- `agent`: your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `gemini-cli-v1.0`, `codex-cli-v1.0`; do not assume Claude) +- `agent`: your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `antigravity-v1.0`, `codex-cli-v1.0`; do not assume Claude) - `confidence`: based on decision clarity - `risk_level`: based on decision impact @@ -91,3 +91,5 @@ StrayMark: Created AIDEC-YYYY-MM-DD-NNN-description.md - Decided on a data structure - Made a performance vs. readability trade-off - Selected between design patterns + +> **Terminal compatibility**: If the terminal does not support box-drawing characters (Unicode), use plain-text formatting with dashes and pipes instead (e.g., `+--+` instead of `╔══╗`). diff --git a/dist/.gemini/skills/straymark-ailog/SKILL.md b/dist/.agent/skills/straymark-ailog/SKILL.md similarity index 92% rename from dist/.gemini/skills/straymark-ailog/SKILL.md rename to dist/.agent/skills/straymark-ailog/SKILL.md index 2173776a..fc1b63f2 100644 --- a/dist/.gemini/skills/straymark-ailog/SKILL.md +++ b/dist/.agent/skills/straymark-ailog/SKILL.md @@ -68,7 +68,7 @@ Fill template with: - `id`: AILOG-YYYY-MM-DD-NNN - `title`: User-provided description - `created`: Current date -- `agent`: your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `gemini-cli-v1.0`, `codex-cli-v1.0`; do not assume Claude) +- `agent`: your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `antigravity-v1.0`, `codex-cli-v1.0`; do not assume Claude) - `confidence`: based on change complexity - `risk_level`: based on files modified @@ -91,3 +91,5 @@ StrayMark: Created AILOG-YYYY-MM-DD-NNN-description.md | Business logic changes | medium | | Auth, security, payments | high | | Database schema, migrations | critical | + +> **Terminal compatibility**: If the terminal does not support box-drawing characters (Unicode), use plain-text formatting with dashes and pipes instead (e.g., `+--+` instead of `╔══╗`). diff --git a/dist/.gemini/skills/straymark-architecture-sync/SKILL.md b/dist/.agent/skills/straymark-architecture-sync/SKILL.md similarity index 100% rename from dist/.gemini/skills/straymark-architecture-sync/SKILL.md rename to dist/.agent/skills/straymark-architecture-sync/SKILL.md diff --git a/dist/.gemini/skills/straymark-architecture/SKILL.md b/dist/.agent/skills/straymark-architecture/SKILL.md similarity index 100% rename from dist/.gemini/skills/straymark-architecture/SKILL.md rename to dist/.agent/skills/straymark-architecture/SKILL.md diff --git a/dist/.gemini/skills/straymark-audit-execute/SKILL.md b/dist/.agent/skills/straymark-audit-execute/SKILL.md similarity index 86% rename from dist/.gemini/skills/straymark-audit-execute/SKILL.md rename to dist/.agent/skills/straymark-audit-execute/SKILL.md index 372228f4..d0e3c0ac 100644 --- a/dist/.gemini/skills/straymark-audit-execute/SKILL.md +++ b/dist/.agent/skills/straymark-audit-execute/SKILL.md @@ -1,6 +1,6 @@ --- name: straymark-audit-execute -description: Execute an external audit of a Charter inside an auditor-side CLI (gemini-cli, claude-cli, copilot-cli, codex-cli). Reads the resolved audit prompt from the canonical location, audits with tool use, writes the report. Operator invokes one instance per CLI. +description: Execute an external audit of a Charter inside an auditor-side CLI (agy, claude-cli, copilot-cli, codex-cli). Reads the resolved audit prompt from the canonical location, audits with tool use, writes the report. Operator invokes one instance per CLI. --- # StrayMark Audit Execute Skill @@ -9,7 +9,7 @@ Execute an external audit of a Charter inside this CLI session. Read the resolve ## When to invoke -This skill runs **inside an auditor-side CLI** (gemini-cli, claude-cli, copilot-cli, codex-cli, or any agent runtime configured with read-only access to the adopter's repo). The operator opens the CLI in the repo, then invokes `/straymark-audit-execute `. +This skill runs **inside an auditor-side CLI** (agy, claude-cli, copilot-cli, codex-cli, or any agent runtime configured with read-only access to the adopter's repo). The operator opens the CLI in the repo, then invokes `/straymark-audit-execute `. The skill is the second step of the v1 audit cycle: @@ -45,9 +45,9 @@ For each found `.straymark/audits//audit-prompt.md`, check whether a **The `auditor:` identity is authoritative input from the operator, not something you infer about yourself.** Resolve it, in priority order: 1. **Second argument** — `/straymark-audit-execute ` (e.g. `/straymark-audit-execute CHARTER-06 deepseek-v4-pro`). -2. **What the operator states in chat** — "I selected model X", "seleccioné el modelo X", "identify as X", "use X". The CLI you run inside (Qwen Code, Claude Code, Gemini CLI, Copilot CLI, …) is a **router, not the model**: it routes prompts to a backend LLM the operator picks via `/model` and confirms in the status bar. The `auditor:` field must name that **backend model** (e.g. `glm-5-2`, `qwen3-7-max`, `deepseek-v4-pro`), which routinely differs from the CLI's product name. +2. **What the operator states in chat** — "I selected model X", "seleccioné el modelo X", "identify as X", "use X". The CLI you run inside (Qwen Code, Claude Code, Antigravity CLI, Copilot CLI, …) is a **router, not the model**: it routes prompts to a backend LLM the operator picks via `/model` and confirms in the status bar. The `auditor:` field must name that **backend model** (e.g. `glm-5-2`, `qwen3-7-max`, `deepseek-v4-pro`), which routinely differs from the CLI's product name. -Use whatever the operator provides **verbatim** (after slugging). You are **forbidden** to introspect, guess, or substitute the CLI/runtime product name. Writing any identifier other than the operator-provided one — **including the name of the CLI you are running in (`qwen-code`, `gemini-cli`, `claude-code`, `copilot`, …)** — is a **defect** that silently corrupts the review step (wrong attribution, false cross-family agreement). Do not refuse a legitimate operator-specified identifier: the operator is the sole authority on which backend model they selected. +Use whatever the operator provides **verbatim** (after slugging). You are **forbidden** to introspect, guess, or substitute the CLI/runtime product name. Writing any identifier other than the operator-provided one — **including the name of the CLI you are running in (`qwen-code`, `agy`, `claude-code`, `copilot`, …)** — is a **defect** that silently corrupts the review step (wrong attribution, false cross-family agreement). Do not refuse a legitimate operator-specified identifier: the operator is the sole authority on which backend model they selected. Slug rules (applied to the provided string): @@ -101,7 +101,7 @@ The report frontmatter MUST conform to `audit-output.schema.v0.json`: ```yaml --- audit_role: auditor -auditor: # operator-provided model id — NEVER the CLI product name (qwen-code, gemini-cli, …) +auditor: # operator-provided model id — NEVER the CLI product name (qwen-code, agy, …) charter_id: git_range: "" prompt_used: audit-prompt.md @@ -119,7 +119,7 @@ audit_quality: high | medium | low # (body following the format declared in the prompt's "Formato de salida" section) ``` -**Guard — verify the identity before you finish (mandatory).** Re-open the file you just wrote and confirm that BOTH the frontmatter `auditor:` field AND the report's `# Auditoría: por ` header equal the operator-provided slug exactly. If either shows anything else — especially the CLI product name you are running in (`qwen-code`, `gemini-cli`, …) — rewrite them. The filename `report-.md`, the `auditor:` field, and the header must all carry the same operator-provided slug. +**Guard — verify the identity before you finish (mandatory).** Re-open the file you just wrote and confirm that BOTH the frontmatter `auditor:` field AND the report's `# Auditoría: por ` header equal the operator-provided slug exactly. If either shows anything else — especially the CLI product name you are running in (`qwen-code`, `agy`, …) — rewrite them. The filename `report-.md`, the `auditor:` field, and the header must all carry the same operator-provided slug. ### 6. Notify the operator — with the wait warning @@ -134,7 +134,7 @@ Audit complete for (this auditor: ). IMPORTANT: do NOT return to the main agent for /straymark-audit-review yet unless ALL audits you commissioned have completed. -If you opened other auditor CLIs (gemini-cli, copilot-cli, codex-cli, ...) +If you opened other auditor CLIs (agy, copilot-cli, codex-cli, ...) and have not yet seen their /straymark-audit-execute finish, wait for them. Invoking /straymark-audit-review with incomplete reports produces a partial consolidated analysis that you will have to discard or re-run — costing diff --git a/dist/.gemini/skills/straymark-audit-prompt/SKILL.md b/dist/.agent/skills/straymark-audit-prompt/SKILL.md similarity index 95% rename from dist/.gemini/skills/straymark-audit-prompt/SKILL.md rename to dist/.agent/skills/straymark-audit-prompt/SKILL.md index def2bbaf..1f2be981 100644 --- a/dist/.gemini/skills/straymark-audit-prompt/SKILL.md +++ b/dist/.agent/skills/straymark-audit-prompt/SKILL.md @@ -1,6 +1,6 @@ --- name: straymark-audit-prompt -description: Generate the unified audit prompt for a Charter at the canonical filesystem location. The operator then opens N auditor-side CLIs (gemini-cli, claude-cli, copilot-cli, etc.) and invokes /straymark-audit-execute in each — no copy/paste. Counterpart of /straymark-audit-review. +description: Generate the unified audit prompt for a Charter at the canonical filesystem location. The operator then opens N auditor-side CLIs (agy, claude-cli, copilot-cli, etc.) and invokes /straymark-audit-execute in each — no copy/paste. Counterpart of /straymark-audit-review. --- # StrayMark Audit Prompt Skill @@ -59,7 +59,7 @@ Audit prompt prepared for . Next steps: - 1. Open one or more auditor-side CLIs (gemini-cli, claude-cli, + 1. Open one or more auditor-side CLIs (agy, claude-cli, copilot-cli, codex-cli — whatever you have) in this repo. Each CLI session uses its own model; recommendation is at least 2 auditors of DIFFERENT model families, so cross-family blind diff --git a/dist/.gemini/skills/straymark-audit-review/SKILL.md b/dist/.agent/skills/straymark-audit-review/SKILL.md similarity index 97% rename from dist/.gemini/skills/straymark-audit-review/SKILL.md rename to dist/.agent/skills/straymark-audit-review/SKILL.md index 8d4fce80..8cffc600 100644 --- a/dist/.gemini/skills/straymark-audit-review/SKILL.md +++ b/dist/.agent/skills/straymark-audit-review/SKILL.md @@ -96,7 +96,7 @@ Mark these as "Missed by all auditors" in the remediation plan. ### 5. Build the consolidated review.md -**Calibrator identity — the operator sets it, never self-perception.** The `calibrator:` and `**Reviewer:**` fields name the **backend model** performing this consolidation. Take it from the optional 2nd argument `` or from what the operator states in chat. The CLI you run inside (Qwen Code, Claude Code, Gemini CLI, …) is a **router, not the model**: writing its product name (`qwen-code`, `gemini-cli`, …) instead of the operator-selected backend model is a defect. Fallback only if the operator provided nothing: ask before writing. **Guard:** before finishing, re-read the written `review.md` and confirm `calibrator:` and `**Reviewer:**` both equal the operator-provided slug — not the CLI product name — and fix them if not. +**Calibrator identity — the operator sets it, never self-perception.** The `calibrator:` and `**Reviewer:**` fields name the **backend model** performing this consolidation. Take it from the optional 2nd argument `` or from what the operator states in chat. The CLI you run inside (Qwen Code, Claude Code, Antigravity CLI, …) is a **router, not the model**: writing its product name (`qwen-code`, `agy`, …) instead of the operator-selected backend model is a defect. Fallback only if the operator provided nothing: ask before writing. **Guard:** before finishing, re-read the written `review.md` and confirm `calibrator:` and `**Reviewer:**` both equal the operator-provided slug — not the CLI product name — and fix them if not. Write the consolidated analysis to `.straymark/audits//review.md` with this structure (six sections, lifted from Sentinel's pre-StrayMark audit-review skill): diff --git a/dist/.gemini/skills/straymark-charter-new/SKILL.md b/dist/.agent/skills/straymark-charter-new/SKILL.md similarity index 95% rename from dist/.gemini/skills/straymark-charter-new/SKILL.md rename to dist/.agent/skills/straymark-charter-new/SKILL.md index 875b6cc7..2185bb8e 100644 --- a/dist/.gemini/skills/straymark-charter-new/SKILL.md +++ b/dist/.agent/skills/straymark-charter-new/SKILL.md @@ -108,6 +108,8 @@ StrayMark: Created CHARTER-NN-slug ## What this skill does NOT do -- **It does not flip status to `in-progress` or `closed`.** Lifecycle transitions are operator decisions. +- **It does not flip status to `in-progress` or `closed`.** Lifecycle transitions are operator decisions; pumps the operator through `straymark charter close` (or manual frontmatter edit for `in-progress`). - **It does not run drift or audit.** Use `straymark charter drift` and `/straymark-audit-prompt` / `/straymark-audit-execute` / `/straymark-audit-review` for those phases. - **It does not replace AILOGs.** Day-to-day work inside the Charter still produces AILOGs. Record where they go by the Charter's origin: an **AILOG-originated** Charter lists them in `originating_ailogs:`; a **spec-originated** Charter (with `originating_spec:`) aggregates its execution AILOGs in **`execution_ailogs:`** at close — `originating_ailogs` and `originating_spec` stay mutually exclusive (the schema enforces exactly-one), and `execution_ailogs` / `context_spec` carry the other side without tripping it. + +> **Terminal compatibility**: If the terminal does not support box-drawing characters (Unicode), use plain-text formatting with dashes and pipes instead (e.g., `+--+` instead of `╔══╗`). diff --git a/dist/.gemini/skills/straymark-followups/SKILL.md b/dist/.agent/skills/straymark-followups/SKILL.md similarity index 100% rename from dist/.gemini/skills/straymark-followups/SKILL.md rename to dist/.agent/skills/straymark-followups/SKILL.md diff --git a/dist/.gemini/skills/straymark-loom/SKILL.md b/dist/.agent/skills/straymark-loom/SKILL.md similarity index 100% rename from dist/.gemini/skills/straymark-loom/SKILL.md rename to dist/.agent/skills/straymark-loom/SKILL.md diff --git a/dist/.gemini/skills/straymark-mcard/SKILL.md b/dist/.agent/skills/straymark-mcard/SKILL.md similarity index 98% rename from dist/.gemini/skills/straymark-mcard/SKILL.md rename to dist/.agent/skills/straymark-mcard/SKILL.md index 8baef8c9..537aa4cd 100644 --- a/dist/.gemini/skills/straymark-mcard/SKILL.md +++ b/dist/.agent/skills/straymark-mcard/SKILL.md @@ -290,7 +290,7 @@ Wait for user confirmation before proceeding. 2. Replace placeholders: - `YYYY-MM-DD` -> Current date - `NNN` -> Sequence number (001, 002, etc.) - - `[agent-name]` -> your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `gemini-cli-v1.0`, `codex-cli-v1.0`, `cursor-v1.0`; do not assume Claude) + - `[agent-name]` -> your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `antigravity-v1.0`, `codex-cli-v1.0`, `cursor-v1.0`; do not assume Claude) - `[Model Name]` -> User-provided model name 3. Fill in all sections with the gathered information 4. Set `review_required: true` in the frontmatter @@ -318,3 +318,5 @@ StrayMark MCARD created: 3. **User declines confirmation**: Acknowledge and exit gracefully 4. **Third-party model with limited info**: Mark unknown sections with `[Information not publicly available]` and note in limitations 5. **No `.straymark/config.yml`**: Default to English (`en`) + +> **Terminal compatibility**: If the terminal does not support box-drawing characters (Unicode), use plain-text formatting with dashes and pipes instead (e.g., `+--+` instead of `╔══╗`). diff --git a/dist/.gemini/skills/straymark-new/SKILL.md b/dist/.agent/skills/straymark-new/SKILL.md similarity index 95% rename from dist/.gemini/skills/straymark-new/SKILL.md rename to dist/.agent/skills/straymark-new/SKILL.md index 53a52cf8..7e98d9db 100644 --- a/dist/.gemini/skills/straymark-new/SKILL.md +++ b/dist/.agent/skills/straymark-new/SKILL.md @@ -61,7 +61,7 @@ Based on the analysis, suggest a document type: | `TODO`, `FIXME`, `HACK` comments added | TDE (code-smell trigger) | | Transversal debt — heritage from prior Charter, applies to multiple modules, requires dedicated Charter, or needs human prioritization | TDE (architectural trigger — distinct from per-Charter `R`; see AGENT-RULES.md §3) | | Requirements or spec files | REQ | -| Multi-session implementation block (>1 day, >5 tasks, multi-phase) | **Charter** — redirect to `/straymark-charter-new` (Charters use `straymark charter new`, not `straymark new`) | +| Multi-session implementation block (>1 day, >5 tasks, multi-phase) | **Charter** — redirect to `/straymark-charter-new` (Charters use the `straymark charter new` CLI, not `straymark new`) | ### 4. Confirm with User @@ -123,7 +123,7 @@ Use the type→directory table in step 7 to resolve where `[TYPE]` documents liv 2. Replace placeholders: - `YYYY-MM-DD` → Current date - `NNN` → Sequence number (001, 002, etc.) - - `[agent-name-v1.0]` → your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `gemini-cli-v1.0`, `codex-cli-v1.0`, `cursor-v1.0`; do not assume Claude) + - `[agent-name-v1.0]` → your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `antigravity-v1.0`, `codex-cli-v1.0`, `cursor-v1.0`; do not assume Claude) 3. Fill in context from git analysis 4. Save to correct location: @@ -187,3 +187,5 @@ After creation, display: 2. **No changes detected**: Ask user to describe what to document 3. **User declines**: Acknowledge and exit gracefully 4. **Invalid type parameter**: Show valid types and ask again + +> **Terminal compatibility**: If the terminal does not support box-drawing characters (Unicode), use plain-text formatting with dashes and pipes instead (e.g., `+--+` instead of `╔══╗`). diff --git a/dist/.gemini/skills/straymark-sec/SKILL.md b/dist/.agent/skills/straymark-sec/SKILL.md similarity index 98% rename from dist/.gemini/skills/straymark-sec/SKILL.md rename to dist/.agent/skills/straymark-sec/SKILL.md index 3988bb64..6b05473e 100644 --- a/dist/.gemini/skills/straymark-sec/SKILL.md +++ b/dist/.agent/skills/straymark-sec/SKILL.md @@ -142,7 +142,7 @@ ID format: `SEC-YYYY-MM-DD-NNN` 2. Replace placeholders: - `YYYY-MM-DD` -> Current date - `NNN` -> Sequence number (001, 002, etc.) - - `[agent-name]` -> your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `gemini-cli-v1.0`, `codex-cli-v1.0`, `cursor-v1.0`; do not assume Claude) + - `[agent-name]` -> your runtime's canonical agent identity (see AGENT-RULES.md §1 — e.g. `claude-code-v1.0`, `antigravity-v1.0`, `codex-cli-v1.0`, `cursor-v1.0`; do not assume Claude) - `[System/Component]` -> The component name from step 1 - `threat_model_methodology: STRIDE` -> The methodology chosen in step 2 - `owasp_asvs_level: 1` -> The ASVS level chosen in step 3 diff --git a/dist/.gemini/skills/straymark-status/SKILL.md b/dist/.agent/skills/straymark-status/SKILL.md similarity index 89% rename from dist/.gemini/skills/straymark-status/SKILL.md rename to dist/.agent/skills/straymark-status/SKILL.md index 922b2d24..e3a14b8d 100644 --- a/dist/.gemini/skills/straymark-status/SKILL.md +++ b/dist/.agent/skills/straymark-status/SKILL.md @@ -49,7 +49,7 @@ Also enumerate **Charters** (bounded units of work — distinct from doc types; straymark charter list 2>/dev/null ``` -If the project has no Charters yet but the work clearly fits the trigger (multi-session implementation block, >5 tasks across phases, audit value), surface that as a gap and recommend `/straymark-charter-new`. +If the project has no Charters yet but the work clearly fits the trigger (multi-session implementation block, >5 tasks across phases, audit value), surface that as a gap in the Display Results step and recommend `/straymark-charter-new`. ### 2. Find Modified Source Files @@ -97,25 +97,25 @@ StrayMark Status ================================================================================ Recent Documents (last hour): - ✅ AILOG-2025-01-27-001-implement-auth.md - ✅ AIDEC-2025-01-27-001-auth-strategy.md + [checkmark] AILOG-2025-01-27-001-implement-auth.md + [checkmark] AIDEC-2025-01-27-001-auth-strategy.md Modified Files Without Documentation: - ⚠️ src/auth/login.ts (cognitive: 12, threshold: 8) - ⚠️ src/api/users.ts (cognitive: 9, threshold: 8) + [warning] src/auth/login.ts (cognitive: 12, threshold: 8) + [warning] src/api/users.ts (cognitive: 9, threshold: 8) Summary: Documents created: 2 Files needing review: 2 -Use /straymark-new to create documentation for undocumented changes. +Use /straymark-status after making changes to verify documentation compliance. ``` ### Symbol Legend -- ✅ = Documentation exists -- ⚠️ = May need documentation -- ℹ️ = Informational +- `[checkmark]` = Documentation exists (use checkmark symbol) +- `[warning]` = May need documentation (use warning symbol) +- `[info]` = Informational (use info symbol) ### Edge Cases diff --git a/dist/.agent/workflows/straymark-adr.md b/dist/.agent/workflows/straymark-adr.md deleted file mode 100644 index adb32ace..00000000 --- a/dist/.agent/workflows/straymark-adr.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -description: Create an ADR (Architecture Decision Record) for significant architectural decisions. Requires human review. ---- - -# StrayMark ADR Skill - -Create an Architecture Decision Record (ADR) for significant architectural decisions. - -> **Note**: ADRs created by AI agents are marked as `draft` and `review_required: true` by default. - -## Instructions - -Use this skill for major architectural decisions that affect the system structure, technology stack, or design patterns. - -### 1. Gather Context - -```bash -# Get current date -date +%Y-%m-%d - -# Summarize the CURRENT work (staged + unstaged + untracked) — label each block. -# Avoid `HEAD~1`: it describes the previous commit, not the work being decided on. -git diff --cached --stat # staged changes -git diff --stat # unstaged changes -git status --porcelain # includes untracked files - -# Check for related ADRs -ls .straymark/02-design/decisions/ADR-*.md 2>/dev/null | tail -5 -``` - -### 2. Confirm with User - -**Always confirm before creating:** - -``` -╔══════════════════════════════════════════════════════════════════╗ -║ StrayMark ADR ║ -╠══════════════════════════════════════════════════════════════════╣ -║ ║ -║ ⚠️ ADRs require human review after creation. ║ -║ ║ -║ 📋 An ADR documents architectural decisions that affect: ║ -║ • System structure ║ -║ • Technology choices ║ -║ • Design patterns ║ -║ • Integration approaches ║ -║ ║ -║ Please provide: ║ -║ 1. Decision title (what architectural decision) ║ -║ 2. Context (why is this decision needed) ║ -║ 3. The decision and alternatives considered ║ -║ ║ -╚══════════════════════════════════════════════════════════════════╝ -``` - -### 3. Determine Sequence Number - -```bash -# Count existing ADRs for today -ls .straymark/02-design/decisions/ADR-$(date +%Y-%m-%d)-*.md 2>/dev/null | wc -l -``` - -### 4. Check Language and Load Template - -Read `.straymark/config.yml` for language setting: -- `en` (default): `.straymark/templates/TEMPLATE-ADR.md` -- `es`: `.straymark/templates/i18n/es/TEMPLATE-ADR.md` - -### 5. Create Document - -Fill template with: -- `id`: ADR-YYYY-MM-DD-NNN -- `title`: Architectural decision title -- `status`: **draft** (always for AI-created ADRs) -- `created`: Current date -- `updated`: Current date -- `agent`: your agent identifier (e.g., `cursor-v1.0`, `copilot-v1.0`, `windsurf-v1.0`) — see AGENT-RULES.md §1 for the canonical list; do not assume Claude -- `confidence`: based on research done -- `review_required`: **true** (always for ADRs) -- `risk_level`: minimum `medium` for architectural decisions - -**Key sections to fill:** -- Status: Note that this was created by AI agent -- Context: Technical and business context, forces at play -- Decision: The architectural decision with justification -- Alternatives Considered: Other options with pros/cons/why not -- Consequences: Positive, negative, neutral -- Affected Components: Table of impacted parts -- Implementation Plan: High-level steps -- Success Metrics: How to validate the decision - -Save to: `.straymark/02-design/decisions/ADR-YYYY-MM-DD-NNN-description.md` - -### 6. Report Result - -``` -⚠️ ADR created (requires human review): - .straymark/02-design/decisions/ADR-YYYY-MM-DD-NNN-description.md - - Status: draft - Review Required: YES - -StrayMark: Created ADR-YYYY-MM-DD-NNN-description.md (review required) -``` - -## Examples of Architectural Decisions - -- Use PostgreSQL over MongoDB for persistence -- Adopt microservices vs. monolith architecture -- Choose REST vs. GraphQL for API -- Select authentication strategy (JWT, OAuth, etc.) -- Define module boundaries and dependencies -- Establish caching strategy diff --git a/dist/.agent/workflows/straymark-aidec.md b/dist/.agent/workflows/straymark-aidec.md deleted file mode 100644 index 77d96021..00000000 --- a/dist/.agent/workflows/straymark-aidec.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -description: Create an AIDEC (AI Decision) document to record a technical decision with alternatives considered. ---- - -# StrayMark AIDEC Skill - -Create an AI Decision (AIDEC) document to record technical decisions and the alternatives considered. - -## Instructions - -Use this skill when you've made a decision between multiple technical approaches and want to document the reasoning. - -### 1. Gather Context - -```bash -# Get current date -date +%Y-%m-%d - -# Summarize the CURRENT work (staged + unstaged + untracked) — label each block. -# Avoid `HEAD~1`: it describes the previous commit, not the work being decided on. -git diff --cached --stat # staged changes -git diff --stat # unstaged changes -git status --porcelain # includes untracked files -``` - -### 2. Confirm with User - -**Always confirm before creating:** - -``` -╔══════════════════════════════════════════════════════════════════╗ -║ StrayMark AIDEC ║ -╠══════════════════════════════════════════════════════════════════╣ -║ ║ -║ 📋 AIDEC documents a decision between alternatives. ║ -║ ║ -║ Please provide: ║ -║ 1. Decision title (what was decided) ║ -║ 2. Alternatives considered (2-3 options) ║ -║ 3. Which alternative was chosen and why ║ -║ ║ -╚══════════════════════════════════════════════════════════════════╝ -``` - -### 3. Determine Sequence Number - -```bash -# Count existing AIDECs for today -ls .straymark/07-ai-audit/decisions/AIDEC-$(date +%Y-%m-%d)-*.md 2>/dev/null | wc -l -``` - -### 4. Check Language and Load Template - -Read `.straymark/config.yml` for language setting: -- `en` (default): `.straymark/templates/TEMPLATE-AIDEC.md` -- `es`: `.straymark/templates/i18n/es/TEMPLATE-AIDEC.md` - -### 5. Create Document - -Fill template with: -- `id`: AIDEC-YYYY-MM-DD-NNN -- `title`: Decision title from user -- `created`: Current date -- `agent`: your agent identifier (e.g., `cursor-v1.0`, `copilot-v1.0`, `windsurf-v1.0`) — see AGENT-RULES.md §1 for the canonical list; do not assume Claude -- `confidence`: based on decision clarity -- `risk_level`: based on decision impact - -**Key sections to fill:** -- Context: Why was a decision needed? -- Problem: What specific problem needed solving? -- Alternatives Considered: At least 2 options with pros/cons -- Decision: Which was chosen and justification -- Consequences: Positive, negative, and risks - -Save to: `.straymark/07-ai-audit/decisions/AIDEC-YYYY-MM-DD-NNN-description.md` - -### 6. Report Result - -``` -✅ AIDEC created: - .straymark/07-ai-audit/decisions/AIDEC-YYYY-MM-DD-NNN-description.md - -StrayMark: Created AIDEC-YYYY-MM-DD-NNN-description.md -``` - -## When to Create an AIDEC - -- Chose between frameworks/libraries -- Selected an algorithm or approach -- Decided on a data structure -- Made a performance vs. readability trade-off -- Selected between design patterns diff --git a/dist/.agent/workflows/straymark-ailog.md b/dist/.agent/workflows/straymark-ailog.md deleted file mode 100644 index 98dadbf6..00000000 --- a/dist/.agent/workflows/straymark-ailog.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -description: Create an AILOG (AI Action Log) document for the current changes. Quick shortcut for the most common document type. ---- - -# StrayMark AILOG Skill - -Quickly create an AI Action Log (AILOG) document for the current changes. - -## Instructions - -This is a shortcut skill that creates AILOG documents directly. - -### 1. Gather Context - -```bash -# Get current date -date +%Y-%m-%d - -# Get modified files -git status --porcelain - -# Summarize the CURRENT work (staged + unstaged + untracked) — label each block. -# Avoid `HEAD~1`: it summarizes the previous commit, not the work being logged. -git diff --cached --stat # staged changes -git diff --stat # unstaged changes -git status --porcelain # includes untracked files -``` - -### 2. Confirm with User - -**Always confirm before creating:** - -``` -╔══════════════════════════════════════════════════════════════════╗ -║ StrayMark AILOG ║ -╠══════════════════════════════════════════════════════════════════╣ -║ ║ -║ 📊 Changes detected: ║ -║ • Files: [list of modified files] ║ -║ • Lines: [+X / -Y] ║ -║ ║ -║ 📝 Will create: ║ -║ AILOG-YYYY-MM-DD-NNN-[description].md ║ -║ ║ -║ Please provide a brief description of what was done: ║ -╚══════════════════════════════════════════════════════════════════╝ -``` - -### 3. Determine Sequence Number - -```bash -# Count existing AILOGs for today -ls .straymark/07-ai-audit/agent-logs/AILOG-$(date +%Y-%m-%d)-*.md 2>/dev/null | wc -l -``` - -Next number = count + 1, formatted as 3 digits (001, 002, etc.) - -### 4. Check Language and Load Template - -Read `.straymark/config.yml` for language setting: -- `en` (default): `.straymark/templates/TEMPLATE-AILOG.md` -- `es`: `.straymark/templates/i18n/es/TEMPLATE-AILOG.md` - -### 5. Create Document - -Fill template with: -- `id`: AILOG-YYYY-MM-DD-NNN -- `title`: User-provided description -- `created`: Current date -- `agent`: your agent identifier (e.g., `cursor-v1.0`, `copilot-v1.0`, `windsurf-v1.0`) — see AGENT-RULES.md §1 for the canonical list; do not assume Claude -- `confidence`: based on change complexity -- `risk_level`: based on files modified - -Save to: `.straymark/07-ai-audit/agent-logs/AILOG-YYYY-MM-DD-NNN-description.md` - -### 6. Report Result - -``` -✅ AILOG created: - .straymark/07-ai-audit/agent-logs/AILOG-YYYY-MM-DD-NNN-description.md - -StrayMark: Created AILOG-YYYY-MM-DD-NNN-description.md -``` - -## Risk Level Guidelines - -| Indicator | Risk Level | -|-----------|------------| -| Config/settings changes | low | -| Business logic changes | medium | -| Auth, security, payments | high | -| Database schema, migrations | critical | diff --git a/dist/.agent/workflows/straymark-architecture-sync.md b/dist/.agent/workflows/straymark-architecture-sync.md deleted file mode 100644 index 97eb6b45..00000000 --- a/dist/.agent/workflows/straymark-architecture-sync.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -description: Keep the architecture model alive as code grows — wrap `straymark architecture sync` (append-only) to detect new source dirs / ADR components, surface them, reconcile against human edits, apply, and re-validate. Never re-refines from scratch. EXPERIMENTAL (Loom A1.3). ---- - -# StrayMark Architecture Sync Skill - -Keep an already-refined architecture model current as the codebase grows. `straymark architecture sync` is **append-only**: it detects new top-level source directories and ADR components not yet in the model and appends them — it **never** clobbers your edits or your DrawIO geometry. This skill runs it as a guided dry-run → confirm → apply → re-validate loop. - -> ⚠️ **EXPERIMENTAL.** The `architecture` model and Loom are an opt-in Loom A1.x experiment — not part of the supported Framework/CLI contract. The model lives at `.straymark/architecture/{model.yml,plan.drawio}`. See `docs/adopters/LOOM.md`. - -## When to use this skill - -Trigger on any of: - -- A new module / source directory was added and the architecture model should reflect it. -- A new ADR introduced components not yet in the model. -- The operator asks to "update" or "refresh" the architecture model without re-refining it. - -If `.straymark/architecture/model.yml` does **not** exist yet, or is still a raw seed (every component in `unassigned`), use `/straymark-architecture` instead — sync extends a curated model, it does not create or refine one. - -## Instructions - -### 1. Dry-run — see what's new - -```bash -straymark architecture sync # dry-run (default): lists components that would be added -``` - -Surface the proposed additions to the operator verbatim — each new component shows its id, globs, and any inferred links: - -``` -2 new components would be added (dry-run — pass --apply to write): - + internal-modules-billing (globs: internal/modules/billing/**) → links: core - + internal-modules-reports (globs: internal/modules/reports/**) -``` - -If it reports nothing new, stop and report **`Model is up to date — nothing to append.`** - -### 2. Reconcile against human edits - -Before applying, check the proposed additions against the curated model: - -- New components land in the placeholder `unassigned` layer — note that they will need reassigning to a real layer afterward (refine them the same way `/straymark-architecture` does). -- Confirm the new ids don't collide with an existing `layer.id` (a `component.id` must never equal a `layer.id`). -- **Confirm with the operator before writing** — sync is append-only but it still mutates `model.yml`. - -### 3. Apply - -```bash -straymark architecture sync --apply # appends the new components to model.yml (+ plan.drawio cells if it exists) -``` - -It appends with a `# Added by 'straymark architecture sync'` marker and, when `plan.drawio` is a recognized DrawIO document, appends matching cells. Existing geometry and edits are untouched. - -### 4. Re-validate - -```bash -straymark architecture validate # exits 1 on any signal -``` - -Resolve any new `undrawn` / `unmodeled` / `empty` signals, then remind the operator to **refine the appended components** — reassign them out of `unassigned` into real layers and wire their `links` (that's a `/straymark-architecture` refinement on just the new entries). - -## Report result - -Surface the CLI output verbatim and name the follow-up. Example: - -``` -✓ Appended 2 components to model.yml (billing, reports) — now in `unassigned`. - Next: reassign them to real layers + add links via /straymark-architecture, then /straymark-loom to view. -``` - -## What this skill does NOT do - -- **It does not re-refine the model.** It only appends what's new; the existing curated layers, labels, links, and geometry are left exactly as they are. -- **It does not assign new components to real layers.** Appended components land in `unassigned`; refining them is a `/straymark-architecture` step. -- **It does not run when no curated model exists.** Use `/straymark-architecture` to generate and refine the first model. - -> **Terminal compatibility**: If the terminal does not support box-drawing characters (Unicode), use plain-text formatting with dashes and pipes instead. diff --git a/dist/.agent/workflows/straymark-architecture.md b/dist/.agent/workflows/straymark-architecture.md deleted file mode 100644 index 186110c3..00000000 --- a/dist/.agent/workflows/straymark-architecture.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -description: Generate the architecture model and refine it in one guided pass — seed with `straymark architecture generate`, then reassign components into real layers, wire dependency links, sync the DrawIO, and validate to green. The agent-native counterpart to the manual DrawIO refinement. EXPERIMENTAL (Loom A1.x). ---- - -# StrayMark Architecture Skill - -Drive the `generate → refine → validate` arc of the StrayMark architecture model from the agent window. `straymark architecture generate` mines *structure* (top-level source dirs → components); the model encodes *intent* (real layers, dependency links, human labels) that the filesystem does not contain. This skill performs the refinement a human would otherwise do in DrawIO, using the agent's knowledge of the repo, and iterates `validate` to green in a single pass. - -> ⚠️ **EXPERIMENTAL.** The `architecture` model, its on-disk format, and Loom are an opt-in Loom A1.x experiment — not part of the supported Framework/CLI contract. See `docs/adopters/LOOM.md`. The model lives at `.straymark/architecture/{model.yml,plan.drawio}`. - -## When to use this skill - -Trigger on any of: - -- The operator asks to "map the architecture", "set up the architecture model", or "refine the architecture seed". -- A `model.yml` was just generated and every component still sits in the placeholder `unassigned` layer. -- The operator wants the 2D/3D Loom views to show real layers and dependency arrows. - -If `.straymark/architecture/model.yml` already exists **and is already refined** (components assigned to real layers, links present), prefer `/straymark-architecture-sync` to extend it append-only instead of re-refining from scratch. - -## Instructions - -### 1. Generate the seed - -```bash -straymark architecture generate # writes model.yml + plan.drawio -straymark architecture generate --force # only if a seed already exists and the operator wants a fresh one -``` - -`generate` enriches from ADRs (C4 diagrams + "Affected Components" tables) **only if they exist**; with none, the seed is structure-only. It seeds every component into a placeholder `unassigned` layer and the `.straymark` stages 00–09 as placeholder layers. **The seed is a draft, not the answer** — the next step is where it becomes meaningful. - -### 2. Refine the model (the phase that matters) - -Read `model.yml` and the codebase, then edit `model.yml` to encode real intent: - -- **Replace the placeholder doc-stage layers with real architecture layers**, inferred from directory conventions and ADRs (e.g. `entrypoints`, `domain`, `persistence`, `web`). **Ask the operator when the layering is ambiguous** — do not guess at the system's intended shape. -- **Reassign every component out of `unassigned`** into a real layer. -- **Fix labels** to human names (`internal-modules-commshub` → "CommsHub"). -- **Tighten globs** so each component owns exactly its files. -- **Infer `links`** between components from the import graph / directory structure / ADR "Affected Components" tables. - -The model schema (`.straymark/architecture/model.yml`): - -```yaml -version: 0 -layers: - - { id: "domain", label: "Domain", order: 0 } # id is the join key from component.layer; order is render order (low first) -components: - - id: "commshub" # stable join key to the DrawIO cell + status overlay - label: "CommsHub" # human label - layer: "domain" # MUST name an existing layer id - globs: ["internal/modules/commshub/**"] # the join to governance state - links: ["audittrail"] # list of target component ids (strings) - docs: [] # optional explicit doc ids; normally inferred via globs - external: false # true only for third-party / external systems -``` - -**Gotchas — each one costs a debugging cycle; pre-empt them:** - -- **A `component.id` must not equal any `layer.id`.** For a single-component layer use a suffixed id (`core` layer → `core-infra` component). fw-4.27.0 emits a clear error for this, but write the model so it never trips. -- **`links` is a list of target component ids (strings)** — `["audittrail", "core"]`, **not** objects like `[{to: …}]` (which fails to parse). -- **Never delete a layer that a component still points at** via `component.layer` — that yields `references unknown layer`. Reassign the components first, then drop the empty placeholder layer. -- The placeholder `unassigned` layer is not required by the schema once empty — but every `component.layer` must still name a layer that exists. - -### 3. Sync the DrawIO so 2D shows arrows - -**3D renders edges from `model.yml` `links`; 2D renders them from `plan.drawio` edges.** Write **both**, or arrows show in only one view. After editing `model.yml`, update `plan.drawio` so each component has a vertex and each `link` has an edge between the matching vertices (the DrawIO cell id joins on the component `id`). Keep human-authored geometry where it exists. - -### 4. Validate — iterate to green - -```bash -straymark architecture validate # text; exits 1 on any signal -straymark architecture validate --output json -``` - -Resolve every signal, then re-run until it exits 0: - -- **`undrawn`** — a component with no cell in `plan.drawio` → add the vertex. -- **`unmodeled`** — a DrawIO cell with no component in `model.yml` → add the component or remove the stale cell. -- **`empty`** — a component whose globs match no files on disk → fix the globs. - -### 5. Report result - -Summarize what changed (layers created, components reassigned, links added) and surface the final `validate` output verbatim. Point the operator at the live views: - -``` -✓ Architecture model refined: 4 layers, 13 components, 10 links — validate is green. - Next: `/straymark-loom` up to see the 2D/3D overlay, or `straymark status --where` for the terminal view. -``` - -## What this skill does NOT do - -- **It does not invent the intended architecture.** When layering or boundaries are ambiguous, it asks the operator — the model encodes human intent, not a filesystem heuristic. -- **It does not maintain the status overlay.** `active` / `in-progress` / `implemented` / `has-debt` / `uncharted` are computed live from governance signals every time you look; this skill authors *structure* only. -- **It does not re-refine an already-curated model.** Use `/straymark-architecture-sync` (append-only) once real layers and links exist. - -> **Terminal compatibility**: If the terminal does not support box-drawing characters (Unicode), use plain-text formatting with dashes and pipes instead. diff --git a/dist/.agent/workflows/straymark-audit-execute.md b/dist/.agent/workflows/straymark-audit-execute.md deleted file mode 100644 index 8e69a810..00000000 --- a/dist/.agent/workflows/straymark-audit-execute.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -description: Execute an external audit of a Charter inside an auditor-side CLI (gemini-cli, claude-cli, copilot-cli, codex-cli). Reads the resolved audit prompt from the canonical location, audits with tool use, writes the report. Operator invokes one instance per CLI. ---- - -# StrayMark Audit Execute Skill - -Execute an external audit of a Charter inside this CLI session. Read the resolved audit prompt that StrayMark prepared at the canonical location, audit the implementation with tool use (citing `path:line` of files actually opened), and write the report at the canonical location for the audit-review skill to consolidate later. - -## When to invoke - -This skill runs **inside an auditor-side CLI** (gemini-cli, claude-cli, copilot-cli, codex-cli, or any agent runtime configured with read-only access to the adopter's repo). The operator opens the CLI in the repo, then invokes `/straymark-audit-execute `. - -The skill is the second step of the v1 audit cycle: - -1. In the main IDE: operator runs `/straymark-audit-prompt CHARTER-NN` → StrayMark writes `.straymark/audits/CHARTER-NN/audit-prompt.md`. -2. **(this skill)** Operator opens an auditor-side CLI in the repo and runs `/straymark-audit-execute CHARTER-NN`. Repeat in N CLIs (recommended: ≥2 of different model families). -3. When ALL audits commissioned have completed, operator returns to the main IDE and runs `/straymark-audit-review CHARTER-NN`. - -## Instructions - -### 1. Resolve the Charter - -Two positional arguments: `` and an optional `` — e.g. `/straymark-audit-execute CHARTER-06 deepseek-v4-pro`. The second argument is the operator-provided auditor identity (see step 2); it is never inferred from the CLI you are running in. - -**Case A — Charter provided** (`/straymark-audit-execute CHARTER-04 [AUDITOR-SLUG]`): -Use the literal Charter value. Construct the audit dir path: `.straymark/audits/CHARTER-04/` — or, when the operator passed `--round