Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"plugins": [
{
"name": "calm",
"description": "Adds the CALM MCP server: call-graph-aware locate/source/edit_symbol/diff_impact and 35 tools total for navigating and safely editing a codebase, backed by a multi-tier resolver (syntactic -> Stack Graphs -> SCIP) instead of grep.",
"description": "Adds the CALM MCP server: call-graph-aware locate/source/edit_symbol/diff_impact and 36 tools total for navigating and safely editing a codebase, backed by a multi-tier resolver (syntactic -> Stack Graphs -> SCIP) instead of grep.",
"author": {
"name": "Eilodon"
},
Expand Down
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Full stage-by-stage guide, all 8 Mandatory Rules, the Preset table, and Tool Qui

---

> 35 tools. 8 stages. Every response carries `suggested_next` — follow it.
> 36 tools. 8 stages. Every response carries `suggested_next` — follow it.
---

## Core Principles
Expand Down Expand Up @@ -262,7 +262,7 @@ remember("auth-flow", "OAuth callback must validate state param — see incident
| 1 Orient | `repo_overview`, `hotspots`, `fitness_report`, `test_gap_hotspots` (coreness × test-coverage-gap ranking) | Directory scanning, README reading |
| 2 Locate | `locate`, `search`, `file_overview` | `grep`, file search |
| 3 Inspect | `source`, `symbol_info`, `understand`, `symbols_batch` (batch source+callers/callees for several exact `qualified_name`s) | `cat` / full file read |
| 4 Trace | `callers`, `callees`, `path`, `dependencies` | Manual call tracing |
| 4 Trace | `callers`, `callees`, `path`, `dependencies`, `reference_impact` (rename/removal reference surface — merges call edges, imports, and textual matches) | Manual call tracing |
| 5 Pre-Edit | `edit_context` | *(no native equivalent)* |
| 6 Edit | `edit_symbol`, `edit_lines` (preferred), `format_files` (rustfmt via stdin, safe replacement for shelling out), `pattern_debt_register`/`pattern_debt_status` (track a duplicated bug pattern) | native `Edit`/`Write` (fallback for new/untracked files) |
| 7 Verify | `diff_impact` | *(no native equivalent)* |
Expand All @@ -288,10 +288,10 @@ remember("auth-flow", "OAuth callback must validate state param — see incident
| Preset | Registered Tools | Use when |
|--------|-----------------|----------|
| `orient` | `repo_overview`, `locate`, `dependencies`, `hotspots`, `fitness_report`, `indexing_status` | Exploration only, no edits |
| `trace` | `repo_overview`, `search`, `locate`, `symbol_info`, `source`, `callers`, `callees`, `path`, `dependencies`, `indexing_status` | Call graph traversal |
| `trace` | `repo_overview`, `search`, `locate`, `symbol_info`, `source`, `callers`, `callees`, `path`, `dependencies`, `reference_impact`, `indexing_status` | Call graph traversal |
| `edit` | `repo_overview`, `search`, `locate`, `symbol_info`, `source`, `callers`, `callees`, `edit_context`, `edit_lines`, `edit_symbol`, `diff_impact`, `indexing_status`, `edit_transaction_status`, `maintenance_status`, `retry_maintenance`, `repair_consistency`, `verify_change` | Code modification workflow |
| `compound` | `repo_overview`, `locate`, `hotspots`, `fitness_report`, `source`, `understand`, `edit_context`, `diff_impact`, `session_context`, `indexing_status`, `remember`, `recall` | Full workflow, no raw graph traversal |
| `full` | All 35 tools | Default; use when workflow spans multiple stages |
| `full` | All 36 tools | Default; use when workflow spans multiple stages |
`--preset` is set once at server startup and cannot change mid-session. Use `full` (default) when the workflow spans multiple stages. Use specific presets only when scope is locked to one stage.

Beyond the 5 named presets above, `--preset`/`config.json`'s `preset` field also accept a **composable toolset spec**: a comma-separated list of toolset (module-domain) names — `trace`, `locate`, `orient`, `memory`, `guardrails`, `recover`, `scip`, `lsp`, `security`, `testgap`, `inspect`, `edit`, `patterndebt` — optionally prefixed with `-` to subtract that toolset instead of adding it. E.g. `--preset "trace,security"` unions two toolsets; `--preset "full,-edit"` is every tool except the edit toolset's (`edit_symbol`/`edit_lines`/`format_files`). This is a different, finer-grained axis than the 5 named presets (which are hand-curated cross-cutting workflow bundles, not toolset unions) — an unrecognized token in either syntax is a hard startup error, never a silent full-access fallback.
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ git tags in [Releases](https://github.com/Eilodon/CALM/releases).
### Added
- Opt-in WS-6 first-slice verification (`docs/plans/2026-08-03-ws6-verification-pipeline-execution-plan.md`): `[verification] rust_check_on_write` (default off) routes a `.rs` write through the durable transaction's `VERIFY_PENDING` state instead of straight to `Done`; new `verify_change(tx_id)` tool runs `cargo check` scoped to the nearest Cargo package and advances the transaction to `Done`/`Failed` -- a failed check does not revert the file already written to disk
- `plugins/calm/.claude-plugin/plugin.json`'s `version` is now checked against `Cargo.toml`'s (`scripts/check-doc-truth.sh`) so the Claude Code plugin manifest can't silently drift from the release it bundles again
- `verify_change` now binds to the transaction's `proposed_digest`, checked both immediately before and immediately after `cargo check` runs -- a concurrent write can no longer get bound to someone else's verification receipt (`VERIFICATION_SNAPSHOT_CHANGED`)
- `[verification] timeout_secs` (default 120s): `cargo check` is killed if it hangs (a stuck `build.rs`/proc-macro/registry fetch) instead of blocking the tool call indefinitely
- `calm init` now creates `.calm/` atomically at `0700` (matching the daemon's own posture) instead of a plain `create_dir_all` at the umask default; `calm doctor --fix` additionally retightens an already-loose `.calm/` and its sensitive files (`index.db`, `memory.key`, `daemon.log`, `audit.log`, `daemon.sock`)
- Non-loopback `calm serve --http` now forces a capability-derived `remote-safe` preset (every tool declaring `read_only_hint = true`, computed live off the tool router) instead of the old `full,-edit` toolset exclusion, which only ever disabled `edit_lines`/`edit_symbol`/`format_files` -- `remember`, `verify_change`, `retry_maintenance`, `scip_refresh`, `lsp_refresh`, `set_toolset`, and `pattern_debt_register` are now also excluded by default over an unauthenticated-by-default remote transport
- The audit ledger (`audit_ledger`) is now HMAC-SHA256-signed (keyed by a new 0600 `.calm/audit.key`, separate from `memory.key`) instead of a plain unkeyed SHA-256 chain -- an actor with only SQLite file write access can no longer forge a chain that still passes `verify_chain`
- `calm setup --npx` now pins the written entry to `@eilodon/calm-mcp@<this binary's own version>` by default instead of an unpinned `npx -y @eilodon/calm-mcp`, so a cold `npx` invocation always resolves to the same release; `--track latest` opts back into the old unpinned behavior
- `.calm/config.json` `risk_rules` (default empty): a path-glob-to-minimum-risk floor (e.g. `{glob: "**/auth/**", minimum: "high"}`) that the write gate can never classify below, closing the gap where a low-fan-in but security-sensitive file read as low risk regardless of caller count
- `remember` now quarantines a note whose content trips the prompt-injection heuristic (still saved, same detection-only philosophy) and `recall` excludes quarantined notes from its ambient/broad paths (FTS `query`, no-args list-all) by default -- an exact `topic` lookup still always returns it, mirroring `edit_context`'s existing `related_notes` ambient-surfacing gate
- `KNOWN_LIMITATIONS.md`: an honest catalog of what CALM doesn't do yet and why each gap is deliberately deferred rather than half-built
- Indexing now skips any file over 8 MiB (`read_source_capped`, checked via a cheap `metadata()` stat before ever reading the file) and bounds a single tree-sitter parse to 5s (`Parser::set_timeout_micros`) -- a pathologically huge or deeply-nested file can no longer hang or balloon the indexer's memory
- `compute_touch_risk` now escalates risk to `"high"` when an edit's own proposed content actually changes a touched function/method's signature TEXT (not just overlaps its line range -- a whole-body replace that leaves the signature byte-for-byte identical does not escalate), reusing `diff_impact`'s own `is_signature_semantically_changed`/`escalate_risk_if_signature_changed`
- `calm serve --http` now caps request body size (16 MiB, `axum::extract::DefaultBodyLimit`) and concurrent in-flight requests (64, `tower::limit::ConcurrencyLimitLayer`) as defense-in-depth against the unbounded-resource gap a bare `axum::Router` had; still not a substitute for a reverse proxy's real rate limiting
- New `reference_impact` tool: merges call edges, import edges naming a symbol, and a repo-wide textual grep into one classified reference list (`must_change`/`likely_change`/`review`/`textual_only`) for rename/removal planning -- closes the exact gap behind two real `benchmarks/b7_task_correctness` misses (a bare re-export statement invisible to the call graph alone)
- `edit_lines`/`edit_symbol` gained an optional `cites` param: the EXACT `qualified_name` of a caller `edit_context` returned this session, checked by equality rather than the existing `reason` field's word-boundary substring search -- closes the "paste a real caller name into an unrelated sentence" gaming path for callers that opt in; the free-text `reason` path remains for backward compatibility

## [0.5.0] - 2026-08-03

Expand Down
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ Roadmap items currently open, roughly in priority order:
1. **Hook adapters for other MCP hosts.** `calm init --hooks[=nudge|enforce]` now scaffolds the PreToolUse/PostToolUse deny-hook wiring generically (backed by `calm-core::hooks`/`hooks_check`), but it only targets Claude Code's hook schema so far. VS Code/GitHub Copilot uses the *same* `PreToolUse` / `permissionDecision: deny` shape, so that port should be close to a direct translation. Cursor (`beforeMCPExecution`) and Windsurf (Cascade Hooks) use different shapes and need their own adapters.
2. **Resolver accuracy.** False positives/negatives in `coreness`/`is_hub` classification, edge cases in the SCIP-overlay caching key. Also useful: getting more of the optional SCIP cross-reference providers (Go, Java, C#, PHP, C, Ruby — see `install_hint` in `repo_overview`'s `health_summary`) easier to install, since call-graph precision for those languages is capped without one installed.
3. **New Tier-0.5 → Tier-0 promotions.** SQL and Dart both already ship (SQL has its own standalone `sqlparser`-based indexer — real grammar, not regex — but deliberately stops short of a call graph, since "calls" isn't a coherent concept across SQL dialects; Dart is Tier-0.5 with the known zero-call-edge grammar limit noted above) — the next candidates are whichever Tier-0.5 language your own report from the "try CALM on a Tier-0.5 language" bullet above turns up as highest-friction.
4. **A sandboxed, multi-language execution broker for verification.** `verify_change` runs one check (`cargo check`, unsandboxed beyond a wall-clock timeout and digest binding) — see `KNOWN_LIMITATIONS.md`'s "Verification is single-language..." entry. Extending to `go test`/`tsc --noEmit`/`pytest` needs a shared network/filesystem/env execution-policy abstraction built first, not each language bolted directly onto a bare subprocess call.
5. **`reference_impact(symbol, operation="rename")`.** `benchmarks/b7_task_correctness` has two real failing rename cases today from composing `callers`/`edit_context` by hand instead of having a tool that merges call edges + SCIP references + imports/re-exports + textual matches into one classified list. See `KNOWN_LIMITATIONS.md`'s "No unified reference-impact tool" entry.
6. **Change-kind-aware risk classification.** `compute_touch_risk` sees caller-count/hub-status and (as of this pass) a path-based `risk_rules` floor, but not whether an edit is a comment tweak vs. a signature break vs. an auth-check removal. Needs the diff content turned into a classified axis and folded into the risk model. See `KNOWN_LIMITATIONS.md`.
7. **`calm guard --staged` / a publishable GitHub Action.** The only integration point today is an MCP client calling CALM's tools directly — a native editor edit or a teammate's local commit is invisible to CALM. See `KNOWN_LIMITATIONS.md`'s "No Git/CI-native integration path" entry.
8. **Multi-file change-set / transaction.** Today every `edit_lines`/`edit_symbol`/`format_files` call is its own independent, file-scoped `EditTransaction` — a multi-file refactor has no aggregate success/failure view. See `KNOWN_LIMITATIONS.md`.

`KNOWN_LIMITATIONS.md` has the full list (including smaller items not listed here) with the reasoning for why each is deliberately deferred rather than half-built.

Please open a GitHub Issue before starting on anything larger than a small fix, so effort doesn't collide with what's already in progress.

Expand Down
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@ tracing-opentelemetry = { version = "0.33" }
# 0.8 + rmcp 2.2.0 (transport-streamable-http-server) resolve and build
# clean together (both on http 1.x / tower-service 0.3.x).
axum = "0.8"
# Same `http` feature as axum above -- already present transitively in
# Cargo.lock (pulled in by axum/hyper's own stack) at this exact version, so
# declaring it directly adds no new supply-chain surface. `limit` is the
# only feature enabled: `ConcurrencyLimitLayer`, used for basic HTTP-
# transport DoS hardening (docs/http-transport.md already documents this
# transport has no built-in protection -- see serve_http's doc comment for
# what this closes and what it deliberately doesn't).
tower = { version = "0.5", default-features = false, features = ["limit"] }

# Internal
calm-core = { path = "crates/calm-core" }
Expand Down
Loading
Loading