From 1bc142710d557fd1e7321a081dcada60043ff72e Mon Sep 17 00:00:00 2001 From: Lovro Lucic <11740211+lluvr@users.noreply.github.com> Date: Thu, 16 Jul 2026 16:27:54 +0200 Subject: [PATCH] Make cma production-ready, relocate to a personal account, upgrade MCP Trim the repository root to 10 files: move the deep-dive docs (DESIGN, ARCHITECTURE, DATA, DECISIONS, GOVERNANCE) under docs/ and the test and bench harnesses under scripts/, then update every internal reference, workflow path, generated-README URL, and doc link so nothing breaks. Remove committed build artifacts. Present cma as a self-contained, methodology-agnostic tool. Neutralize references to the private Lodestone repository that resolved to 404 for adopters, keeping the public sibling links (Touchstone, frame-check) and the blog. Move self-references to lluvr/cma and drop the organization publisher and author framing; the citation shipped in every MCP payload now reads "(L. Lucic, 2026)". Remove the Zenodo DOI references from both CITATION.cff files and soften the publisher-identity claim in SECURITY.md pending re-issuance under the new account. Upgrade the MCP server to the current protocol. The initialize handshake negotiates the protocol version (echo a supported revision, otherwise the newest: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05) rather than hard-coding 2024-11-05, and per-call provenance reports the revision negotiated for the session. Every tool declares a three-section outputSchema and tool calls return structuredContent, so clients on 2025-06-18 or newer consume and validate structured output while the text block stays for older clients. Rewrite the server instructions to stand alone. Harden and tidy. Exempt the canon detector and its self-test fixtures from gitleaks (they carried the forbidden patterns by construction), add .ruff_cache and .claude/settings.local.json to .gitignore, pin PEP 740 attestations in the publish workflow so the SECURITY.md provenance promise cannot regress, correct stale versions and counts and a false wheel-bundling claim, and normalize punctuation to plain ASCII across committed content. Verified: 143 bash tests, 57 MCP tests, canon audit, ruff, all workflow YAML, a wheel build, and a jsonschema validation of structuredContent against the advertised outputSchema. Signed-off-by: Lovro Lucic <11740211+lluvr@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/ISSUE_TEMPLATE/config.yml | 5 +- .github/ISSUE_TEMPLATE/feature_request.md | 9 ++-- .github/PULL_REQUEST_TEMPLATE.md | 22 ++++----- .github/workflows/publish-mcp.yml | 14 ++++-- .github/workflows/test.yml | 6 +-- .github/workflows/tests-mcp.yml | 2 +- .gitignore | 4 ++ .gitleaks.toml | 16 ++++++ AGENTS.md | 18 +++---- CHANGELOG.md | 18 ++++--- CITATION.cff | 40 +++------------ CONTRIBUTING.md | 32 ++++++------ NOTICE | 18 +++---- README.md | 49 ++++++++++--------- SECURITY.md | 12 ++--- cma | 22 ++++----- cma-mcp/CHANGELOG.md | 8 ++- cma-mcp/CITATION.cff | 8 --- cma-mcp/NOTICE | 16 +++--- cma-mcp/README.md | 15 ++++-- cma-mcp/cma_jsonl.py | 2 +- cma-mcp/cma_subprocess.py | 2 +- cma-mcp/docs/ARCHITECTURE.md | 41 +++++++++------- cma-mcp/docs/FAQ.md | 33 ++++++------- cma-mcp/docs/MCP_SERVER.md | 38 ++++++++++----- cma-mcp/docs/TROUBLESHOOTING.md | 14 +++--- cma-mcp/mcp_compose.py | 30 ++++++++---- cma-mcp/mcp_schema.py | 59 +++++++++++++++++++++-- cma-mcp/mcp_server.py | 53 +++++++++++++++++--- cma-mcp/pyproject.toml | 1 - cma-mcp/setup.py | 2 +- cma-mcp/tests/test_mcp_server.py | 54 ++++++++++++++++++++- cma-mcp/tests/test_mcp_wire.py | 11 ++++- cma-mcp/tests/test_payload_determinism.py | 2 +- ARCHITECTURE.md => docs/ARCHITECTURE.md | 11 ++--- DATA.md => docs/DATA.md | 2 +- DECISIONS.md => docs/DECISIONS.md | 19 ++++---- DESIGN.md => docs/DESIGN.md | 40 +++++++-------- GOVERNANCE.md => docs/GOVERNANCE.md | 7 ++- hooks/claude-code-session-start.sh | 8 +-- hooks/cma-pre | 8 +-- bench.sh => scripts/bench.sh | 12 ++--- test.sh => scripts/test.sh | 10 ++-- 44 files changed, 487 insertions(+), 308 deletions(-) rename ARCHITECTURE.md => docs/ARCHITECTURE.md (95%) rename DATA.md => docs/DATA.md (99%) rename DECISIONS.md => docs/DECISIONS.md (91%) rename DESIGN.md => docs/DESIGN.md (68%) rename GOVERNANCE.md => docs/GOVERNANCE.md (95%) rename bench.sh => scripts/bench.sh (92%) rename test.sh => scripts/test.sh (99%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 771a62f..6002175 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -13,7 +13,7 @@ labels: bug ## Expected behavior - + ## Actual behavior diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 30b2fcc..0e43a7c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,5 @@ blank_issues_enabled: false contact_links: - name: Security issue - url: https://github.com/Clarethium/cma/security/advisories/new + url: https://github.com/lluvr/cma/security/advisories/new about: Report security issues via GitHub private vulnerability reporting per SECURITY.md. Do NOT open public issues for vulnerabilities. - - name: Lodestone methodology question - url: https://github.com/Clarethium/lodestone/issues - about: Methodology canon questions (FM catalog, surface protocols, compound practice) live with Lodestone. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 949150c..fa90833 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -23,7 +23,7 @@ labels: enhancement -## Companion impact +## Related-project impact diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2310599..c607430 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,12 +1,12 @@ @@ -28,31 +28,31 @@ before opening a substantial change. Especially: - [ ] Surface-breaking change (major version bump) - [ ] Documentation only - [ ] Test addition / refactor -- [ ] Architectural decision (DECISIONS.md entry added) +- [ ] Architectural decision (docs/DECISIONS.md entry added) ## Reviewer checklist - [ ] DCO sign-off on every commit (`git log` shows `Signed-off-by:` trailer) - [ ] Relevant test suite passes locally -- [ ] If bash cma surface changed: `cma`, `test.sh`, `DESIGN.md`, and `ARCHITECTURE.md` (if action-time injection touched) updated together +- [ ] If bash cma surface changed: `cma`, `scripts/test.sh`, `docs/DESIGN.md`, and `docs/ARCHITECTURE.md` (if action-time injection touched) updated together - [ ] If cma-mcp surface changed: `mcp_schema.py`, `mcp_server.py`, the relevant test, and `cma-mcp/docs/MCP_SERVER.md` updated together - [ ] If payload shape changed: `cma-mcp/tests/test_payload_determinism.py` updated - [ ] If runtime behavior changed: the relevant CHANGELOG `[Unreleased]` updated - [ ] No new runtime dependency added (bash cma: bash + python3 stdlib only; cma-mcp: Python stdlib only) - [ ] `bash scripts/canon_audit.sh` passes locally -## Companion-link impact +## Related-project impact ## DECISIONS diff --git a/.github/workflows/publish-mcp.yml b/.github/workflows/publish-mcp.yml index 0e551ac..a06cde0 100644 --- a/.github/workflows/publish-mcp.yml +++ b/.github/workflows/publish-mcp.yml @@ -17,10 +17,11 @@ # 3. Push tag `cma-mcp-X.Y.Z`. # 4. Approve the deployment in the GitHub Actions UI when the # reviewer-required gate fires on the `pypi` environment. -# 5. Create a GitHub Release at the tag so the GitHub-Zenodo -# integration mints a versioned DOI. -# 6. Update `cma-mcp/CITATION.cff` with the issued DOI under -# `identifiers:` and bump `doi:` to the versioned DOI. +# 5. If the GitHub-Zenodo integration is enabled for this +# repository, create a GitHub Release at the tag so it mints a +# versioned DOI. +# 6. When a DOI is issued, record it in `cma-mcp/CITATION.cff` +# under `identifiers:` (and set a top-level `doi:` to it). # # A TestPyPI upload step is available as a commented job below # (`publish-to-testpypi`); swap the comment blocks and add @@ -196,3 +197,8 @@ jobs: name: cma-mcp-dist path: dist/ - uses: pypa/gh-action-pypi-publish@release/v1 + with: + # PEP 740 attestations back the provenance-verification path + # documented in SECURITY.md. Set explicitly rather than relying + # on the action default so the guarantee cannot silently regress. + attestations: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c5a3e3c..8933e58 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: run: python3 --version - name: Run test suite - run: ./test.sh + run: ./scripts/test.sh lint: runs-on: ubuntu-latest @@ -41,8 +41,8 @@ jobs: - name: Lint cma and hooks run: | shellcheck cma - shellcheck test.sh - shellcheck bench.sh + shellcheck scripts/test.sh + shellcheck scripts/bench.sh shellcheck hooks/cma-pre shellcheck hooks/claude-code-pre-tool-use.sh shellcheck hooks/claude-code-session-start.sh diff --git a/.github/workflows/tests-mcp.yml b/.github/workflows/tests-mcp.yml index 5166c88..6e92421 100644 --- a/.github/workflows/tests-mcp.yml +++ b/.github/workflows/tests-mcp.yml @@ -63,7 +63,7 @@ jobs: - name: Run pytest with coverage # Coverage measurement scopes the eight runtime modules per # [tool.coverage.run] in pyproject.toml. The reported number - # reflects in-process dispatch only — `tests/test_mcp_wire.py` + # reflects in-process dispatch only: `tests/test_mcp_wire.py` # spawns cma-mcp as a real subprocess (closes ANTICIPATED_ # CRITIQUES C-8), and pytest-cov does not follow subprocess # paths without a sitecustomize hook. Lines exercised only diff --git a/.gitignore b/.gitignore index f3ce38e..ee76bb7 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,10 @@ coverage.xml *.swo *~ +# linters / agent-local config (per-developer, never committed) +.ruff_cache/ +.claude/settings.local.json + # os .DS_Store Thumbs.db diff --git a/.gitleaks.toml b/.gitleaks.toml index c5be2ee..2d6fb6d 100644 --- a/.gitleaks.toml +++ b/.gitleaks.toml @@ -12,6 +12,22 @@ title = "cma gitleaks configuration" # these, do not replace. useDefault = true +# The canon-discipline detector and its self-test fixtures are the +# files explicitly allowed to name the forbidden patterns (in order to +# detect or self-verify them). They therefore trip the custom rules +# below by construction: `canon_audit.sh` matches the *AUDIT* filename +# shape, and `canon_audit_known_leaks.txt` deliberately carries +# leak-shaped strings (including a /home/ path) to exercise the +# detector. Exempt them from all rules, consistent with the public-canon +# discipline's own path allowlist. +[allowlist] +description = "Canon-discipline detector and self-test fixtures may name forbidden patterns" +paths = [ + '''scripts/canon_audit\.sh''', + '''scripts/canon_audit_known_leaks\.txt''', + '''scripts/canon_audit_pystring_concat_known_leaks\.py''', +] + # Refuse commits matching common agent-handoff scratchpad filename # patterns. These files are scratch space and should never enter # version control regardless of content. diff --git a/AGENTS.md b/AGENTS.md index f505ed9..15aed8a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ or `.cursorrules` is. Read it before making changes. ## What this repo is -`Clarethium/cma` is the public canonical repository for **cma** +`lluvr/cma` is the public canonical repository for **cma** (executable compound practice loop) plus its MCP wrapper at `cma-mcp/`. The bash CLI at the repo root is the load-bearing implementation; the Python MCP wrapper at `cma-mcp/` is a thin @@ -16,7 +16,7 @@ distribution surface. They ship together because every cma flag is a cma-mcp tool argument and every JSONL field in `surface_events.jsonl` is a cma-mcp parser concern; same-repo prevents drift structurally. -The decision is codified in `DECISIONS.md` AD-008. If you are +The decision is codified in `docs/DECISIONS.md` AD-008. If you are proposing structural changes, read AD-008 first. ## What goes in this repo @@ -24,10 +24,10 @@ proposing structural changes, read AD-008 first. This repository ships only what an adopter needs to install, run, extend, and audit CMA. The scope is fixed: -- The bash CLI and its `test.sh` suite. +- The bash CLI and its `scripts/test.sh` suite. - The `cma-mcp/` Python wrapper, its tests, and the wheel metadata. -- `README.md`, `CONTRIBUTING.md`, `GOVERNANCE.md`, `SECURITY.md`, - `CHANGELOG.md`, `LICENSE`, `CITATION.cff`, `DECISIONS.md`. +- `README.md`, `CONTRIBUTING.md`, `docs/GOVERNANCE.md`, `SECURITY.md`, + `CHANGELOG.md`, `LICENSE`, `CITATION.cff`, `docs/DECISIONS.md`. - `AGENTS.md` (this file) at the root. Anything outside that scope does not enter the repository. The @@ -93,7 +93,7 @@ with a placeholder marker; the marker itself is a leak. - DCO sign-off required (`git commit -s ...`). The `dco-check` workflow blocks merges of unsigned commits. -- Bash CLI tests run via `./test.sh` at the repo root. MCP wrapper +- Bash CLI tests run via `./scripts/test.sh` at the repo root. MCP wrapper tests live under `cma-mcp/tests/` and run via `pytest cma-mcp/tests/`. Both must pass before merging. - Style: no em-dashes, en-dashes, smart quotes, or curly apostrophes @@ -108,7 +108,7 @@ with a placeholder marker; the marker itself is a leak. ## Pointers for further reading - `README.md`: what CMA is and how to use it. -- `DECISIONS.md`: durable architectural decisions (AD-001 through +- `docs/DECISIONS.md`: durable architectural decisions (AD-001 through AD-008). - `CONTRIBUTING.md`: PR flow, sign-off, style. - `SECURITY.md`: vulnerability disclosure. @@ -119,8 +119,8 @@ with a placeholder marker; the marker itself is a leak. Beyond the file shapes above, certain phrasings always leak. These never appear in committed content (with the exception of this AGENTS.md, the canon audit script `scripts/canon_audit.sh`, and its two self-test fixtures `scripts/canon_audit_known_leaks.txt` and `scripts/canon_audit_pystring_concat_known_leaks.py`, which are allowed to name the patterns in order to forbid or self-verify them): - `maintainer-side`, `maintainer-internal` (any compound). -- `the operator's [strategy|methodology|notes|vault|workspace|tree|dev tree|bet|stake|positioning]` — also when an adjective intervenes (`the operator's research vault`). -- Bare `operator [paper|study|playbook|doctrine|memo|brief]` — these artifact-shape words name a written artifact authored by "the operator" and are unambiguously leak-shaped. +- `the operator's [strategy|methodology|notes|vault|workspace|tree|dev tree|bet|stake|positioning]`, also when an adjective intervenes (`the operator's research vault`). +- Bare `operator [paper|study|playbook|doctrine|memo|brief]`: these artifact-shape words name a written artifact authored by "the operator" and are unambiguously leak-shaped. - Practitioner-sense `operator` compounds: `operator [methodology|framework|practice|discipline|skill|stance]`, `multi-operator`, `operator-AI`, and `the operator's [loop|stance|skill|judgment|contribution|disposition|perspective|choice|workflow|discipline]`. "operator" was retired from public content in favor of "builder" (the person), second person for direct address, or dropped where it read as filler; these compounds are leaks. Bare `operator` in unrelated literal senses (cloud operators, the Python `operator` module, mathematical operators) is fine. The fresh-reader test catches any practitioner-sense recurrence the patterns miss. - Any definite reference to `vault` as a body of operator material: `the vault`, `in the vault`, `from the vault`. Also forbidden as terms of art: `vault-faithful`, `vault-validated`, `vault behaviour`, `vault precision threshold`, `vault notes`. Allowed only in domain compounds where `vault` is unrelated (`password vault`, `secrets vault`, `hashicorp vault`, `key vault`). - Sanitization-shape parentheticals: `(see private)`, `(internal reference)`, `(maintainer-side reference)`, `(see maintainer-side ...)`. diff --git a/CHANGELOG.md b/CHANGELOG.md index da1f3a7..cd8d12b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and ## [Unreleased] +### Changed + +- Repository home moved to a personal account (`lluvr/cma`). Self-references, badges, and issue/security links updated; author and publisher framing is now personal (organization publisher attribution dropped). +- Zenodo DOI references removed from `CITATION.cff` pending re-issuance under the new account; `SECURITY.md`'s publisher-identity claim softened accordingly. +- Repository layout: the deep-dive docs (`DESIGN`, `ARCHITECTURE`, `DATA`, `DECISIONS`, `GOVERNANCE`) moved under `docs/`, and `test.sh` / `bench.sh` moved under `scripts/`. All internal references updated. + --- ## [1.1.0] - 2026-05-25 @@ -20,7 +26,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and ## [1.0.0] - 2026-05-15 -cma 1.0 reference implementation. The surface defined in [DESIGN.md](DESIGN.md) is locked and complete. +cma 1.0 reference implementation. The surface defined in [DESIGN.md](docs/DESIGN.md) is locked and complete. ### Surface @@ -36,7 +42,7 @@ cma 1.0 reference implementation. The surface defined in [DESIGN.md](DESIGN.md) ### Action-time injection -- Five-stage architecture (interception, context extraction, query, injection, logging) specified in [ARCHITECTURE.md](ARCHITECTURE.md). Reference implementations: +- Five-stage architecture (interception, context extraction, query, injection, logging) specified in [ARCHITECTURE.md](docs/ARCHITECTURE.md). Reference implementations: - Claude Code: `hooks/claude-code-pre-tool-use.sh` (per-action surfacing) and `hooks/claude-code-session-start.sh` (session priming with recurrence + active rejections, optionally behavior pivots). - Shell: `hooks/cma-pre` for zsh (native `preexec`) and bash (via `bash-preexec`), with manual-wrap support. - Failure-isolated: hook errors never block the wrapped action; 5-second timeout on cma queries. @@ -64,10 +70,10 @@ cma 1.0 reference implementation. The surface defined in [DESIGN.md](DESIGN.md) ### Documentation -- [DESIGN.md](DESIGN.md): seven-primitive surface, argument semantics, output expectations. -- [ARCHITECTURE.md](ARCHITECTURE.md): five-stage action-time injection contract, data shapes, validation framework, quality criteria for integrations. -- [DATA.md](DATA.md): per-record-type schemas with examples, schema versioning policy, atomicity guarantees, tolerant-read behavior, storage requirements, backup recommendations, migration policy. -- [DECISIONS.md](DECISIONS.md): architectural decision records. +- [DESIGN.md](docs/DESIGN.md): seven-primitive surface, argument semantics, output expectations. +- [ARCHITECTURE.md](docs/ARCHITECTURE.md): five-stage action-time injection contract, data shapes, validation framework, quality criteria for integrations. +- [DATA.md](docs/DATA.md): per-record-type schemas with examples, schema versioning policy, atomicity guarantees, tolerant-read behavior, storage requirements, backup recommendations, migration policy. +- [DECISIONS.md](docs/DECISIONS.md): architectural decision records. ### Roadmap diff --git a/CITATION.cff b/CITATION.cff index 87d1da6..26fce9c 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,10 +1,9 @@ cff-version: 1.2.0 message: >- If you use cma in academic, applied, or compliance work, please - cite it using the metadata below. The methodology canon - (Lodestone) and the MCP distribution wrapper (cma-mcp, in this - repository under cma-mcp/) are separately citeable artifacts; - see the references block. + cite it using the metadata below. The MCP distribution wrapper + (cma-mcp, in this repository under cma-mcp/) is a separately + citeable artifact; see the references block. title: "cma: executable compound practice loop" type: software authors: @@ -12,12 +11,10 @@ authors: given-names: Lovro orcid: "https://orcid.org/0009-0008-9976-6933" website: "https://blog.clarethium.com" -repository-code: "https://github.com/Clarethium/cma" -url: "https://github.com/Clarethium/cma" +repository-code: "https://github.com/lluvr/cma" +url: "https://github.com/lluvr/cma" abstract: >- - cma is the executable companion to Lodestone, Clarethium's - canonical methodology for AI-coupled work. cma runs the - compound practice loop on your local machine: it + cma runs the compound practice loop on your local machine: it captures failures, surfaces relevant prior context at the moment of action, tracks decisions and rejected alternatives, detects recurrence, and captures preventions. Action-time injection ships @@ -31,18 +28,9 @@ keywords: - decision-tracking - prevention - lodestone - - clarethium license: Apache-2.0 version: "1.1.0" date-released: "2026-05-25" -doi: "10.5281/zenodo.20066625" -identifiers: - - type: doi - value: "10.5281/zenodo.20066625" - description: "Concept DOI; resolves to the latest release in this repository (cma or cma-mcp)" - - type: doi - value: "10.5281/zenodo.20232904" - description: "Versioned DOI for cma 1.0.0" references: - type: software title: "cma-mcp: Model Context Protocol distribution for the cma compound practice loop" @@ -50,7 +38,7 @@ references: - family-names: Lucic given-names: Lovro orcid: "https://orcid.org/0009-0008-9976-6933" - url: "https://github.com/Clarethium/cma/tree/main/cma-mcp" + url: "https://github.com/lluvr/cma/tree/main/cma-mcp" license: Apache-2.0 notes: >- Lives in this repository under cma-mcp/. Brings the same @@ -58,17 +46,3 @@ references: Desktop, Cursor, Cline, Continue.dev) by wrapping cma's CLI as a subprocess. See cma-mcp/CITATION.cff for its citable form. - - type: article - title: "Lodestone: canonical methodology for AI-coupled work" - authors: - - family-names: Lucic - given-names: Lovro - orcid: "https://orcid.org/0009-0008-9976-6933" - url: "https://github.com/Clarethium/lodestone" - license: CC-BY-4.0 - notes: >- - The methodology canon Clarethium publishes alongside cma. - Defines stance, the loop, calibration, altitude, failure - shapes, quality levels, surface protocols, and compound - practice (Section VIII). cma is the executable instantiation - of Lodestone Section VIII. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9332a1..a5b37fe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,11 +2,11 @@ The cma project ships two components in this repository: -- **cma** (bash, repository root) — the canonical compound practice +- **cma** (bash, repository root): the canonical compound practice loop reference implementation. Contributions touch `cma`, `hooks/`, - `test.sh`, `bench.sh`, and the design docs (`DESIGN.md`, - `ARCHITECTURE.md`, `DATA.md`). -- **cma-mcp** (Python, `cma-mcp/` subdirectory) — the Model Context + `scripts/test.sh`, `scripts/bench.sh`, and the design docs (`docs/DESIGN.md`, + `docs/ARCHITECTURE.md`, `docs/DATA.md`). +- **cma-mcp** (Python, `cma-mcp/` subdirectory): the Model Context Protocol distribution wrapper. Contributions touch the Python modules (`mcp_*.py`, `cma_*.py`), `cma-mcp/tests/`, and `cma-mcp/docs/`. @@ -14,8 +14,8 @@ The cma project ships two components in this repository: This document covers **how** contributions happen mechanically: file layout, test requirements, PR process, and what a reviewer will check. For **who** decides and **when** a contribution becomes -canon, see `GOVERNANCE.md`. Architectural decisions and their -rationales are recorded in `DECISIONS.md`. +canon, see `docs/GOVERNANCE.md`. Architectural decisions and their +rationales are recorded in `docs/DECISIONS.md`. --- @@ -25,8 +25,8 @@ rationales are recorded in `DECISIONS.md`. cma/ ├── cma bash CLI (the seven primitives) ├── hooks/ Claude Code + shell preexec integrations -├── test.sh, bench.sh bash test and benchmark harnesses -├── DESIGN.md ARCHITECTURE.md DATA.md cma's surface, architecture, schema +├── scripts/ test.sh, bench.sh, canon_audit.sh +├── docs/ DESIGN.md ARCHITECTURE.md DATA.md DECISIONS.md GOVERNANCE.md ├── CHANGELOG.md cma's release history ├── README.md cma overview ├── cma-mcp/ Python MCP distribution wrapper @@ -36,8 +36,8 @@ cma/ │ ├── pyproject.toml PyPI metadata, build config, py-modules list │ ├── README.md cma-mcp quickstart (also rendered on PyPI) │ └── CHANGELOG.md cma-mcp's release history (independent of cma) -├── DECISIONS.md GOVERNANCE.md project-level governance (covers both) -├── CONTRIBUTING.md SECURITY.md CITATION.cff NOTICE LICENSE cross-cutting +├── CONTRIBUTING.md SECURITY.md CODE_OF_CONDUCT.md community health +├── CITATION.cff NOTICE LICENSE AGENTS.md cross-cutting └── .github/ ├── workflows/test.yml cma's bash test workflow ├── workflows/tests-mcp.yml cma-mcp's pytest workflow @@ -56,13 +56,13 @@ prefixed accordingly (`cma-1.1`, `cma-mcp-0.2`). ## Before you start -1. **Read `DECISIONS.md`.** Architectural changes append a new +1. **Read `docs/DECISIONS.md`.** Architectural changes append a new entry; do not silently overturn an existing one. A contribution that contradicts a prior decision needs the contradiction named in the PR description. 2. **For bash cma contributions:** ensure `bash` and a working `python3` are available (cma uses python3 for JSON escape only). - Run `./test.sh` from the repository root before opening a PR. + Run `./scripts/test.sh` from the repository root before opening a PR. 3. **For cma-mcp contributions:** confirm bash cma is installed and on `PATH` (cma-mcp's tests exercise real subprocess calls). ```bash @@ -72,7 +72,7 @@ prefixed accordingly (`cma-1.1`, `cma-mcp-0.2`). "$(pwd)/cma" ~/.local/bin/cma` (per cma's README quickstart). 4. **Run the full test suite for the component you touched.** ```bash - ./test.sh # bash cma tests + ./scripts/test.sh # bash cma tests cd cma-mcp && pip install -e .[test] && python3 -m pytest -q ``` The suite for the touched component must stay green. @@ -144,7 +144,7 @@ payload shape requires a determinism-test update. under the rules of [DCO 1.1](https://developercertificate.org/). 2. **Tests pass on Python 3.10, 3.11, 3.12.** CI runs all three. 3. **No new external runtime dependencies** without an architectural - decision in `DECISIONS.md`. cma-mcp's runtime dependency footprint + decision in `docs/DECISIONS.md`. cma-mcp's runtime dependency footprint is currently the Python standard library only; adding a dependency requires explicit rationale. 4. **Three-section payload discipline preserved.** If the PR changes @@ -167,14 +167,14 @@ A PR that lands meets all of the following: - [ ] Schema, server, test, and docs updated together for surface changes - [ ] CHANGELOG.md `[Unreleased]` updated - [ ] No new runtime dependency without architectural decision -- [ ] If contradicting a prior DECISIONS.md entry, the contradiction is named in the PR description +- [ ] If contradicting a prior docs/DECISIONS.md entry, the contradiction is named in the PR description --- ## Reporting issues Bug reports, feature requests, and protocol questions go to -[GitHub Issues](https://github.com/Clarethium/cma/issues). For +[GitHub Issues](https://github.com/lluvr/cma/issues). For issues specific to one component, prefix the title with `[cma]` or `[cma-mcp]` so triage can disambiguate. Security issues use GitHub's private vulnerability reporting; see `SECURITY.md`. diff --git a/NOTICE b/NOTICE index 6c8d7be..5a92018 100644 --- a/NOTICE +++ b/NOTICE @@ -1,8 +1,6 @@ cma project (cma + cma-mcp) Copyright 2026 Lovro Lucic -Published under Clarethium (https://github.com/Clarethium). - This product includes software developed by Lovro Lucic. Components @@ -33,19 +31,17 @@ at repository root. External works referenced ------------------------- -Reference methodology lives in Lodestone -(https://github.com/Clarethium/lodestone), licensed CC-BY 4.0. -Neither cma nor cma-mcp bundles Lodestone content. If you -tag captures with a methodology's failure-mode vocabulary (such as -Lodestone's FM-1..10), you are responsible for citing that methodology -in your own work. +cma is methodology-agnostic and bundles no methodology content. +If you tag captures with a methodology's failure-mode vocabulary +(such as Lodestone's FM-1..10), you are responsible for citing that +methodology in your own work. Verification substrate referenced in design documents is Touchstone (https://github.com/Clarethium/touchstone), Apache 2.0 (library) and CC-BY 4.0 (Standard). -Companion projects in the Clarethium body ------------------------------------------ +Related projects +---------------- - Lodestone: canonical methodology (CC-BY 4.0) - Touchstone: model-independent measurement substrate @@ -60,4 +56,4 @@ and adversarial test architecture follow the conventions established by frame-check. Where this project diverges (e.g., bundling the MCP wrapper alongside the wrapped binary in one repository rather than as a separate sibling repo), the divergence is named in -DECISIONS.md. +docs/DECISIONS.md. diff --git a/README.md b/README.md index 8d647f8..aeaa381 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,23 @@ # cma -[![tests](https://github.com/Clarethium/cma/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/Clarethium/cma/actions/workflows/test.yml) -[![tests-mcp](https://github.com/Clarethium/cma/actions/workflows/tests-mcp.yml/badge.svg?branch=main)](https://github.com/Clarethium/cma/actions/workflows/tests-mcp.yml) -[![codeql](https://github.com/Clarethium/cma/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/Clarethium/cma/actions/workflows/codeql.yml) +[![tests](https://github.com/lluvr/cma/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/lluvr/cma/actions/workflows/test.yml) +[![tests-mcp](https://github.com/lluvr/cma/actions/workflows/tests-mcp.yml/badge.svg?branch=main)](https://github.com/lluvr/cma/actions/workflows/tests-mcp.yml) +[![codeql](https://github.com/lluvr/cma/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/lluvr/cma/actions/workflows/codeql.yml) [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE) -Capture what each piece of work teaches: failures, decisions, the paths you ruled out. Get the relevant ones back the moment you need them. cma is the command-line companion to [Lodestone](https://github.com/Clarethium/lodestone). +Capture what each piece of work teaches: failures, decisions, the paths you ruled out. Get the relevant ones back the moment you need them. cma runs entirely on your machine. ## What this is -cma runs the compound practice loop on your machine: it captures failures as they happen, surfaces the relevant ones at the moment you are about to act again, tracks decisions, and flags when a failure is recurring. It is the executable instantiation of the practice defined in Lodestone. +cma runs the compound practice loop on your machine: it captures failures as they happen, surfaces the relevant ones at the moment you are about to act again, tracks decisions, and flags when a failure is recurring. -The methodology lives in Lodestone. cma is what running that methodology looks like in a terminal. +cma is methodology-agnostic. It owns the data substrate (how captures are stored, surfaced, and joined into computable evidence) and stays out of the vocabulary you use to classify them. Pair it with whatever failure-mode catalog your practice already uses; Lodestone is one such methodology. ## Status cma 1.0 reference implementation. All seven primitives fully functional: `cma miss`, `cma decision`, `cma reject`, `cma prevented`, `cma surface`, `cma distill` (default + `--review` + `--retire`), and `cma stats` (default + `--rejections` + `--preventions` + `--recurrence` + `--leaks` + `--behavior`). Action-time injection (Claude Code hook + shell wrapper). Texture preservation on misses. Test suite (143 cases) covers functional paths, edge cases, JSON validity, the leak-detection join, hook integration, and shell wrapper modes. -The full surface is specified in [DESIGN.md](DESIGN.md). Additive features (action-time injection, texture preservation, counterfactual capture, recurrence detection) layer on without changing the locked surface. +The full surface is specified in [DESIGN.md](docs/DESIGN.md). Additive features (action-time injection, texture preservation, counterfactual capture, recurrence detection) layer on without changing the locked surface. ## Quick start @@ -26,7 +26,7 @@ The full surface is specified in [DESIGN.md](DESIGN.md). Additive features (acti Clone the repository and add the script to your `PATH`: ```bash -git clone https://github.com/Clarethium/cma.git +git clone https://github.com/lluvr/cma.git ln -s "$(pwd)/cma/cma" ~/.local/bin/cma # or copy to anywhere on PATH cma init # create the data directory with a README ``` @@ -50,9 +50,9 @@ cma miss "missed validation in middleware" \ The texture fields (`--excerpt`, `--intended`, `--corrected`) preserve the conditions of the failure so future surfacing can match by situation, not just keywords. -The `--fm` value is an opaque string from your perspective; cma stores it without interpretation. When using a methodology with a canonical failure-mode catalog (such as [Lodestone](https://github.com/Clarethium/lodestone)), tag with the methodology's canonical names so analysis tooling can interpret them. cma is methodology-agnostic; the catalog and its meaning live in the methodology, not in cma. +The `--fm` value is an opaque string from your perspective; cma stores it without interpretation. When using a methodology with a canonical failure-mode catalog (such as Lodestone), tag with the methodology's canonical names so analysis tooling can interpret them. cma is methodology-agnostic; the catalog and its meaning live in the methodology, not in cma. -Captures are written to `~/.cma/` as JSON Lines files (one record per line, append-only). The data directory can be overridden with `CMA_DIR=/path/to/data cma ...`. The full schema, atomicity guarantees, and migration policy are documented in [DATA.md](DATA.md). +Captures are written to `~/.cma/` as JSON Lines files (one record per line, append-only). The data directory can be overridden with `CMA_DIR=/path/to/data cma ...`. The full schema, atomicity guarantees, and migration policy are documented in [DATA.md](docs/DATA.md). Run `cma --help` for the full command surface. @@ -90,7 +90,7 @@ The closure rate counts only preventions evidenced by a surface event between th ## Action-time injection -cma surfaces relevant prior captures automatically when you (or an AI assistant) are about to act. The five-stage architecture (interception, context extraction, query, injection, logging) is documented in [ARCHITECTURE.md](ARCHITECTURE.md). Two reference integrations ship in this repository. +cma surfaces relevant prior captures automatically when you (or an AI assistant) are about to act. The five-stage architecture (interception, context extraction, query, injection, logging) is documented in [ARCHITECTURE.md](docs/ARCHITECTURE.md). Two reference integrations ship in this repository. ### Claude Code @@ -168,7 +168,7 @@ Triggers fire on commands likely to warrant surfacing: editors (`vim`, `nvim`, ` Failure isolation: if cma is missing, errors, or times out (default 5 seconds), the wrapped command still runs cleanly. The wrapper never blocks an action on its own failure. -Both integrations log surface events to `~/.cma/surface_events.jsonl`. `cma stats --leaks` later joins these events against subsequent misses to flag failures that occurred despite a relevant warning being surfaced — the validation evidence that the loop closes. +Both integrations log surface events to `~/.cma/surface_events.jsonl`. `cma stats --leaks` later joins these events against subsequent misses to flag failures that occurred despite a relevant warning being surfaced, the validation evidence that the loop closes. ## MCP distribution (cma-mcp) @@ -187,28 +187,29 @@ pip install cma-mcp See [`cma-mcp/README.md`](cma-mcp/README.md) for the MCP-specific quickstart and tool surface. The architectural decisions governing -the wrapper are recorded in [DECISIONS.md](DECISIONS.md). +the wrapper are recorded in [DECISIONS.md](docs/DECISIONS.md). ## Testing ```bash -./test.sh +./scripts/test.sh ``` Tests cover all capture verbs (normal and edge cases including special characters, missing arguments, unknown flags) and the operational verbs (`surface`, `distill`, `stats`). -## The Clarethium body +## Related work -cma sits alongside two open reference artifacts published by Clarethium: +cma sits alongside a set of open reference artifacts: - **[Touchstone](https://github.com/Clarethium/touchstone)** validates work against quality standards. -- **[Lodestone](https://github.com/Clarethium/lodestone)** orients practice. +- **[frame-check](https://github.com/Clarethium/frame-check)** analyzes structural framing as an MCP server. +- **Lodestone** orients practice with a canonical methodology. -cma is the executable companion to Lodestone. The doctrine is in Lodestone; the running code is here. Experiments and findings from this practice are published at [What Holds Up](https://blog.clarethium.com). +cma runs on its own and is agnostic to the methodology you practice; when that methodology is Lodestone, cma is what running it looks like in a terminal. Experiments and findings from this practice are published at [What Holds Up](https://blog.clarethium.com). ## Methodology integration -cma is methodology-agnostic. The `--fm` field on captures is an opaque string; cma stores it without interpretation. When using a methodology with a canonical failure-mode catalog (such as [Lodestone](https://github.com/Clarethium/lodestone)), tag with the methodology's canonical names. The methodology owns the vocabulary and its meaning; cma owns the data substrate. +cma is methodology-agnostic. The `--fm` field on captures is an opaque string; cma stores it without interpretation. When using a methodology with a canonical failure-mode catalog (such as Lodestone), tag with the methodology's canonical names. The methodology owns the vocabulary and its meaning; cma owns the data substrate. For automatic classification at capture time, set `CMA_FM_CLASSIFIER` to a command that reads the description on stdin and emits the failure-mode tag on stdout: @@ -219,21 +220,21 @@ cma miss "skipped verification before deploying" # Classifier auto-tags the --fm value based on the description. ``` -The classifier is external to cma; you provide the command. It can be Lodestone-aware (mapping descriptions to Lodestone's canonical failure shapes), methodology-specific, or generic. cma invokes it as an opaque command. Failure-isolated: if the classifier errors, is missing, or times out (5s), the capture proceeds without an `--fm` value. See [ARCHITECTURE.md Section 9](ARCHITECTURE.md) for the full integration pattern. +The classifier is external to cma; you provide the command. It can be Lodestone-aware (mapping descriptions to Lodestone's canonical failure shapes), methodology-specific, or generic. cma invokes it as an opaque command. Failure-isolated: if the classifier errors, is missing, or times out (5s), the capture proceeds without an `--fm` value. See [ARCHITECTURE.md Section 9](docs/ARCHITECTURE.md) for the full integration pattern. ## Architecture -cma's action-time injection layer follows a five-stage architecture (interception, context extraction, query, injection, logging). The pattern, reference implementations, data contracts, and validation framework are specified in [ARCHITECTURE.md](ARCHITECTURE.md). Read it before writing a new integration; conform to its contracts so downstream analysis tooling stays consistent. +cma's action-time injection layer follows a five-stage architecture (interception, context extraction, query, injection, logging). The pattern, reference implementations, data contracts, and validation framework are specified in [ARCHITECTURE.md](docs/ARCHITECTURE.md). Read it before writing a new integration; conform to its contracts so downstream analysis tooling stays consistent. ### Performance -ARCHITECTURE.md Section 6 specifies <50ms typical latency for action-time injection. The `./bench.sh` harness measures each operation 100 times after 3 warmup runs against a synthetic 100-capture data set, and reports min / p50 / p95 / p99. The text run prints a table; `./bench.sh --json` emits a machine-readable record (operation name, percentile latencies, host kernel/CPU/filesystem, timestamp) suitable for tracking over time. +docs/ARCHITECTURE.md Section 6 specifies <50ms typical latency for action-time injection. The `./scripts/bench.sh` harness measures each operation 100 times after 3 warmup runs against a synthetic 100-capture data set, and reports min / p50 / p95 / p99. The text run prints a table; `./scripts/bench.sh --json` emits a machine-readable record (operation name, percentile latencies, host kernel/CPU/filesystem, timestamp) suitable for tracking over time. On commodity Linux and macOS the hot operations (`cma-pre --check`, `cma surface`, `cma stats` default summary) come in at p95 under 50ms. p99 is noisier and occasionally crosses the target on busy hosts; the architecture target is "typical" latency, not worst-case. Sub-50ms work is inherently sample-sensitive; re-run on the target host before citing numbers, and prefer the JSON output over a single text run. ## Roadmap -The 1.0 surface is locked (see [DESIGN.md](DESIGN.md)) and all seven primitives are functional. Action-time injection ships for Claude Code (PreToolUse and SessionStart hooks) and for shell environments (zsh native preexec, bash via bash-preexec). Both follow the five-stage architecture in [ARCHITECTURE.md](ARCHITECTURE.md). +The 1.0 surface is locked (see [DESIGN.md](docs/DESIGN.md)) and all seven primitives are functional. Action-time injection ships for Claude Code (PreToolUse and SessionStart hooks) and for shell environments (zsh native preexec, bash via bash-preexec). Both follow the five-stage architecture in [ARCHITECTURE.md](docs/ARCHITECTURE.md). Beyond 1.0: counterfactual capture analysis tooling, per-project data scoping, recency-weighted surface ranking. See [CHANGELOG.md](CHANGELOG.md) for the full pending list. @@ -243,4 +244,4 @@ Apache 2.0. See [LICENSE](LICENSE). ## Author -L. Lucic. Published under Clarethium. +L. Lucic. diff --git a/SECURITY.md b/SECURITY.md index 3df7e98..3df97cb 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,8 +7,8 @@ This policy covers both components in this repository: bash cma | Component | Version | Supported | |---|---|---| -| cma | 1.0.x | Yes | -| cma | < 1.0 | No | +| cma | 1.1.x | Yes | +| cma | < 1.1 | No | | cma-mcp | 0.1.x | Yes | | cma-mcp | < 0.1 | No | @@ -22,7 +22,7 @@ artifact and update on each minor release. If you find a security issue in either component, do not open a public GitHub issue. Instead, use GitHub's private vulnerability reporting: open the repository **Security** tab and click **Report a -vulnerability** (). +vulnerability** (). Include: - Affected component (cma or cma-mcp) and version @@ -57,7 +57,7 @@ Their combined threat surface is limited: from your `PATH`. You are responsible for confirming the `cma` binary on your `PATH` is the canonical one (run `cma --version` and verify the SHA against the - [Clarethium/cma](https://github.com/Clarethium/cma) release). + [lluvr/cma](https://github.com/lluvr/cma) release). 4. **No network calls.** cma-mcp performs zero network I/O. No telemetry, no remote configuration, no external dependencies at runtime beyond the Python standard library. @@ -86,8 +86,8 @@ provenance bundle from PyPI's integrity endpoint: https://pypi.org/integrity/cma-mcp///provenance ``` -The returned JSON identifies the publisher as `Clarethium/cma`, -workflow `publish-mcp.yml`, environment `pypi`. Verification +The returned JSON identifies the publishing GitHub Actions +workflow (`publish-mcp.yml`) and environment (`pypi`). Verification tooling such as [`pypi-attestation-models`](https://pypi.org/project/pypi-attestation-models/) can validate the bundle and confirm the wheel was produced by this repository's release workflow rather than swapped at the diff --git a/cma b/cma index 969fc71..08e2f45 100755 --- a/cma +++ b/cma @@ -1,9 +1,8 @@ #!/usr/bin/env bash # cma - Compound practice loop -# https://github.com/Clarethium/cma +# https://github.com/lluvr/cma # -# Specification: see DESIGN.md -# Methodology: https://github.com/Clarethium/lodestone +# Specification: see docs/DESIGN.md set -euo pipefail @@ -170,7 +169,7 @@ cmd_miss() { # invoke the classifier with description on stdin and use its first # line of output as the fm tag. Failure-isolated: classifier errors, # missing commands, or timeouts do not block the capture. - # See ARCHITECTURE.md Section 9 (Methodology integration). + # See docs/ARCHITECTURE.md Section 9 (Methodology integration). if [[ -z "$fm" ]] && [[ -n "${CMA_FM_CLASSIFIER:-}" ]]; then fm=$(printf '%s' "$description" | timeout 5 sh -c "$CMA_FM_CLASSIFIER" 2>/dev/null | head -1 || true) # Trim leading/trailing whitespace @@ -1059,13 +1058,13 @@ warn_if_storage_risky() { # cloud-sync directories that watch+rewrite files (Dropbox, # iCloud Drive, OneDrive, Google Drive). Warn rather than block # so you can override after reading the rationale in - # DATA.md. + # docs/DATA.md. local dir="$1" case "$dir" in *Dropbox*|*"iCloud Drive"*|*OneDrive*|*"Google Drive"*|*GoogleDrive*|*pCloudDrive*|*Sync/*) echo "cma: warning: $dir looks like a cloud-sync path." >&2 echo "cma: append atomicity is not guaranteed on synced directories;" >&2 - echo "cma: see DATA.md (Storage requirements) for the rationale." >&2 + echo "cma: see docs/DATA.md (Storage requirements) for the rationale." >&2 return 0 ;; esac @@ -1077,7 +1076,7 @@ warn_if_storage_risky() { nfs*|cifs|smbfs|fuse.sshfs|fuseblk) echo "cma: warning: $dir is on a $fs filesystem." >&2 echo "cma: append atomicity is not guaranteed on network filesystems;" >&2 - echo "cma: see DATA.md (Storage requirements) for the rationale." >&2 + echo "cma: see docs/DATA.md (Storage requirements) for the rationale." >&2 ;; esac } @@ -1270,7 +1269,7 @@ cmd_init() { This directory is the durable corpus of compound practice. The schema, layout, atomicity guarantees, and migration policy are documented at: - https://github.com/Clarethium/cma/blob/main/DATA.md + https://github.com/lluvr/cma/blob/main/docs/DATA.md Files in this directory: @@ -1327,10 +1326,9 @@ Other: cma --version cma --help -Specification: DESIGN.md in this repository. -Architecture: ARCHITECTURE.md in this repository. -Schema: DATA.md in this repository. -Methodology: https://github.com/Clarethium/lodestone +Specification: docs/DESIGN.md in this repository. +Architecture: docs/ARCHITECTURE.md in this repository. +Schema: docs/DATA.md in this repository. Data directory: \$CMA_DIR (default: ~/.cma) EOF diff --git a/cma-mcp/CHANGELOG.md b/cma-mcp/CHANGELOG.md index 06f9851..3943e1d 100644 --- a/cma-mcp/CHANGELOG.md +++ b/cma-mcp/CHANGELOG.md @@ -19,7 +19,13 @@ and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0. ## [Unreleased] -(no entries yet) +### Changed + +- Protocol version negotiation. The `initialize` handshake now responds with the protocol revision the client requested when the server supports it (`2025-11-25`, `2025-06-18`, `2025-03-26`, `2024-11-05`), and otherwise responds with the newest revision the server supports, per the MCP lifecycle spec. Previously the server always returned `2024-11-05` regardless of the client's request, which mislabeled the session for clients speaking a newer revision. The `--version` fingerprint reports the newest supported revision (`2025-11-25`); per-call provenance reports the revision negotiated for the session. +- Structured tool output. Every tool declares an `outputSchema` (the shared three-section shape), and tool-call results include `structuredContent` alongside the existing text block, so `2025-06-18`+ clients can consume and validate the payload without re-parsing the text. Backward-compatible: clients that predate structured output ignore both fields. +- Server `instructions` and tool descriptions read as self-contained. cma-mcp is described as a methodology-agnostic substrate without a hard dependency on an external methodology link; references that did not resolve for adopters were removed. +- Repository home moved to `lluvr/cma`; author and publisher framing is now personal. The provenance `citation` shipped in every payload reads "(L. Lucic, 2026)". Zenodo DOI references were removed from `CITATION.cff` pending re-issuance under the new account. +- Documentation section of the README corrected: the wheel ships the Python modules plus `LICENSE` and `NOTICE`; the docs and changelog live in the source repository (an earlier "bundled with the wheel" claim did not match what the wheel actually contains). --- diff --git a/cma-mcp/CITATION.cff b/cma-mcp/CITATION.cff index 34329fe..3c49798 100644 --- a/cma-mcp/CITATION.cff +++ b/cma-mcp/CITATION.cff @@ -27,18 +27,10 @@ keywords: - decision-tracking - prevention - cma - - clarethium license: Apache-2.0 version: "0.1.4" date-released: "2026-07-03" -doi: "10.5281/zenodo.20066625" identifiers: - - type: doi - value: "10.5281/zenodo.20066625" - description: "Concept DOI; resolves to the latest release" - - type: doi - value: "10.5281/zenodo.20211591" - description: "Versioned DOI for cma-mcp 0.1.2" - type: url value: "https://pypi.org/project/cma-mcp/" description: "PyPI distribution" diff --git a/cma-mcp/NOTICE b/cma-mcp/NOTICE index 6c8d7be..db8d926 100644 --- a/cma-mcp/NOTICE +++ b/cma-mcp/NOTICE @@ -1,8 +1,6 @@ cma project (cma + cma-mcp) Copyright 2026 Lovro Lucic -Published under Clarethium (https://github.com/Clarethium). - This product includes software developed by Lovro Lucic. Components @@ -33,19 +31,17 @@ at repository root. External works referenced ------------------------- -Reference methodology lives in Lodestone -(https://github.com/Clarethium/lodestone), licensed CC-BY 4.0. -Neither cma nor cma-mcp bundles Lodestone content. If you -tag captures with a methodology's failure-mode vocabulary (such as -Lodestone's FM-1..10), you are responsible for citing that methodology -in your own work. +cma is methodology-agnostic and bundles no methodology content. +If you tag captures with a methodology's failure-mode vocabulary +(such as Lodestone's FM-1..10), you are responsible for citing that +methodology in your own work. Verification substrate referenced in design documents is Touchstone (https://github.com/Clarethium/touchstone), Apache 2.0 (library) and CC-BY 4.0 (Standard). -Companion projects in the Clarethium body ------------------------------------------ +Related projects +---------------- - Lodestone: canonical methodology (CC-BY 4.0) - Touchstone: model-independent measurement substrate diff --git a/cma-mcp/README.md b/cma-mcp/README.md index 78df12c..afac7ff 100644 --- a/cma-mcp/README.md +++ b/cma-mcp/README.md @@ -95,15 +95,19 @@ three top-level sections: { "analysis": { ... data and stdout }, "agent_guidance": { what to tell the user, how to cite }, - "provenance": { server_version, license, cost: 0.0, ... } + "provenance": { server_version, protocol_version, license, cost_usd: 0.0, ... } } +Tool calls also return this payload as `structuredContent` (validated +against each tool's `outputSchema`) for MCP clients on protocol +`2025-06-18` or newer, alongside the text form older clients read. + The `agent_guidance` and `provenance` sections exist because an agent passing cma-mcp output to a user without attribution would strip the reproducibility that makes the loop's evidence worth citing. Surfacing "how to cite faithfully" inside the payload is the structure that carries that integrity forward. This convention -is the same one Frame Check uses; +is the same one frame-check uses; cma-mcp inherits it. Adversarial tests in `tests/test_payload_determinism.py` pin the structure. @@ -157,14 +161,17 @@ pipeline wiring and that the cma binary is reachable. ## Documentation -Bundled with the wheel: +In the repository: - `CHANGELOG.md`: cma-mcp release history - `docs/MCP_SERVER.md`: protocol reference - `docs/ARCHITECTURE.md`: module layout, data flow, contracts - `docs/FAQ.md`: conceptual questions, install gotchas, cross-client config - `docs/TROUBLESHOOTING.md`: symptoms and fixes -- `LICENSE` (Apache-2.0), `NOTICE`, `CITATION.cff` + +The installed wheel carries `LICENSE` and `NOTICE` in its `dist-info` +metadata (Apache-2.0 attribution); the docs above live in the source +repository. ## Running tests diff --git a/cma-mcp/cma_jsonl.py b/cma-mcp/cma_jsonl.py index b792e7c..fc21be3 100644 --- a/cma-mcp/cma_jsonl.py +++ b/cma-mcp/cma_jsonl.py @@ -12,7 +12,7 @@ surface_events.jsonl Schema is documented in cma's DATA.md. This module reads those files -without writing — cma-mcp's tools always shell out to bash cma for +without writing. cma-mcp's tools always shell out to bash cma for writes; reads happen here directly because they are simpler and faster than spawning a subprocess for every resource fetch. diff --git a/cma-mcp/cma_subprocess.py b/cma-mcp/cma_subprocess.py index 5b83c0b..e5a4218 100644 --- a/cma-mcp/cma_subprocess.py +++ b/cma-mcp/cma_subprocess.py @@ -125,7 +125,7 @@ def resolve_cma_binary() -> str: argv=["cma"], returncode=None, stdout="", - stderr="cma binary not found on PATH; install from https://github.com/Clarethium/cma", + stderr="cma binary not found on PATH; install from https://github.com/lluvr/cma", reason="missing_binary", ) return found diff --git a/cma-mcp/docs/ARCHITECTURE.md b/cma-mcp/docs/ARCHITECTURE.md index ff5282f..e903dc6 100644 --- a/cma-mcp/docs/ARCHITECTURE.md +++ b/cma-mcp/docs/ARCHITECTURE.md @@ -8,7 +8,7 @@ when evaluating changes. For the protocol surface (every tool argument, every resource URI), see [`MCP_SERVER.md`](MCP_SERVER.md). For the architectural -decisions that shaped this design, see [`DECISIONS.md`](../../DECISIONS.md) +decisions that shaped this design, see [`DECISIONS.md`](../../docs/DECISIONS.md) at the repository root. --- @@ -65,9 +65,9 @@ no-MCP-SDK-dependency. Plus two cross-cutting modules: -- `mcp_log.py` — stderr-only structured logging. Stdout is reserved +- `mcp_log.py`: stderr-only structured logging. Stdout is reserved for JSON-RPC. -- `_build_info.py` — auto-generated at build time by `setup.py`, +- `_build_info.py`: auto-generated at build time by `setup.py`, bakes the git SHA into the wheel so `--version` reports a real value after `pip install` (see "Install fingerprint" below). @@ -84,7 +84,7 @@ The `cli()` entry point in `mcp_server.py` routes by argument: | `cma-mcp --test` | `_emit_test_payload()` runs a canned `cma_stats` against your `~/.cma/`, prints the full three-section payload, exits | offline pipeline check without an MCP client handshake | | `cma-mcp --help` | argparse default | discoverability | -Unknown flags exit non-zero with a usage message — the CLI never +Unknown flags exit non-zero with a usage message. The CLI never silently swallows misconfiguration. --- @@ -110,7 +110,7 @@ silently swallows misconfiguration. "intended","corrected","excerpt"]). The result is an argv list like ["miss", "", "--surface", "auth", "--fm", "FM-3"]. Values you supply land in distinct argv slots - only — never concatenated into a shell-interpreted string + only, never concatenated into a shell-interpreted string (DECISIONS AD-004). 5. _wrap_cma_call invokes cma_subprocess.run_cma(argv) which calls @@ -127,13 +127,13 @@ silently swallows misconfiguration. "agent_guidance": {"what_this_tool_does": "...", "what_this_tool_does_not_do": "...", "how_to_cite_faithfully": "..."}, - "provenance": {"server_version": "0.1.2", + "provenance": {"server_version": "0.1.4", "license": "Apache-2.0", "cost_usd": 0.0, "cma_argv": ["/usr/local/bin/cma", "miss", "", ...], "cma_returncode": 0, - "cma_binary_version": "cma 1.0.0", + "cma_binary_version": "cma 1.1.0", "git_sha": "abc123...", "deterministic": true, "timestamp": "2026-05-07T..."} @@ -173,6 +173,13 @@ Every tool response and every resource read returns: } ``` +Tool calls return this payload two ways: serialized in the `content` +text block, and as `structuredContent` (the same object) for +2025-06-18+ clients that validate it against the tool's +`outputSchema`. Resource reads return it in `contents[].text`. +`provenance.protocol_version` reports the revision negotiated for the +current session, not just the server's default. + **Why three sections, not one.** A plain stdout passthrough lets the agent paraphrase cma's output as its own observation, stripping the attribution that makes the loop's evidence worth citing. The @@ -214,7 +221,7 @@ structurally, not by review. (DECISIONS AD-006-style discipline). When `cma` is not on `PATH`, the response carries `{"isError": true, "reason": "missing_binary", - "install": "https://github.com/Clarethium/cma#readme"}`. + "install": "https://github.com/lluvr/cma#readme"}`. No silent skip. The cma binary path resolution: `shutil.which("cma")`. If you @@ -228,8 +235,8 @@ paths.) `cma_jsonl.py` reads your data directly for the four read-only resource URIs (`cma://decisions`, `cma://rejections`, -`cma://core`, `cma://stats`). The reader is **tolerant** — DECISIONS -AD-002 — and reports the parse-trust signal in `provenance`: +`cma://core`, `cma://stats`). The reader is **tolerant** (DECISIONS +AD-002) and reports the parse-trust signal in `provenance`: ``` ReadResult( @@ -261,8 +268,8 @@ the records. ``` {"server_name": "cma-mcp", - "server_version": "0.1.2", - "protocol_version": "2024-11-05", + "server_version": "0.1.4", + "protocol_version": "2025-11-25", "git_sha": "", "cma_binary_version": "", "python": "3.12.3", @@ -301,7 +308,7 @@ on the most common install path. | `mcp_log.py` | ~70 | Stderr-only structured logging. Stdout reserved for JSON-RPC. | | `_build_info.py` | 2 | Auto-generated by `setup.py` at build time. `BUILD_GIT_SHA = "..."`. Gitignored. | -Test suite (`tests/`): 54 cases plus the wheel-install smoke step +Test suite (`tests/`): 55 cases plus the wheel-install smoke step in CI. --- @@ -329,11 +336,11 @@ shape that keeps cma-mcp thin and drift-resistant. A surface change (adding a tool, adding a resource, changing a schema) touches **four files together**: -1. `mcp_schema.py` — add the entry to `TOOLS` or `RESOURCES`. -2. `mcp_server.py` — add the `_handle_*` dispatcher and wire it. -3. `tests/test_mcp_server.py` — add a conformance test that +1. `mcp_schema.py`: add the entry to `TOOLS` or `RESOURCES`. +2. `mcp_server.py`: add the `_handle_*` dispatcher and wire it. +3. `tests/test_mcp_server.py`: add a conformance test that exercises the surface. -4. `docs/MCP_SERVER.md` — document the reference. +4. `docs/MCP_SERVER.md`: document the reference. A PR that moves only one of the four is incomplete. Reviewers will ask for the others. See [`CONTRIBUTING.md`](../../CONTRIBUTING.md) diff --git a/cma-mcp/docs/FAQ.md b/cma-mcp/docs/FAQ.md index b0fd6b4..8aaa7b3 100644 --- a/cma-mcp/docs/FAQ.md +++ b/cma-mcp/docs/FAQ.md @@ -34,16 +34,15 @@ to your `~/.cma/` per its DATA.md schema. On WSL, that is the WSL home (`/home//.cma/`), not the Windows side. You can override via `CMA_DIR=/some/other/path` and bash -cma honors it — cma-mcp passes the env through subprocess +cma honors it; cma-mcp passes the env through subprocess inheritance. ### Is cma-mcp methodology-specific? -No. cma stores `--fm` as an opaque string. If you use -[Lodestone](https://github.com/Clarethium/lodestone), tag captures -with FM-1..10; if you use a different methodology, tag with -that catalog. cma-mcp does not validate, expand, or interpret the -tag. Tool descriptions reference Lodestone as the canonical +No. cma stores `--fm` as an opaque string. If you use Lodestone, +tag captures with its FM-1..10; if you use a different methodology, +tag with that catalog. cma-mcp does not validate, expand, or +interpret the tag. Tool descriptions name Lodestone as one example methodology but bundle no vocabulary (DECISIONS AD-006). --- @@ -56,7 +55,7 @@ Yes. cma-mcp wraps the canonical bash cma binary as a subprocess. On startup, every tool call invokes `cma ...`. Without the binary on `PATH`, every call returns `isError: true` with `reason: missing_binary`. Install bash cma first per the -[parent README](https://github.com/Clarethium/cma#readme), then +[parent README](https://github.com/lluvr/cma#readme), then `pip install cma-mcp`. ### Where do I put the MCP client config? @@ -68,7 +67,7 @@ binary on `PATH`, every call returns `isError: true` with | Cline | VS Code settings UI → Cline → MCP servers | `cma` | | Continue.dev | `~/.continue/config.json` | `mcpServers.cma` | -The block content is the same across clients — point at the +The block content is the same across clients. Point at the installed `cma-mcp` entry point: ``` @@ -109,11 +108,11 @@ Run `cma-mcp --version` directly in a terminal. It emits a one-line JSON fingerprint with `server_version`, `protocol_version`, `git_sha`, `cma_binary_version`, `python` version, and `script` path. If `cma_binary_version` is `null`, bash cma is missing or -silent — fix that first. +silent. Fix that first. For a deeper check, run `cma-mcp --test`. It emits a full three-section payload for `cma_stats` (default view) against your -real `~/.cma/` corpus — the same shape an MCP client would see for +real `~/.cma/` corpus, the same shape an MCP client would see for that tool call, without needing to spin up a client. ### Why does my agent paraphrase cma's output instead of quoting it? @@ -122,7 +121,7 @@ The agent guidance section of every payload includes `how_to_cite_faithfully`: a one-line instruction telling the agent exactly how to quote without smoothing the numbers. If the agent still paraphrases, surface the issue with the agent's prompt -configuration rather than cma-mcp's payload — the discipline lives +configuration rather than cma-mcp's payload. The discipline lives in the agent's reading, not in the wire format. ### Can I use cma-mcp and the bash hooks at the same time? @@ -131,14 +130,14 @@ Yes. They are independent integration paths over the same underlying corpus (`~/.cma/*.jsonl`). The PreToolUse hook in Claude Code surfaces priming context before tool calls; cma-mcp tools surface or capture on demand from any MCP-compatible client. Both -write through bash cma's atomic-write discipline — captures from +write through bash cma's atomic-write discipline; captures from either path interleave correctly. ### How fast is each MCP call? Lightweight calls (ping, tools/list, resources/list) round-trip in under 5ms. Subprocess-bound calls inherit bash cma's latency: -~50ms for `cma_stats` (default), ~5–15ms for `cma_surface` and +~50ms for `cma_stats` (default), ~5 to 15ms for `cma_surface` and `cma_miss`. Run `python3 bench.py` from the cma-mcp directory for numbers against your machine. The MCP wrapper itself adds essentially zero overhead. @@ -147,7 +146,7 @@ essentially zero overhead. The three-section payload contract (`analysis` + `agent_guidance` + `provenance`) is stable across cma-mcp 0.x. Tool argument schemas -are stable within a major version (`SERVER_VERSION` — see +are stable within a major version (`SERVER_VERSION`, see `mcp_server.py`). bash cma's JSONL data schema is stable across the `1.0` line per its DATA.md. Schema changes that are not backwards-compatible bump the relevant major version explicitly. @@ -198,7 +197,7 @@ discipline (DECISIONS AD-002). Every response carries `provenance.citation`: -> `cma-mcp 0.1.2 (Clarethium, 2026). https://github.com/Clarethium/cma/tree/main/cma-mcp` +> `cma-mcp 0.1.4 (L. Lucic, 2026). https://github.com/lluvr/cma/tree/main/cma-mcp` Also in `CITATION.cff` at the repository root and in the project's PyPI metadata. Once a Zenodo DOI is allocated, the citation will @@ -214,9 +213,9 @@ Lodestone separately if you reference its vocabulary. ## Where things live -- **Reference:** [`MCP_SERVER.md`](MCP_SERVER.md) — +- **Reference:** [`MCP_SERVER.md`](MCP_SERVER.md): every tool argument, every resource URI, the exact response shapes. -- **Architecture map:** [`ARCHITECTURE.md`](ARCHITECTURE.md) — +- **Architecture map:** [`ARCHITECTURE.md`](ARCHITECTURE.md): module layout, data flow, contracts. - **Symptoms and fixes:** [`TROUBLESHOOTING.md`](TROUBLESHOOTING.md). diff --git a/cma-mcp/docs/MCP_SERVER.md b/cma-mcp/docs/MCP_SERVER.md index 0336054..bf0628b 100644 --- a/cma-mcp/docs/MCP_SERVER.md +++ b/cma-mcp/docs/MCP_SERVER.md @@ -5,7 +5,7 @@ protocol surface: the initialize handshake, tools/list, tools/call, resources/list, resources/read, ping, and notifications. It covers the request and response shapes a client sees. -For the rationale behind these choices, see [`DECISIONS.md`](../../DECISIONS.md) +For the rationale behind these choices, see [`DECISIONS.md`](../../docs/DECISIONS.md) at the repository root. ## Transport @@ -24,7 +24,7 @@ Request: "id": 1, "method": "initialize", "params": { - "protocolVersion": "2024-11-05", + "protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": "claude-desktop", "version": "1.x"} } @@ -36,33 +36,47 @@ Response: "jsonrpc": "2.0", "id": 1, "result": { - "protocolVersion": "2024-11-05", + "protocolVersion": "2025-11-25", "capabilities": { "tools": {"listChanged": false}, "resources": {"listChanged": false, "subscribe": false} }, - "serverInfo": {"name": "cma-mcp", "version": "0.1.2"}, + "serverInfo": {"name": "cma-mcp", "version": "0.1.4"}, "instructions": "cma-mcp distributes the cma compound practice loop ..." } } The `instructions` field carries cross-tool orientation prose for agents and for MCP clients whose UI surfaces the field. Names the -use case, the default invocation pattern, and the methodology-canon -boundary (Lodestone owns vocabulary; cma stores `--fm` opaque). +use case, the default invocation pattern, and the methodology +boundary (the methodology owns vocabulary; cma stores `--fm` opaque). + +### Version negotiation + +The server speaks these protocol revisions, newest first: +`2025-11-25`, `2025-06-18`, `2025-03-26`, `2024-11-05`. Per the MCP +lifecycle spec, if the client requests a revision the server +supports, the server responds with that same revision; otherwise it +responds with its newest (`2025-11-25`), and the client decides +whether to proceed. A client that omits `protocolVersion` gets the +newest. ## Tools `tools/list` returns seven tools. Each tool definition has -`name`, `title`, `description`, and `inputSchema`. The full schema -shapes are in `mcp_schema.py`. +`name`, `title`, `description`, `inputSchema`, and `outputSchema`. +Every tool returns the same three-section payload, so `outputSchema` +is the shared shape below; the full schema shapes are in +`mcp_schema.py`. ### Common shapes All tool results have `content` (a one-element array of `{type: -"text", text: }`) and `isError` (boolean). +"text", text: }`), `structuredContent` (the same +payload as a JSON object, for 2025-06-18+ clients that validate it +against the tool's `outputSchema`), and `isError` (boolean). -The text payload is always a three-section JSON document: +The payload is always a three-section JSON document: { "analysis": { ... }, @@ -187,8 +201,8 @@ Server version follows semver: { "server_name": "cma-mcp", - "server_version": "0.1.2", - "protocol_version": "2024-11-05", + "server_version": "0.1.4", + "protocol_version": "2025-11-25", "git_sha": "abc12345" or "abc12345+dirty" or null, "cma_binary_version": "" or null, "python": "3.12.3", diff --git a/cma-mcp/docs/TROUBLESHOOTING.md b/cma-mcp/docs/TROUBLESHOOTING.md index c5d1cba..b2e9d69 100644 --- a/cma-mcp/docs/TROUBLESHOOTING.md +++ b/cma-mcp/docs/TROUBLESHOOTING.md @@ -1,6 +1,6 @@ # cma-mcp Troubleshooting -Symptoms, diagnostics, fixes. Read top-down — the diagnostic loop +Symptoms, diagnostics, fixes. Read top-down: the diagnostic loop at the start gives the right answer for ~80% of issues. For "why" questions and conceptual orientation, see @@ -22,7 +22,7 @@ identifies the layer to fix. ``` If `1` fails: install bash cma per the -[parent README](https://github.com/Clarethium/cma#readme). +[parent README](https://github.com/lluvr/cma#readme). If `2` fails (binary works but corpus errors): run `cma init` to materialize `~/.cma/`, or check that `CMA_DIR` is not pointing @@ -90,7 +90,7 @@ log tells you what failed. **Symptom.** Every tool call returns: ``` {"isError": true, "reason": "missing_binary", - "install": "https://github.com/Clarethium/cma#readme"} + "install": "https://github.com/lluvr/cma#readme"} ``` **Cause.** The cma binary is not on the PATH that cma-mcp sees. @@ -171,7 +171,7 @@ unrecognized schema. **Fix.** Two paths. -1. If the records came from a non-Clarethium cma fork (different +1. If the records came from a different cma fork (a different `schema_version` value), confirm the schema is read-compatible with cma 1.0. Most additive changes are; check the fork's schema docs. @@ -203,7 +203,7 @@ unrecognized schema. binary is missing or unreadable.** Install git and confirm `git rev-parse HEAD` works from the cma-mcp directory. -`git_sha: null` is honest and not a fatal error — the install +`git_sha: null` is honest and not a fatal error; the install fingerprint surfaces the gap rather than hiding it. --- @@ -232,7 +232,7 @@ floor, not a ceiling. ## Where to file a bug Reproducible bugs go to -[github.com/Clarethium/cma/issues](https://github.com/Clarethium/cma/issues) +[github.com/lluvr/cma/issues](https://github.com/lluvr/cma/issues) with the `cma-mcp` label or `[cma-mcp]` in the title to disambiguate from bash cma issues. @@ -260,5 +260,5 @@ MCP client: ``` Security issues use GitHub's private vulnerability reporting; see -[SECURITY.md](https://github.com/Clarethium/cma/blob/main/SECURITY.md), +[SECURITY.md](https://github.com/lluvr/cma/blob/main/SECURITY.md), not the public issue tracker. diff --git a/cma-mcp/mcp_compose.py b/cma-mcp/mcp_compose.py index f5c446b..dba7e7f 100644 --- a/cma-mcp/mcp_compose.py +++ b/cma-mcp/mcp_compose.py @@ -36,7 +36,7 @@ # cma binary surfaces here as None rather than crashing the server. _SERVER_NAME: str = "cma-mcp" _SERVER_VERSION: str = "0.1.0" -_PROTOCOL_VERSION: str = "2024-11-05" +_PROTOCOL_VERSION: str = "2025-11-25" _GIT_SHA: str | None = None _CMA_BINARY_VERSION: str | None = None @@ -62,6 +62,20 @@ def configure_provenance( _CMA_BINARY_VERSION = cma_version() +def set_protocol_version(version: str) -> None: + """Update the protocol version reported in provenance to the revision + negotiated for the current session. + + Startup configures this to the server's default (latest supported); + mcp_server._handle_initialize overrides it once the client's + initialize handshake settles on a revision, so per-call provenance + reports the version the session actually speaks rather than the + server's maximum. + """ + global _PROTOCOL_VERSION + _PROTOCOL_VERSION = version + + def _now_iso() -> str: """UTC ISO-8601 with microsecond resolution.""" from datetime import datetime, timezone @@ -80,8 +94,8 @@ def base_provenance() -> dict[str, Any]: "license": "Apache-2.0", "cost_usd": 0.0, "citation": ( - f"cma-mcp {_SERVER_VERSION} (Clarethium, 2026). " - f"https://github.com/Clarethium/cma/tree/main/cma-mcp" + f"cma-mcp {_SERVER_VERSION} (L. Lucic, 2026). " + f"https://github.com/lluvr/cma/tree/main/cma-mcp" ), "deterministic": True, "timestamp": _now_iso(), @@ -108,17 +122,15 @@ def base_provenance() -> dict[str, Any]: "Does not interpret the capture, does not classify " "automatically. The fm field stays opaque unless " "CMA_FM_CLASSIFIER is wired for an external classifier. " - "cma-mcp is a substrate; methodology vocabulary lives in the " - "methodology canon (see " - "https://github.com/Clarethium/lodestone for the canonical " - "methodology Clarethium publishes)." + "cma-mcp is a substrate; methodology vocabulary lives in " + "whatever methodology you practice, not in cma." ), "how_to_cite_faithfully": ( "Cite the capture explicitly when telling you about " "it: name the cma tool that ran ('cma_miss' / 'cma_decision' " "/ etc.), the id returned in analysis.record.id (or visible " "in analysis.cma_stdout), and the stored surface/fm. Do not " - "paraphrase as 'I noted that...' — paraphrase strips the " + "paraphrase as 'I noted that...': paraphrase strips the " "durability you chose this tool to obtain." ), } @@ -334,7 +346,7 @@ def compose_error_response( "how_to_cite_faithfully": ( "Surface the error reason verbatim ('cma binary " "missing on PATH', 'cma subprocess timeout', etc.). " - "Do not paraphrase as 'something went wrong' — that " + "Do not paraphrase as 'something went wrong'; that " "robs you of the actionable detail." ), }, diff --git a/cma-mcp/mcp_schema.py b/cma-mcp/mcp_schema.py index 3fe0f16..b3ba9fc 100644 --- a/cma-mcp/mcp_schema.py +++ b/cma-mcp/mcp_schema.py @@ -19,8 +19,8 @@ but you may pass any short label that fits your work. `fm` (failure-mode) is opaque per DECISIONS AD-006. cma-mcp does not -bundle a failure-mode catalog. Tool descriptions reference Lodestone -as the canonical methodology that owns the FM-1..10 vocabulary; +bundle a failure-mode catalog. Tool descriptions name Lodestone as +one example methodology that owns an FM-1..10 vocabulary; if you use a different methodology, pass that methodology's tag through as opaque data. """ @@ -42,8 +42,8 @@ _FM_DESCRIPTION = ( "Failure-mode tag, opaque to cma. When you use a " "methodology with a canonical catalog (such as Lodestone's " - "FM-1..10, see https://github.com/Clarethium/lodestone), pass " - "that tag here as a string. cma-mcp does not bundle the catalog " + "FM-1..10), pass that tag here as a string. cma-mcp does not " + "bundle the catalog " "itself. If unset, cma falls back to your " "CMA_FM_CLASSIFIER plugin (if configured) or stores the miss " "with no fm." @@ -507,6 +507,52 @@ def _fm_field() -> dict: } +# Shared output schema. Every cma-mcp tool returns the same three-section +# payload, so the shape is declared once and attached to each tool below. +# 2025-06-18+ clients use it to validate `structuredContent`; older clients +# ignore the field, so it is backward-compatible. +THREE_SECTION_OUTPUT_SCHEMA: dict[str, Any] = { + "type": "object", + "description": ( + "Every cma-mcp tool returns the same three-section payload: the " + "tool's data, guidance for relaying it, and provenance." + ), + "properties": { + "analysis": { + "type": "object", + "description": "Tool-specific result data and the raw cma stdout.", + }, + "agent_guidance": { + "type": "object", + "description": ( + "How to relay the result: what the tool does, what it does " + "not do, and how to cite it faithfully." + ), + "properties": { + "what_this_tool_does": {"type": "string"}, + "what_this_tool_does_not_do": {"type": "string"}, + "how_to_cite_faithfully": {"type": "string"}, + }, + }, + "provenance": { + "type": "object", + "description": "Reproducibility metadata for the call.", + "properties": { + "server_name": {"type": "string"}, + "server_version": {"type": "string"}, + "protocol_version": {"type": "string"}, + "license": {"type": "string"}, + "cost_usd": {"type": "number"}, + "citation": {"type": "string"}, + "deterministic": {"type": "boolean"}, + "timestamp": {"type": "string"}, + }, + }, + }, + "required": ["analysis", "agent_guidance", "provenance"], +} + + # Ordered list (the order defines the sequence in tools/list response). TOOLS: list[dict[str, Any]] = [ CMA_MISS, @@ -518,6 +564,11 @@ def _fm_field() -> dict: CMA_STATS, ] +# Every cma tool returns the same three-section payload; attach the shared +# output schema to each so tools/list advertises it uniformly. +for _tool in TOOLS: + _tool["outputSchema"] = THREE_SECTION_OUTPUT_SCHEMA + # ── resources ───────────────────────────────────────────────────── diff --git a/cma-mcp/mcp_server.py b/cma-mcp/mcp_server.py index d9d7821..b83c319 100644 --- a/cma-mcp/mcp_server.py +++ b/cma-mcp/mcp_server.py @@ -68,7 +68,32 @@ # publish workflow's verify-tag step hard-fails on mismatch. SERVER_NAME = "cma-mcp" SERVER_VERSION = "0.1.4" -PROTOCOL_VERSION = "2024-11-05" + +# Protocol versions this server speaks, newest first. The wire surface +# it uses (initialize, tools/list, tools/call, resources/list, +# resources/read, ping) is unchanged across these revisions, so the +# server negotiates to whichever revision the client requests and +# otherwise offers its newest. See negotiate_protocol_version(). +SUPPORTED_PROTOCOL_VERSIONS = ( + "2025-11-25", + "2025-06-18", + "2025-03-26", + "2024-11-05", +) +# Preferred/default revision (the newest supported). Exposed via the +# --version fingerprint and returned when a client requests a revision +# this server does not support. +PROTOCOL_VERSION = SUPPORTED_PROTOCOL_VERSIONS[0] + + +def negotiate_protocol_version(client_protocol: str | None) -> str: + """Resolve the protocol version for the session per the MCP lifecycle + spec: if the server supports the revision the client requested, respond + with that same revision; otherwise respond with the latest revision the + server supports (the client then decides whether to proceed).""" + if client_protocol in SUPPORTED_PROTOCOL_VERSIONS: + return client_protocol + return PROTOCOL_VERSION # Cross-tool orientation prose for MCP clients whose UI surfaces the # initialize response's `instructions` field (e.g., Claude Desktop). @@ -84,8 +109,9 @@ "cma_surface before substantive work to inherit relevant prior " "context (this also logs a surface event used by leak detection). " "Use cma_stats and the cma:// resources to inspect the corpus. " - "cma-mcp is methodology-agnostic: vocabulary lives in Lodestone " - "(https://github.com/Clarethium/lodestone). Three-section payload " + "cma-mcp is methodology-agnostic: the failure-mode vocabulary " + "lives in whatever methodology you practice, not in cma. " + "Three-section payload " "(analysis + agent_guidance + provenance) on every response; " "preserve attribution when relaying tool output to you." ) @@ -306,14 +332,23 @@ def _handle_cma_stats(params: dict) -> dict: def _handle_initialize(params: dict) -> dict: - """Initialize handshake: return server identity and capabilities.""" + """Initialize handshake: negotiate protocol version, return server + identity and capabilities.""" + client_protocol = params.get("protocolVersion") + negotiated = negotiate_protocol_version(client_protocol) + # Reflect the negotiated revision in every subsequent payload's + # provenance, not just the server's default. The lifecycle guarantees + # initialize precedes any tool call, so this settles before the first + # provenance block is built. + mcp_compose.set_protocol_version(negotiated) mcp_log.info( "initialize", - client_protocol=params.get("protocolVersion"), + client_protocol=client_protocol, + negotiated_protocol=negotiated, client_name=(params.get("clientInfo") or {}).get("name"), ) return { - "protocolVersion": PROTOCOL_VERSION, + "protocolVersion": negotiated, "capabilities": { "tools": {"listChanged": False}, "resources": {"listChanged": False, "subscribe": False}, @@ -332,6 +367,7 @@ def _handle_tools_list(_: dict) -> dict: "title": t.get("title", t["name"]), "description": t["description"], "inputSchema": t["inputSchema"], + "outputSchema": t["outputSchema"], } for t in mcp_schema.TOOLS ] @@ -370,6 +406,11 @@ def _handle_tools_call(params: dict) -> dict: "text": json.dumps(payload, ensure_ascii=False, indent=2), } ], + # Structured mirror of the same three-section payload for + # 2025-06-18+ clients that consume and validate structuredContent + # against the tool's outputSchema. The text block above stays for + # backward compatibility with clients that do not. + "structuredContent": payload, "isError": is_error, } diff --git a/cma-mcp/pyproject.toml b/cma-mcp/pyproject.toml index 1568177..4a67ed5 100644 --- a/cma-mcp/pyproject.toml +++ b/cma-mcp/pyproject.toml @@ -21,7 +21,6 @@ keywords = [ "prevention", "lodestone", "cma", - "clarethium", "claude-desktop", "cursor", ] diff --git a/cma-mcp/setup.py b/cma-mcp/setup.py index 3dee882..611ab55 100644 --- a/cma-mcp/setup.py +++ b/cma-mcp/setup.py @@ -1,6 +1,6 @@ """Build-time hook: bake the repo git SHA into _build_info.py. -The pyproject.toml file is the authoritative metadata source — this +The pyproject.toml file is the authoritative metadata source. This shim runs only during sdist/wheel builds (and editable installs) so the resulting artifact carries the git SHA it was built from. After `pip install` from a wheel there is no `.git` directory next to the diff --git a/cma-mcp/tests/test_mcp_server.py b/cma-mcp/tests/test_mcp_server.py index b1d559f..af8864b 100644 --- a/cma-mcp/tests/test_mcp_server.py +++ b/cma-mcp/tests/test_mcp_server.py @@ -17,7 +17,9 @@ def test_initialize_returns_protocol_and_serverinfo(fresh_dispatcher): - result = call_handler(fresh_dispatcher, "initialize", {"protocolVersion": "2024-11-05"}) + result = call_handler( + fresh_dispatcher, "initialize", {"protocolVersion": mcp_server.PROTOCOL_VERSION} + ) assert result["protocolVersion"] == mcp_server.PROTOCOL_VERSION assert result["serverInfo"]["name"] == "cma-mcp" assert result["serverInfo"]["version"] == mcp_server.SERVER_VERSION @@ -31,6 +33,41 @@ def test_initialize_returns_protocol_and_serverinfo(fresh_dispatcher): assert "cma_miss" in result["instructions"] +def test_initialize_negotiates_protocol_version(fresh_dispatcher): + """Per the MCP lifecycle spec: the server echoes a supported revision + the client requests, and falls back to its own latest otherwise.""" + # Newest supported is the preferred default. + assert mcp_server.PROTOCOL_VERSION == mcp_server.SUPPORTED_PROTOCOL_VERSIONS[0] + # Legacy revision stays supported for older clients. + assert "2024-11-05" in mcp_server.SUPPORTED_PROTOCOL_VERSIONS + # Every supported revision is echoed back unchanged. + for version in mcp_server.SUPPORTED_PROTOCOL_VERSIONS: + result = call_handler(fresh_dispatcher, "initialize", {"protocolVersion": version}) + assert result["protocolVersion"] == version + # An unsupported request falls back to the server's latest. + result = call_handler(fresh_dispatcher, "initialize", {"protocolVersion": "1.0.0"}) + assert result["protocolVersion"] == mcp_server.PROTOCOL_VERSION + # A client that omits the field gets the server's latest. + result = call_handler(fresh_dispatcher, "initialize", {}) + assert result["protocolVersion"] == mcp_server.PROTOCOL_VERSION + + +def test_provenance_reflects_negotiated_protocol_version(fresh_dispatcher): + """After the initialize handshake, provenance reports the protocol + revision negotiated for the session, not just the server default.""" + import mcp_compose + + # A supported legacy revision is reflected in provenance... + call_handler(fresh_dispatcher, "initialize", {"protocolVersion": "2024-11-05"}) + assert mcp_compose.base_provenance()["protocol_version"] == "2024-11-05" + # ...and re-initializing with a newer one updates it. + call_handler(fresh_dispatcher, "initialize", {"protocolVersion": "2025-11-25"}) + assert mcp_compose.base_provenance()["protocol_version"] == "2025-11-25" + # An unsupported request falls back to the server's latest here too. + call_handler(fresh_dispatcher, "initialize", {"protocolVersion": "1.0.0"}) + assert mcp_compose.base_provenance()["protocol_version"] == mcp_server.PROTOCOL_VERSION + + def test_server_version_is_strict_semver(): """Per CHANGELOG / SERVER_VERSION discipline, version is M.m.p only.""" parts = mcp_server.SERVER_VERSION.split(".") @@ -57,6 +94,19 @@ def test_tools_list_carries_seven_tools(fresh_dispatcher): assert tool["inputSchema"]["type"] == "object" +def test_tools_list_advertises_output_schema(fresh_dispatcher): + """Every tool declares outputSchema (the shared three-section shape) + so 2025-06-18+ clients can validate structuredContent against it.""" + result = call_handler(fresh_dispatcher, "tools/list") + for tool in result["tools"]: + schema = tool.get("outputSchema") + assert isinstance(schema, dict), f"{tool['name']} missing outputSchema" + assert schema["type"] == "object" + assert set(schema["required"]) == {"analysis", "agent_guidance", "provenance"} + for section in ("analysis", "agent_guidance", "provenance"): + assert section in schema["properties"] + + def test_tool_descriptions_reference_lodestone_for_methodology(fresh_dispatcher): """ Per DECISIONS AD-006: cma-mcp does not bundle Lodestone vocabulary. @@ -218,7 +268,7 @@ def test_initialize_notification_does_not_crash(fresh_dispatcher): def test_git_sha_falls_back_to_baked_build_info(monkeypatch, tmp_path): - """When the runtime git probe fails (PyPI install layout — no `.git` + """When the runtime git probe fails (PyPI install layout, no `.git` next to the script), `_git_sha()` must fall back to the build-time value baked into `_build_info.BUILD_GIT_SHA` by `setup.py`. diff --git a/cma-mcp/tests/test_mcp_wire.py b/cma-mcp/tests/test_mcp_wire.py index 986173d..88abe03 100644 --- a/cma-mcp/tests/test_mcp_wire.py +++ b/cma-mcp/tests/test_mcp_wire.py @@ -1,7 +1,7 @@ """ Wire-protocol subprocess tests. -The other test files dispatch in-process — they exercise handler +The other test files dispatch in-process: they exercise handler logic but never push bytes through real stdin/stdout pipes. This file spawns cma-mcp as a real subprocess, exchanges JSON-RPC over the standard MCP transport, and pins the framing-level invariants @@ -40,7 +40,7 @@ class WireServer: """A real cma-mcp subprocess driven over stdin/stdout pipes. Reads one JSON-RPC line per response. Notifications produce no - response. The class deliberately stays minimal — it is the + response. The class deliberately stays minimal: it is the test's leverage point, not a general-purpose MCP client. """ @@ -318,6 +318,13 @@ def test_tools_call_cma_stats_round_trips_three_section_payload( # passed to cma. On an empty corpus the call still succeeds. assert payload["provenance"]["cma_returncode"] == 0 assert payload["provenance"]["cma_argv"][-1] == "stats" + # 2025-06-18+ structured output: structuredContent mirrors the + # text payload exactly and carries the three-section shape a + # validating client checks against the tool's outputSchema. + assert result["structuredContent"] == payload + assert set(result["structuredContent"].keys()) >= { + "analysis", "agent_guidance", "provenance"} + assert result["isError"] is False @pytest.mark.subprocess diff --git a/cma-mcp/tests/test_payload_determinism.py b/cma-mcp/tests/test_payload_determinism.py index d0803c6..8254196 100644 --- a/cma-mcp/tests/test_payload_determinism.py +++ b/cma-mcp/tests/test_payload_determinism.py @@ -42,7 +42,7 @@ def _assert_provenance_canonical(provenance: dict) -> None: assert provenance["license"] == "Apache-2.0" assert provenance["cost_usd"] == 0.0 assert provenance["deterministic"] is True - assert "Clarethium" in provenance["citation"] + assert "Lucic" in provenance["citation"] def _setup_provenance() -> None: diff --git a/ARCHITECTURE.md b/docs/ARCHITECTURE.md similarity index 95% rename from ARCHITECTURE.md rename to docs/ARCHITECTURE.md index 9a38cac..2b05aae 100644 --- a/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -6,7 +6,7 @@ The document is the contract between cma and any integration that connects it to ## 1. Purpose and scope -cma is the executable of compound practice, the discipline defined in [Lodestone](https://github.com/Clarethium/lodestone). The compound practice loop (Lodestone Section VIII) has five steps: +cma is the executable of compound practice. The compound practice loop has five steps: 1. **Capture** a failure, decision, rejection, or prevention. 2. **Surface** relevant prior captures when context matches a future action. @@ -18,7 +18,7 @@ The loop closes only if step 2 (surface) happens reliably at the moment of step This document covers the action-time injection layer: the pattern by which surfacing is triggered automatically by an external interception point, the data it produces, and the criteria that distinguish state-of-the-art integrations from bolt-on ones. -The document does not cover the seven primitives themselves (see [DESIGN.md](DESIGN.md)) or the methodology defined in Lodestone. +The document does not cover the seven primitives themselves (see [DESIGN.md](DESIGN.md)) or the vocabulary of any methodology paired with cma. ## 2. The five-stage architecture @@ -250,7 +250,7 @@ The architecture is designed to produce data supporting three independent layers - Score deltas correlated with cma usage intensity (captures per task, surfacings per task). - Failure-shape distribution shifts (fewer recurrences of named failure shapes). -**Strength**: objective, model-independent measurement. **Weakness**: requires your actual work to be amenable to Touchstone evaluation, which depends on output type. Currently aspirational; the bridge between Lodestone, cma, and Touchstone is the project's intellectual spine and is the next major architectural project after this one. +**Strength**: objective, model-independent measurement. **Weakness**: requires your actual work to be amenable to Touchstone evaluation, which depends on output type. Currently aspirational; the bridge between cma, a methodology's catalog, and Touchstone measurement is the next major architectural project after this one. The three layers are independent. A system that passes the Process layer alone is a journal. A system that passes Process + Behavior is a working compound practice loop. A system that passes all three is a methodology with empirical grounding. @@ -324,13 +324,13 @@ Integrations writing to `surface_events.jsonl` without conforming to the schema The architecture's contract is: integrations call `cma surface` and respect its output schema (Section 4). Adding new fields to surface events (additive) is backward-compatible. Removing fields requires a major version bump. -The contract is documented in this file and in [DESIGN.md](DESIGN.md). Changes to the contract follow the project's versioning policy (see [CHANGELOG.md](CHANGELOG.md)). +The contract is documented in this file and in [DESIGN.md](DESIGN.md). Changes to the contract follow the project's versioning policy (see [CHANGELOG.md](../CHANGELOG.md)). ## 9. Methodology integration cma is methodology-agnostic. The `--fm` field on captures and any methodology-specific tags are opaque strings from cma's perspective. Semantics are owned by the methodology in use. -When you use cma alongside a methodology that defines a canonical failure-mode catalog (Lodestone is the canonical human-AI collaboration methodology under Clarethium; others may emerge), you tag captures with the methodology's canonical names. Analysis tooling that reads cma data interprets the tags according to the methodology context. +When you use cma alongside a methodology that defines a canonical failure-mode catalog (Lodestone is one such methodology; others may emerge), you tag captures with the methodology's canonical names. Analysis tooling that reads cma data interprets the tags according to the methodology context. The integration is by convention (shared vocabulary), not by code. cma does not depend on any methodology. Methodologies do not depend on cma. Each evolves independently. cma documentation does not replicate methodology catalogs; methodology documents own their catalogs and their meaning. @@ -352,5 +352,4 @@ The classifier is external to cma: this repository ships no classifier. Methodol ## 10. References - [DESIGN.md](DESIGN.md): the seven cma 1.0 primitives. -- [Lodestone Section VIII](https://github.com/Clarethium/lodestone): the compound practice loop (the methodology this architecture serves). - [Touchstone](https://github.com/Clarethium/touchstone): the measurement infrastructure for the outcome layer of validation. diff --git a/DATA.md b/docs/DATA.md similarity index 99% rename from DATA.md rename to docs/DATA.md index c0b3a2e..15707af 100644 --- a/DATA.md +++ b/docs/DATA.md @@ -228,4 +228,4 @@ If you choose to stay on schema 1.0, you can do so indefinitely; cma 2.0 readers - [DESIGN.md](DESIGN.md): the seven cma 1.0 primitives that produce these records. - [ARCHITECTURE.md](ARCHITECTURE.md): the action-time injection layer and three-layer validation framework that uses this data. -- [CHANGELOG.md](CHANGELOG.md): record of schema and feature changes over time. +- [CHANGELOG.md](../CHANGELOG.md): record of schema and feature changes over time. diff --git a/DECISIONS.md b/docs/DECISIONS.md similarity index 91% rename from DECISIONS.md rename to docs/DECISIONS.md index 3a7333e..0d2e2b5 100644 --- a/DECISIONS.md +++ b/docs/DECISIONS.md @@ -16,18 +16,18 @@ Newest first. --- -## AD-008: cma-mcp lives inside Clarethium/cma as a subdirectory, not as a separate sibling repository +## AD-008: cma-mcp lives inside lluvr/cma as a subdirectory, not as a separate sibling repository **Date:** 2026-05-06 -**Decision.** cma-mcp ships under `cma-mcp/` in the Clarethium/cma +**Decision.** cma-mcp ships under `cma-mcp/` in the lluvr/cma repository alongside the canonical bash CLI rather than as a -separate `Clarethium/cma-mcp` repository. One repository, one +separate `lluvr/cma-mcp` repository. One repository, one governance scaffold (root-level `DECISIONS.md`, `GOVERNANCE.md`, `CONTRIBUTING.md`, `SECURITY.md`, `CITATION.cff`, `NOTICE`), two release tracks (tags prefixed `cma-1.x` and `cma-mcp-0.x`), two CHANGELOGs (`CHANGELOG.md` for cma; `cma-mcp/CHANGELOG.md` for -cma-mcp), two CI workflows (`tests.yml` for bash cma; +cma-mcp), two CI workflows (`test.yml` for bash cma; `tests-mcp.yml` for the Python wrapper, path-filtered to `cma-mcp/**`). @@ -93,11 +93,12 @@ Resources are reserved for context the agent reads to orient itself for `cma_miss` and `cma_prevented` reference Lodestone's FM-1..10 as an example methodology but do not enumerate it. -**Rationale.** Methodology vocabulary lives in -Lodestone; bundling a frozen copy in cma-mcp couples release cadence -and inverts canon-vs-companion separation. If you want the FM -catalog, read Lodestone directly; if you want autoclassification, -wire `CMA_FM_CLASSIFIER` per cma's plugin convention. +**Rationale.** Methodology vocabulary lives in the methodology, not +in cma-mcp; bundling a frozen copy couples release cadence and +inverts the substrate-vs-catalog separation. If you want a +failure-mode catalog, tag with your methodology's (Lodestone's +FM-1..10, for example); if you want autoclassification, wire +`CMA_FM_CLASSIFIER` per cma's plugin convention. --- diff --git a/DESIGN.md b/docs/DESIGN.md similarity index 68% rename from DESIGN.md rename to docs/DESIGN.md index 233befe..bc10338 100644 --- a/DESIGN.md +++ b/docs/DESIGN.md @@ -4,17 +4,17 @@ This document locks the surface API for cma 1.0. Implementation follows from thi ## Purpose -cma is the executable companion to [Lodestone](https://github.com/Clarethium/lodestone). It runs the compound practice loop on your local machine: capture failures, surface relevant prior context at the moment of action, track decisions and rejected alternatives, detect recurrence, and capture preventions. +cma runs the compound practice loop on your local machine: capture failures, surface relevant prior context at the moment of action, track decisions and rejected alternatives, detect recurrence, and capture preventions. -This document specifies the seven primitives that compose the cma surface, the relationships between them, and how the surface maps to the vocabulary defined in Lodestone. +This document specifies the seven primitives that compose the cma surface, the relationships between them, and how the surface maps to a methodology's failure-mode vocabulary. ## Conceptual basis -Vocabulary lives in two places: prose (the Lodestone glossary) and commands (cma primitives). The two surfaces share the same load-bearing terms. +Vocabulary lives in two places: a methodology's prose glossary and cma's commands (the primitives). The two surfaces share the same load-bearing terms. -Capture concepts are first-class. The Lodestone glossary names four distinct capture types — Miss, Decision, Rejection, Prevention — and cma preserves that distinction by giving each a verb. The conceptual difference between recording a failure and recording an eliminated option is load-bearing; collapsing them under a single `cma capture --type=...` would hide the distinction. +Capture concepts are first-class. cma's surface names four distinct capture types (Miss, Decision, Rejection, Prevention) and preserves that distinction by giving each a verb. The conceptual difference between recording a failure and recording an eliminated option is load-bearing; collapsing them under a single `cma capture --type=...` would hide the distinction. -Operational concerns are not first-class. Listing rejections, viewing leaks, retiring a learning, previewing a distillation — these are modes of larger operations, expressed as flags rather than separate verbs. Three operational verbs cover them all (surface, distill, stats). +Operational concerns are not first-class. Listing rejections, viewing leaks, retiring a learning, previewing a distillation: these are modes of larger operations, expressed as flags rather than separate verbs. Three operational verbs cover them all (surface, distill, stats). The result is seven primitives total: four capture verbs and three operational verbs. @@ -35,7 +35,7 @@ cma miss - `` (required, positional). One-line statement of what failed. Phrased actively: "Treated X as Y without verifying" rather than "X was treated as Y." - `--surface` (optional). The domain area: `auth`, `db`, `docs`, `ui`, `infra`, `general`, `git`. Auto-detected from file paths when `--files` is provided. -- `--fm` (optional). A failure-mode tag. cma stores the value opaquely; interpretation is the methodology's responsibility. When using a methodology with a canonical catalog (such as [Lodestone](https://github.com/Clarethium/lodestone)), tag with that methodology's canonical names. Auto-classification can be plugged in via the `CMA_FM_CLASSIFIER` env var (see ARCHITECTURE.md). +- `--fm` (optional). A failure-mode tag. cma stores the value opaquely; interpretation is the methodology's responsibility. When using a methodology with a canonical catalog (such as Lodestone), tag with that methodology's canonical names. Auto-classification can be plugged in via the `CMA_FM_CLASSIFIER` env var (see ARCHITECTURE.md). - `--files` (optional). Files involved in the failure. Comma-separated list. **Output:** Confirmation with the captured description, surface, fm, and a unique miss ID. If a similar miss exists in the last 90 days, output flags the recurrence and indicates which warning weight has been incremented. @@ -140,9 +140,9 @@ cma distill --review **Modes:** -- **Default mode** — promote a learning from accumulated captures to a permanent core learning that surfaces every session. `` is the distilled principle. -- **`--retire` mode** — retire a core learning that no longer applies or has been superseded. The learning is moved out of active surfacing but retained in the reasoning record. -- **`--review` mode** — preview the patterns that have accumulated since the last distillation. Outputs a summary of recent captures grouped by surface and failure shape, and lists candidate distillations. Read-only. +- **Default mode**: promote a learning from accumulated captures to a permanent core learning that surfaces every session. `` is the distilled principle. +- **`--retire` mode**: retire a core learning that no longer applies or has been superseded. The learning is moved out of active surfacing but retained in the reasoning record. +- **`--review` mode**: preview the patterns that have accumulated since the last distillation. Outputs a summary of recent captures grouped by surface and failure shape, and lists candidate distillations. Read-only. **Arguments (default mode):** @@ -167,12 +167,12 @@ cma stats **Modes:** -- **Default mode** — summary dashboard. Total captures by type, recent activity, most-active surfaces, top failure shapes, prevention rate, recurrence trends. -- **`--rejections` view** — list of active rejections with surfaces, ages, and revisit triggers. -- **`--leaks` view** — failures that occurred despite an active warning. Each leak increments the warning's weight. -- **`--preventions` view** — captured preventions with linked misses. Evidence of the loop closing. -- **`--recurrence` view** — failure shapes ordered by recurrence rate. Identifies preventions that are not working. -- **`--behavior` view** — behavior-layer signals from misses carrying intended/corrected texture, grouped by surface and failure mode. +- **Default mode**: summary dashboard. Total captures by type, recent activity, most-active surfaces, top failure shapes, prevention rate, recurrence trends. +- **`--rejections` view**: list of active rejections with surfaces, ages, and revisit triggers. +- **`--leaks` view**: failures that occurred despite an active warning. Each leak increments the warning's weight. +- **`--preventions` view**: captured preventions with linked misses. Evidence of the loop closing. +- **`--recurrence` view**: failure shapes ordered by recurrence rate. Identifies preventions that are not working. +- **`--behavior` view**: behavior-layer signals from misses carrying intended/corrected texture, grouped by surface and failure mode. **Output:** Tabular text with optional filters. Designed for human reading, not piping. @@ -182,11 +182,11 @@ cma stats Reference-implementation polish will land as additive features without changing this surface: -- **Texture preservation on misses** (conversation excerpt, intended action, corrected action) — added as additional optional fields on `cma miss`. The basic signature does not change. -- **Counterfactual capture** — same as above. -- **Action-time injection** (PreToolUse hook integration) — not a cma command; an integration with the host environment. -- **Active failure-shape curation** (3-4 active at any time, others archived) — implementation detail of how surfacing prioritizes warnings; surface unchanged. -- **Recurrence detection auto-flagging** — already implicit in `cma miss` output (recurrence is flagged when a similar prior miss exists); becomes more aggressive in a later version. +- **Texture preservation on misses** (conversation excerpt, intended action, corrected action): added as additional optional fields on `cma miss`. The basic signature does not change. +- **Counterfactual capture**: same as above. +- **Action-time injection** (PreToolUse hook integration): not a cma command; an integration with the host environment. +- **Active failure-shape curation** (3-4 active at any time, others archived): implementation detail of how surfacing prioritizes warnings; surface unchanged. +- **Recurrence detection auto-flagging**: already implicit in `cma miss` output (recurrence is flagged when a similar prior miss exists); becomes more aggressive in a later version. ## Output and storage diff --git a/GOVERNANCE.md b/docs/GOVERNANCE.md similarity index 95% rename from GOVERNANCE.md rename to docs/GOVERNANCE.md index 912648e..e54a233 100644 --- a/GOVERNANCE.md +++ b/docs/GOVERNANCE.md @@ -1,7 +1,7 @@ # Governance **Scope:** Covers the cma project as a whole. The project ships as -a single repository ([Clarethium/cma](https://github.com/Clarethium/cma)) +a single repository ([lluvr/cma](https://github.com/lluvr/cma)) with two components: the bash cma reference implementation (repository root) and the cma-mcp Python distribution wrapper (`cma-mcp/` subdirectory). One curator, one governance model, one @@ -102,9 +102,8 @@ forces a position: - **Suggestion/RFC process** modeled on Touchstone's `SUGGESTIONS/PROCESS.md`. cma-mcp is small enough that PR review is sufficient at the current scale; an RFC layer may add unwanted weight. -- **Trademark and brand policy.** cma-mcp is published under - Clarethium; brand decisions defer to the Clarethium-level - curator. +- **Trademark and brand policy.** cma is a personal project; brand + and naming decisions rest with the author. --- diff --git a/hooks/claude-code-session-start.sh b/hooks/claude-code-session-start.sh index 91702b1..9da4ea3 100755 --- a/hooks/claude-code-session-start.sh +++ b/hooks/claude-code-session-start.sh @@ -26,7 +26,7 @@ # "recurrence,rejections"). Available sections: recurrence, rejections, # behavior. Set to "all" to include every available section. # -# See ARCHITECTURE.md Section 2.1 (Interception) for the design context. +# See docs/ARCHITECTURE.md Section 2.1 (Interception) for the design context. set -uo pipefail @@ -37,7 +37,7 @@ if [[ ! -t 0 ]]; then cat > /dev/null fi -# Stage 3: query — failure-isolated. If cma missing, silent exit. +# Stage 3: query, failure-isolated. If cma missing, silent exit. if ! command -v cma >/dev/null 2>&1; then exit 0 fi @@ -79,7 +79,7 @@ get_section() { echo "$out" } -# Stage 4: injection — assemble output, write to stdout for Claude Code +# Stage 4: injection. Assemble output, write to stdout for Claude Code # to inject as session context. Silent when nothing to show. declare -a parts=() @@ -103,7 +103,7 @@ for p in "${parts[@]}"; do echo "$p" done -# Stage 5: logging — handled by cma stats invocations themselves where +# Stage 5: logging, handled by cma stats invocations themselves where # applicable (stats commands are aggregate views that do not log surface # events; this is intentional, since session-start priming is broad rather # than action-specific). diff --git a/hooks/cma-pre b/hooks/cma-pre index cea679d..442a36b 100755 --- a/hooks/cma-pre +++ b/hooks/cma-pre @@ -1,7 +1,7 @@ #!/usr/bin/env bash # cma-pre: action-time injection wrapper for shell environments. # -# Implements the five-stage architecture from ARCHITECTURE.md: +# Implements the five-stage architecture from docs/ARCHITECTURE.md: # 1. Interception: invoked by shell preexec hook OR manually # 2. Context extract: parses command line for trigger + surface heuristics # 3. Query: calls `cma surface` with derived filters @@ -16,7 +16,7 @@ # Failure isolation: if cma is missing, errors, or times out, the wrapped # command still runs. The wrapper never blocks a command on its own failure. # -# See ARCHITECTURE.md for the design contract this script implements. +# See docs/ARCHITECTURE.md for the design contract this script implements. set -uo pipefail @@ -45,7 +45,7 @@ Shell integration (bash, requires bash-preexec): preexec_functions+=("cma_pre_hook") cma_pre_hook() { cma-pre --check "$1"; } -See ARCHITECTURE.md for the design contract. +See docs/ARCHITECTURE.md for the design contract. EOF exit 1 fi @@ -139,7 +139,7 @@ if [[ -n "$output" && "$output" != "No captures match." ]]; then fi # --------------------------------------------------------------------------- -# Stage 5: logging — handled by `cma surface` invocation above. +# Stage 5: logging, handled by `cma surface` invocation above. # --------------------------------------------------------------------------- # Execute the wrapped command (if not in check-only mode) diff --git a/bench.sh b/scripts/bench.sh similarity index 92% rename from bench.sh rename to scripts/bench.sh index a1f2c0a..0f353a0 100755 --- a/bench.sh +++ b/scripts/bench.sh @@ -1,14 +1,14 @@ #!/usr/bin/env bash # bench.sh - Performance benchmarks for cma's action-time injection layer. # -# ARCHITECTURE.md Section 6 specifies <50ms typical end-to-end overhead for +# docs/ARCHITECTURE.md Section 6 specifies <50ms typical end-to-end overhead for # integration calls. This script measures `cma-pre --check` (the hook path) # and `cma surface` (the underlying query) so the claim is verifiable rather # than aspirational. # # Usage: -# ./bench.sh Run and print a human-readable table. -# ./bench.sh --json Emit machine-readable JSON to stdout (one object). +# ./scripts/bench.sh Run and print a human-readable table. +# ./scripts/bench.sh --json Emit machine-readable JSON to stdout (one object). # # Methodology: each operation is timed N=100 times after 3 warmup iterations. # Reports min, median (p50), p95, p99. Numbers vary across machines, kernels, @@ -17,8 +17,8 @@ set -uo pipefail -CMA="$(cd "$(dirname "$0")" && pwd)/cma" -PRE="$(cd "$(dirname "$0")" && pwd)/hooks/cma-pre" +CMA="$(cd "$(dirname "$0")/.." && pwd)/cma" +PRE="$(cd "$(dirname "$0")/.." && pwd)/hooks/cma-pre" N=${BENCH_N:-100} EMIT_JSON=false @@ -136,7 +136,7 @@ print(json.dumps({ PYEOF else echo "" - echo "Latency benchmarks (N=$N per operation; ARCHITECTURE.md target: <50ms typical)" + echo "Latency benchmarks (N=$N per operation; docs/ARCHITECTURE.md target: <50ms typical)" echo "Host: $HOST_KERNEL ($HOST_CPU, fs=$HOST_FS)" echo "" while IFS=$'\t' read -r name mn p50 p95 p99; do diff --git a/test.sh b/scripts/test.sh similarity index 99% rename from test.sh rename to scripts/test.sh index e4fb396..3f1b1da 100755 --- a/test.sh +++ b/scripts/test.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash # Tests for cma 1.0 -# Run from repository root: ./test.sh +# Run from repository root: ./scripts/test.sh set -uo pipefail -CMA="$(cd "$(dirname "$0")" && pwd)/cma" +CMA="$(cd "$(dirname "$0")/.." && pwd)/cma" CMA_DIR=$(mktemp -d) export CMA_DIR trap 'rm -rf "$CMA_DIR"' EXIT @@ -751,7 +751,7 @@ expect_contains "behavior shows corrected" "fix the root cause" "$CMA" sta # --------------------------------------------------------------------------- reset -HOOK="$(cd "$(dirname "$0")" && pwd)/hooks/claude-code-pre-tool-use.sh" +HOOK="$(cd "$(dirname "$0")/.." && pwd)/hooks/claude-code-pre-tool-use.sh" # Make cma command available on PATH for the hook's subprocess call HOOK_BIN_DIR=$(mktemp -d) ln -sf "$CMA" "$HOOK_BIN_DIR/cma" @@ -804,7 +804,7 @@ fi # --------------------------------------------------------------------------- reset -SS_HOOK="$(cd "$(dirname "$0")" && pwd)/hooks/claude-code-session-start.sh" +SS_HOOK="$(cd "$(dirname "$0")/.." && pwd)/hooks/claude-code-session-start.sh" # Empty data: silent out=$(bash "$SS_HOOK" &1) @@ -876,7 +876,7 @@ fi # --------------------------------------------------------------------------- reset -PRE="$(cd "$(dirname "$0")" && pwd)/hooks/cma-pre" +PRE="$(cd "$(dirname "$0")/.." && pwd)/hooks/cma-pre" # No-args exits 1 expect_exit "cma-pre with no args exits 1" 1 bash "$PRE"