mason-context 0.3.7 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Mason – the context builder for LLMs 👷
1
+ # Mason – the system of record for your codebase's AI assistants 👷
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/mason-context)](https://www.npmjs.com/package/mason-context)
4
4
  [![CI](https://img.shields.io/github/actions/workflow/status/adrianczuczka/mason/ci.yml?branch=main)](https://github.com/adrianczuczka/mason/actions/workflows/ci.yml)
@@ -6,39 +6,41 @@
6
6
  [![license](https://img.shields.io/github/license/adrianczuczka/mason)](https://github.com/adrianczuczka/mason/blob/main/LICENSE)
7
7
  [![issues](https://img.shields.io/github/issues/adrianczuczka/mason)](https://github.com/adrianczuczka/mason/issues)
8
8
 
9
- Mason gives LLMs a persistent map of your codebase so they stop exploring from scratch every session.
9
+ ### Persistent, provably-fresh context your assistant can't grep for: team decisions, change history, and a feature-to-file map — assembled per task in one call.
10
10
 
11
- **The problem:** Every time an LLM starts a new conversation about your code, it greps, reads files, and pieces together the architecture burning tokens on context it already understood yesterday. On a 164-file project, answering "what features does this app have?" requires reading 8+ files across multiple tool calls.
11
+ **Modern agents are good at reading code. They're terrible at knowing what your team learned the hard way, what changes together, and whether yesterday's understanding still holds. Mason owns exactly that.**
12
12
 
13
- **Mason's fix:** A concept map that persists across sessions. One tool call returns a feature-to-file lookup table — the LLM knows exactly where to look, without exploring.
13
+ ```bash
14
+ claude mcp add mason --scope user -- npx -p mason-context mason-mcp
15
+ ```
14
16
 
15
- **Measured result** ([deepeval](https://github.com/confident-ai/deepeval), Claude Sonnet, 164-file KMP project):
17
+ Restart Claude Code, then ask: *"use mason to set up this project."* The assistant calls `mason_init`, walks you through a quick Q&A to build the concept map, and you're done.
16
18
 
17
- | Question | With Mason | Without Mason | Token saving |
18
- |---|---|---|---|
19
- | List all features | 10,258 tok | 31,346 tok | **67%** |
20
- | Trace data flow | 12,010 tok | 15,258 tok | **21%** |
21
- | Compare platforms | 10,897 tok | 19,353 tok | **44%** |
22
- | Onboarding flow | 10,271 tok | 11,432 tok | **10%** |
23
- | **Average** | | | **36%** |
19
+ Next session, your assistant loads the map instead of grepping 8 files to figure out what your app does.
24
20
 
25
- Same answer quality (0.9/1.0 on all tests, both paths). Reproduce: [bench/](bench/).
21
+ > **0.6.0 note:** Mason 0.6 adds decision records (`save_decision`), task-scoped assembly (`get_context`), map verification (`verify_snapshot`), the self-maintaining refresh loop, and richer uninitialized responses. If you set Mason up before 0.6, re-run setup once (ask your assistant to "run mason_init again") — it refreshes the marker-delimited CLAUDE.md section that routes assistants to the new tools.
26
22
 
27
- ## Quick start
23
+ > **0.4.0 note:** Mason is MCP-only as of v0.4.0. The previous `mason <command>` CLI has been removed — everything runs through MCP tools, driven by your assistant. See [0.4.0 migration](#040-migration) below if you used the old CLI.
28
24
 
29
- ```bash
30
- claude mcp add mason --scope user -- npx -p mason-context mason-mcp
31
- ```
25
+ ---
26
+
27
+ ## The pain
28
+
29
+ Agentic search keeps getting better at re-deriving what's *in* the code — but three kinds of context can't be re-derived, and today they evaporate:
32
30
 
33
- Restart Claude Code, then ask: *"use mason to analyze this project and create a snapshot."*
31
+ - **Decisions.** "We tried retrying 401s in 2023; it locked accounts." Your assistant re-suggests it next sprint, in every teammate's session.
32
+ - **History.** Which files change together, which dirs are dead — knowledge that lives in thousands of commits, too expensive to mine per session.
33
+ - **Freshness.** Any cached understanding — a wiki, a CLAUDE.md, a map — rots silently, and a confidently wrong assistant is worse than a slow one.
34
34
 
35
- That's it — Mason will analyze your codebase and create a concept map. Next session, it loads the map instead of re-exploring everything.
35
+ ## The fix
36
36
 
37
- ## How it works
37
+ Mason is an MCP server that maintains three git-committed, deterministic stores and assembles them per task:
38
38
 
39
- ### Concept map
39
+ - **Concept map** (`.mason/snapshot.json`) — features and flows → files, built by your assistant, spot-checked by `verify_snapshot`
40
+ - **Decision records** (`.mason/decisions/`) — team knowledge the code can't express, captured by `save_decision`, PR-reviewed like code
41
+ - **Drift engine** — LLM-free proof of what's stale, per entry, with a self-maintaining refresh loop for CI
40
42
 
41
- Mason's core feature. It persists a feature-to-file map in `.mason/snapshot.json` that survives across conversations. When the LLM needs to understand your project, it reads this map instead of grepping through your entire codebase:
43
+ Ask your assistant to do a task and one `get_context` call returns the relevant features, files, tests, blast radius (git co-change + references), matching decisions, and a freshness verdict. The map itself:
42
44
 
43
45
  ```json
44
46
  {
@@ -55,76 +57,231 @@ Mason's core feature. It persists a feature-to-file map in `.mason/snapshot.json
55
57
  }
56
58
  ```
57
59
 
58
- The map is generated by the LLM itself — Mason provides the analysis tools, and the LLM interprets your code to decide what the features and flows are. This means the map captures architectural understanding, not just file listings.
60
+ The assistant jumps straight to the relevant files instead of exploring.
59
61
 
60
- Create one by asking your AI assistant to *"create a mason snapshot"*, or via CLI:
62
+ **Where the map comes from:** Mason doesn't parse your code. Your assistant reads the project through Mason's analysis tools and writes the map itself — capturing architectural intent, not just symbols and call edges. Setup also adds a short section to your CLAUDE.md so every future session (any assistant, any teammate) consults the stores before exploring.
61
63
 
62
- ```bash
63
- mason set-llm gemini # configure a provider (no API key needed)
64
- mason snapshot ~/my-project # generate concept map
65
- mason snapshot --install-hook # auto-update on every commit
66
- ```
64
+ ## What the numbers say
65
+
66
+ Measured with real headless agent sessions in A/B arms (baseline always has a populated CLAUDE.md — beating a context-free agent is not a result). Full harness, pinned commits, and losses included: [bench/harness/](bench/harness/).
67
+
68
+ - **Where Mason wins — knowledge that isn't in the code.** On tasks whose correct answer hinges on a recorded engineering decision (seeded fairly: the baseline had the same facts in a discoverable doc), Mason averaged **9.0/10 vs 7.0/10**. The baseline missed the constraint entirely half the time, and needed ~3× the turns when it found it; Mason surfaced it in one `get_context` call, every time.
69
+ - **Stale-map safety.** Against a deliberately stale map, the drift flag + changed-file previews led the agent to verify and answer current-code truth — the "confidently wrong from a stale cache" failure did not occur.
70
+ - **Where it's a wash — and we say so.** On questions agents can answer by reading code, quality is parity across hono (186 files), vuejs/core (483), and nestjs/nest (1676): 8.7–8.8 both arms, with Mason slightly *behind* on nest (8.5 vs 8.8). If your only questions are "how does X work", modern agents don't need a map.
71
+ - **Cost of ownership, measured.** Map builds scale linearly at ~$1.20 per 100 files (Sonnet): $3.22 for hono, $5.63 for vue-core, $19.52 for nest. Incremental refreshes after drift are cents.
72
+
73
+ ## Decision records
74
+
75
+ The store that makes Mason more than a map. When your assistant learns something the code can't express — a failed approach, a deprecation, a workaround's reason, a review-settled convention — it records it with `save_decision`:
76
+
77
+ - One JSON file per record in `.mason/decisions/` — concurrent additions merge cleanly; conflicting edits to the same record surface to a human, which is the point
78
+ - Git-committed and PR-reviewed: nothing enters team knowledge without the normal review gate
79
+ - Anchored to files and drift-checked: when the anchor files change, the record is flagged for re-verification instead of silently going stale
80
+ - Surfaced by `get_context` as constraints exactly when a task touches them — for every teammate, in every session, on any assistant
81
+
82
+ ## MCP tools
83
+
84
+ | Tool | Purpose |
85
+ |---|---|
86
+ | `mason_init` | **Start here.** Returns the Map-Reduce setup playbook. Idempotent. |
87
+ | `mason_complete_init` | Marks the project as initialized once the playbook is done. |
88
+ | `generate_snapshot_batch` | Map step — returns one batch of files for the assistant to summarize. |
89
+ | `save_partial_snapshot` | Persists the partial map for one batch. |
90
+ | `reduce_snapshot` | Reduce step — returns every partial + instructions to merge into a unified map. |
91
+ | `save_snapshot` | Persist the final unified map. Clears partials. |
92
+ | `mason_set_confluence` | Configure Confluence credentials — two-step: list spaces, then persist. |
93
+ | `export_to_confluence` | Sync the concept map to Confluence as PM-readable wiki pages. |
94
+ | `get_snapshot` | **First call for any architecture question.** Loads the concept map — feature → file lookup — in one LLM-free call. |
95
+ | `get_context` | **First call for any task or bug.** Matching features + files + tests + blast radius + freshness + recorded decisions, in one call. |
96
+ | `save_decision` | Record knowledge the code can't express — failed approaches, deprecations, conventions. Git-committed, PR-reviewed, drift-checked. |
97
+ | `mason_check_drift` | Feature-level staleness report — what changed since the snapshot, and whether to refresh incrementally or rebuild. |
98
+ | `verify_snapshot` | Spot-check map correctness — sampled entries + file skeletons for the assistant to judge, least-recently-verified first. |
99
+ | `save_verification` | Record verification verdicts — failures flag entries for re-mapping until fixed. |
100
+ | `get_impact` | **Call before editing a file.** Traces what's affected — co-change history + references + related tests. |
101
+ | `analyze_project` | Git stats — hot files, stale dirs, commit conventions. |
102
+ | `full_analysis` | One-shot orientation for unmapped projects: structure + samples + tests + git. |
103
+ | `get_code_samples` | Smart file previews selected by architectural role. |
67
104
 
68
- ### Change impact analysis
105
+ The init / write tools refuse to run until `mason_init` has completed. The read-only diagnostics (`analyze_project`, `full_analysis`, `get_code_samples`) work without init.
69
106
 
70
- Before editing a file, Mason can tell you what else might be affected. It combines three signals that would each require multiple tool calls to gather manually:
107
+ Setup also offers to add a short marker-delimited section to your project's CLAUDE.md telling assistants to consult the map before exploring assistants follow project instructions far more reliably than they discover MCP tools on their own.
71
108
 
72
- - **Co-change history** files that historically change together in git commits
109
+ ### How the concept map is built
110
+
111
+ To stay accurate on codebases of any size, Mason uses a **Map-Reduce** pattern instead of stuffing the whole codebase into one LLM call:
112
+
113
+ - **Map**: `generate_snapshot_batch` returns ~50 files at a time (skeletons of every file in the batch plus a few deeper-read bodies for grounding). Your assistant produces a partial concept map for that batch and persists it with `save_partial_snapshot`. Repeat until every file in the project has been visited.
114
+ - **Reduce**: `reduce_snapshot` returns all the partials plus instructions to merge them into one product-shaped catalog — combining platform variants ("home Android" + "home iOS" → "home screen"), deduplicating, and ensuring no file is dropped.
115
+ - **Save**: `save_snapshot` persists the unified map and cleans up the partials.
116
+
117
+ The result: every source file is represented exactly once in the final snapshot. A 200-file project takes ~5 batches; a 1000-file monorepo takes ~20.
118
+
119
+ ## Change impact
120
+
121
+ Before editing a file, Mason tells you what else might be affected. Three signals you'd normally need a dozen tool calls to gather, in one call:
122
+
123
+ - **Co-change history** — files that historically change together in commits
73
124
  - **References** — files that import or mention the target by name
74
- - **Related tests** — test files paired to the target by naming convention
125
+ - **Related tests** — test files paired by naming convention
126
+
127
+ Ask your assistant *"what would be affected if I changed WeatherRepository?"* and it'll call `get_impact` for you.
128
+
129
+ ## Drift detection
130
+
131
+ A concept map that silently goes stale is worse than no map — your assistant confidently jumps to files that no longer do what the map says. `mason_check_drift` compares the map against HEAD (pure git + filesystem, no LLM call) and reports drift at the **feature level**: which features are stale and which files changed under them, new source files not yet mapped, ghost files the map still references, and renames. It ends with a recommendation — `up-to-date`, `incremental` (re-map just the stale entries), or `full-rebuild` (re-run the Map-Reduce playbook).
132
+
133
+ Ask your assistant *"is the concept map still fresh?"* — and if it isn't, the same report tells it exactly which entries to regenerate. `get_snapshot` includes the same drift report whenever it detects a stale map, so a stale map self-heals in the course of normal use.
134
+
135
+ Incremental refreshes are safe against partial updates: every entry a refresh touches is stamped with the commit it was verified against, so entries skipped in one refresh keep reporting as stale instead of silently riding along on the map's new hash. Features that disappear from the codebase can be deleted from the map with `save_snapshot`'s `removeFeatures`/`removeFlows` — renames stop leaving zombie entries behind.
136
+
137
+ When a lot of files drifted at once, the assistant runs a **scoped refresh** instead of a full rebuild: `generate_snapshot_batch` accepts a `files` list, so the Map-Reduce loop walks only the drifted files and the reduce step merges the result into the existing map. 60 drifted files in a 1000-file monorepo means ~2 batches, not 20.
138
+
139
+ ### Drift checks in CI
140
+
141
+ Because the check is deterministic, it also ships as a tiny standalone binary — the one exception to "MCP-only", read-only and LLM-free:
75
142
 
76
143
  ```bash
77
- mason impact WeatherRepository.kt -d ~/my-project
144
+ npx -p mason-context mason-drift --dir . # exit 0 fresh · 1 stale · 2 error
145
+ npx -p mason-context mason-drift --json # full report as JSON
146
+ npx -p mason-context mason-drift --refresh-prompt # stale? print refresh instructions for any agent
78
147
  ```
79
148
 
80
- Also available as the `get_impact` MCP toolask your assistant *"what would be affected if I changed WeatherRepository?"*
149
+ Run it on merges to main to catch a rotting map before your assistant does. Note: the diff is computed against the snapshot's base commit, so shallow CI checkouts need enough `fetch-depth` to reach it when they don't, `mason-drift` reports stale with `full-rebuild` rather than guessing.
81
150
 
82
- ### Git history analysis
151
+ ### The map maintains itself
83
152
 
84
- Mason aggregates hundreds of commits into actionable stats: which files change most often (hot files you should be careful with), which directories haven't been touched in months (potentially stale code), and what commit conventions the team follows. This is the kind of analysis that would take dozens of `git log` calls to compute manually.
153
+ Detection is free and deterministic; the fix needs an LLM but not any particular one. `mason-drift --refresh-prompt` emits provider-neutral instructions that any coding agent with the Mason MCP server connected can execute. Pipe it to whichever headless CLI your team runs:
85
154
 
86
155
  ```bash
87
- mason analyze ~/my-project
156
+ # Claude Code
157
+ claude -p "$(mason-drift --refresh-prompt)" --dangerously-skip-permissions \
158
+ --mcp-config '{"mcpServers":{"mason":{"command":"npx","args":["-y","-p","mason-context","mason-mcp"]}}}'
159
+
160
+ # OpenAI Codex CLI (mason configured in ~/.codex/config.toml)
161
+ codex exec --full-auto "$(mason-drift --refresh-prompt)"
162
+
163
+ # Gemini CLI (mason configured in .gemini/settings.json)
164
+ gemini --yolo -p "$(mason-drift --refresh-prompt)"
88
165
  ```
89
166
 
90
- ## MCP tools
167
+ To close the loop in CI, this repo ships a reusable GitHub Actions workflow — detect on every push, refresh with your agent of choice, commit the updated map back:
168
+
169
+ ```yaml
170
+ jobs:
171
+ mason:
172
+ uses: adrianczuczka/mason/.github/workflows/mason-refresh.yml@main
173
+ with:
174
+ agent-command: >-
175
+ claude -p "$MASON_REFRESH_PROMPT" --dangerously-skip-permissions
176
+ --strict-mcp-config --mcp-config
177
+ '{"mcpServers":{"mason":{"command":"npx","args":["-y","-p","mason-context","mason-mcp"]}}}'
178
+ secrets: inherit
179
+ ```
91
180
 
92
- Mason exposes 6 tools via the Model Context Protocol. Any MCP-compatible client (Claude Code, Cursor, etc.) can use them:
181
+ Omit `agent-command` for detect-only mode: free, no credentials, fails the check when the map goes stale.
93
182
 
94
- | Tool | What it does |
95
- |---|---|
96
- | `get_snapshot` | Load the concept map — maps features/flows to files |
97
- | `save_snapshot` | Persist the concept map for future sessions |
98
- | `get_impact` | Change impact: co-change history, references, related tests |
99
- | `analyze_project` | Git history: commit patterns, hot files, stale dirs |
100
- | `full_analysis` | All-in-one first visit: git stats + structure + code samples + test map |
101
- | `get_code_samples` | Smart file previews selected by architectural role |
183
+ ## Confluence sync
102
184
 
103
- ## CLI usage
185
+ Keep a Confluence wiki in sync with the concept map, in plain product language that PMs and designers can read. Each sync rewrites the snapshot through your assistant into PM-friendly descriptions, pushes one page per feature, and posts a "what changed since last sync" entry to a changelog page. Mason owns these pages and overwrites each one on every sync, so edit the code, not the page — manual edits to a page body are replaced. Re-running a sync with no code change is a no-op: it makes no Confluence edits at all.
104
186
 
105
- Mason also works as a standalone CLI for generating CLAUDE.md files and running analysis without an MCP client. Configure an LLM provider once, then use any command:
187
+ Setup happens during `mason_init` (you'll be asked) or any time later by asking your assistant *"set up Confluence for this project."* The assistant walks you through the Atlassian site URL, your account email, and an API token from id.atlassian.com, then lets you pick which space to use. To sync, ask *"sync the wiki to Confluence."*
106
188
 
107
- ```bash
108
- mason set-llm claude|gemini|ollama|openai # configure provider
109
- mason generate # analyze codebase + LLM -> CLAUDE.md
110
- mason analyze # git stats only (no LLM needed)
111
- mason impact File.kt # change impact analysis
112
- mason snapshot # create/update concept map
189
+ > ⚠️ **Token in chat history.** The API token is pasted into your assistant chat, not a terminal. It will appear in your chat history. If that's not acceptable, skip Confluence sync.
190
+
191
+ ## Other clients
192
+
193
+ Mason's MCP server is client-agnostic. Pick yours:
194
+
195
+ <details>
196
+ <summary><strong>Cursor</strong></summary>
197
+
198
+ Add to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in your project):
199
+
200
+ ```json
201
+ {
202
+ "mcpServers": {
203
+ "mason": {
204
+ "command": "npx",
205
+ "args": ["-p", "mason-context", "mason-mcp"]
206
+ }
207
+ }
208
+ }
113
209
  ```
210
+ </details>
114
211
 
115
- Most providers work without an API key — `claude`, `gemini`, and `ollama` all use their respective CLIs directly.
212
+ <details>
213
+ <summary><strong>Windsurf</strong></summary>
116
214
 
117
- ## Security
215
+ Add to `~/.codeium/windsurf/mcp_config.json`:
118
216
 
119
- **What the snapshot contains:** Feature names, relative file paths, and flow descriptions. No source code, secrets, or business logic.
217
+ ```json
218
+ {
219
+ "mcpServers": {
220
+ "mason": {
221
+ "command": "npx",
222
+ "args": ["-p", "mason-context", "mason-mcp"]
223
+ }
224
+ }
225
+ }
226
+ ```
227
+ </details>
120
228
 
121
- **What it doesn't touch:** Mason respects `.gitignore` (via `git ls-files`) and has a deny-list that blocks `.env`, `.pem`, `.key`, credentials, and other sensitive files from being sampled. Path traversal protection ensures all file access stays within the project root.
229
+ <details>
230
+ <summary><strong>OpenAI Codex CLI</strong></summary>
122
231
 
123
- **LLM data flow:** Generating a snapshot via CLI sends sampled file contents to your configured LLM provider — the same way any AI coding assistant reads your code. Use `ollama` for fully local generation. The MCP server tools (`get_snapshot`, `get_impact`, etc.) only read local files.
232
+ Add to `~/.codex/config.toml`:
233
+
234
+ ```toml
235
+ [mcp_servers.mason]
236
+ command = "npx"
237
+ args = ["-p", "mason-context", "mason-mcp"]
238
+ ```
239
+ </details>
240
+
241
+ <details>
242
+ <summary><strong>VS Code</strong></summary>
243
+
244
+ Add to your VS Code settings (`settings.json`):
245
+
246
+ ```json
247
+ {
248
+ "mcp": {
249
+ "servers": {
250
+ "mason": {
251
+ "command": "npx",
252
+ "args": ["-p", "mason-context", "mason-mcp"]
253
+ }
254
+ }
255
+ }
256
+ }
257
+ ```
258
+ </details>
124
259
 
125
260
  ## Language support
126
261
 
127
- Mason is completely language-agnostic. It uses file naming patterns and git history rather than language-specific parsing, so it works with any project that has source files and a git repository — TypeScript, Kotlin, Python, Go, Rust, Swift, Java, C#, Dart, and more.
262
+ Language-agnostic. Mason works from file naming patterns and git history rather than language-specific parsing, so it runs on any project with a git repo — TypeScript, Kotlin, Python, Go, Rust, Swift, Java, C#, Dart, and more.
263
+
264
+ ## Security
265
+
266
+ - **The snapshot contains:** feature names, relative file paths, flow descriptions. No source code, no secrets, no business logic.
267
+ - **Respects `.gitignore`** via `git ls-files`. A deny-list blocks `.env`, `.pem`, `.key`, credentials, and other sensitive files from being sampled.
268
+ - **Path traversal protection** keeps all file access inside the project root.
269
+ - **MCP tools are local-only.** Generating a snapshot via MCP uses your assistant's existing LLM context — Mason itself makes no API calls.
270
+
271
+ ## 0.4.0 migration
272
+
273
+ If you used Mason before v0.4.0, the standalone `mason <command>` CLI has been removed. Everything now runs through MCP tools, called by your assistant.
274
+
275
+ | Old CLI | New flow |
276
+ |---|---|
277
+ | `mason set-llm <provider>` | Not needed — your assistant *is* the LLM. |
278
+ | `mason snapshot` | Ask your assistant: *"set up Mason here"* → it calls `mason_init` → `generate_snapshot` → `save_snapshot`. |
279
+ | `mason generate` (CLAUDE.md) | Removed. Use your assistant directly. |
280
+ | `mason analyze` | Ask your assistant: *"give me git stats for this repo"* — it calls `analyze_project`. |
281
+ | `mason impact File.kt` | Ask your assistant: *"what would changing File.kt affect?"* — it calls `get_impact`. |
282
+ | `mason snapshot --install-hook` | Removed. The map auto-refreshes when the assistant detects stale state. |
283
+
284
+ The npm package is still published, but only the `mason-mcp` binary is meaningful now. Running `mason` directly prints a migration message and exits.
128
285
 
129
286
  ## License
130
287