claude-augur-mcp 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vivek Menon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,292 @@
1
+ <img align="right" src="claude-augur.svg" alt="claude-augur-mcp" width="220">
2
+
3
+ # claude-augur-mcp
4
+
5
+ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for **plan reasoning summaries** in [Claude Code](https://docs.anthropic.com/en/docs/claude-code). Surfaces decisions, tradeoffs, and assumptions as scannable abstracts so you can correct Claude's reasoning at a glance.
6
+
7
+ <br clear="right">
8
+
9
+ ![claude-augur-mcp](demo/demo.gif)
10
+
11
+ [![npm version](https://img.shields.io/npm/v/claude-augur-mcp.svg)](https://www.npmjs.com/package/claude-augur-mcp) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org/) [![Claude](https://img.shields.io/badge/Claude-D97757?logo=claude&logoColor=fff)](#) [![GitHub stars](https://img.shields.io/github/stars/Vvkmnn/claude-augur-mcp?style=social)](https://github.com/Vvkmnn/claude-augur-mcp)
12
+
13
+ ---
14
+
15
+ Claude's reasoning about plans is invisible. When Claude writes a plan, its decisions, assumptions, and tradeoffs are buried in the document — you have to read the entire thing to find them. If Claude assumed the wrong approach or made a bad tradeoff, you won't know until implementation is underway and something breaks.
16
+
17
+ Augur reads the plan structure and returns a template that Claude fills with its actual reasoning — inline in the response, not hidden in a collapsed tool result. You see decisions, assumptions, and tradeoffs at a glance and can correct them before a single line of code is written.
18
+
19
+ ## install
20
+
21
+ **Requirements:**
22
+
23
+ [![Claude Code](https://img.shields.io/badge/Claude_Code-555?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOCAxMCIgc2hhcGUtcmVuZGVyaW5nPSJjcmlzcEVkZ2VzIj4KICA8IS0tIENsYXdkOiBDbGF1ZGUgQ29kZSBtYXNjb3QgLS0+CiAgPCEtLSBEZWNvZGVkIGZyb206IOKWkOKWm+KWiOKWiOKWiOKWnOKWjCAvIOKWneKWnOKWiOKWiOKWiOKWiOKWiOKWm+KWmCAvIOKWmOKWmCDilp3ilp0gLS0+CiAgPCEtLSBTdWItcGl4ZWxzIGFyZSAxIHdpZGUgeCAyIHRhbGwgdG8gbWF0Y2ggdGVybWluYWwgY2hhciBjZWxsIGFzcGVjdCByYXRpbyAtLT4KICA8cmVjdCBmaWxsPSIjZDk3NzU3IiB4PSIzIiAgeT0iMCIgd2lkdGg9IjEyIiBoZWlnaHQ9IjIiLz4KICA8cmVjdCBmaWxsPSIjZDk3NzU3IiB4PSIzIiAgeT0iMiIgd2lkdGg9IjIiICBoZWlnaHQ9IjIiLz4KICA8cmVjdCBmaWxsPSIjZDk3NzU3IiB4PSI2IiAgeT0iMiIgd2lkdGg9IjYiICBoZWlnaHQ9IjIiLz4KICA8cmVjdCBmaWxsPSIjZDk3NzU3IiB4PSIxMyIgeT0iMiIgd2lkdGg9IjIiICBoZWlnaHQ9IjIiLz4KICA8cmVjdCBmaWxsPSIjZDk3NzU3IiB4PSIxIiAgeT0iNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjIiLz4KICA8cmVjdCBmaWxsPSIjZDk3NzU3IiB4PSIzIiAgeT0iNiIgd2lkdGg9IjEyIiBoZWlnaHQ9IjIiLz4KICA8cmVjdCBmaWxsPSIjZDk3NzU3IiB4PSI0IiAgeT0iOCIgd2lkdGg9IjEiICBoZWlnaHQ9IjIiLz4KICA8cmVjdCBmaWxsPSIjZDk3NzU3IiB4PSI2IiAgeT0iOCIgd2lkdGg9IjEiICBoZWlnaHQ9IjIiLz4KICA8cmVjdCBmaWxsPSIjZDk3NzU3IiB4PSIxMSIgeT0iOCIgd2lkdGg9IjEiICBoZWlnaHQ9IjIiLz4KICA8cmVjdCBmaWxsPSIjZDk3NzU3IiB4PSIxMyIgeT0iOCIgd2lkdGg9IjEiICBoZWlnaHQ9IjIiLz4KPC9zdmc+Cg==)](https://claude.ai/code)
24
+
25
+ **From shell:**
26
+
27
+ ```bash
28
+ claude mcp add claude-augur-mcp -- npx claude-augur-mcp
29
+ ```
30
+
31
+ **From inside Claude** (restart required):
32
+
33
+ ```
34
+ Add this to our global mcp config: npx claude-augur-mcp
35
+
36
+ Install this mcp: https://github.com/Vvkmnn/claude-augur-mcp
37
+ ```
38
+
39
+ **From any manually configurable `mcp.json`**: (Cursor, Windsurf, etc.)
40
+
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "claude-augur-mcp": {
45
+ "command": "npx",
46
+ "args": ["claude-augur-mcp"],
47
+ "env": {}
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ There is **no `npm install` required** — no external databases, no indexing, only Node.js built-ins for filesystem access.
54
+
55
+ However, if `npx` resolves the wrong package, you can force resolution with:
56
+
57
+ ```bash
58
+ npm install -g claude-augur-mcp
59
+ ```
60
+
61
+ ## features
62
+
63
+ 1 tool. Plan structure extraction. Template seeding. Inline rendering.
64
+
65
+ #### augur_explain
66
+
67
+ Read a plan file and return a structured template for Claude to fill with its reasoning. Claude renders the abstract **inline in its response** — not hidden in a collapsed tool result.
68
+
69
+ **Call after writing or editing a plan file:**
70
+
71
+ ```
72
+ augur_explain plan_path="/Users/you/.claude/plans/your-plan.md"
73
+ ```
74
+
75
+ **MCP returns two content blocks:**
76
+
77
+ Block 1 — one-line summary, visible even when the tool result is collapsed:
78
+
79
+ ```
80
+ your-plan.md · 10/18 done
81
+ ```
82
+
83
+ Block 2 — template with pre-rendered header, progress, and `[FILL]` markers:
84
+
85
+ ```
86
+ ┌ 📐 my-project · your-plan.md ────────────────────────────────────
87
+ │ Build a REST API with authentication, rate limiting,
88
+ │ and WebSocket support for real-time notifications.
89
+
90
+ ├ Progress ───────────────────────────────────────────────────────
91
+ │ Done (10/18): Auth scaffold, Rate limiter + 1 more
92
+ │ Next: WebSocket layer + 1 more
93
+
94
+ ├ Decisions ──────────────────────────────────────────────────────
95
+ │ [FILL: 2-4 decisions, format: "✓ choice — reason"]
96
+ │ [child decisions use: " └ choice — reason"]
97
+
98
+ ├ Assumptions ────────────────────────────────────────────────────
99
+ │ [FILL: 1-2 assumptions, format: "? statement"]
100
+
101
+ ├ Tradeoffs ──────────────────────────────────────────────────────
102
+ │ [FILL: 1-2 lines, "+" for pro, "−" for con]
103
+
104
+ ├ Reasoning ──────────────────────────────────────────────────────
105
+ │ [FILL: 2-3 lines explaining WHY]
106
+ └──────────────────────────────────────────────────────────────────
107
+ ```
108
+
109
+ **Claude fills the template inline:**
110
+
111
+ ```
112
+ ┌ 📐 my-project · your-plan.md ────────────────────────────────────
113
+ │ Build a REST API with authentication, rate limiting,
114
+ │ and WebSocket support for real-time notifications.
115
+
116
+ ├ Progress ───────────────────────────────────────────────────────
117
+ │ Done (10/18): Auth scaffold, Rate limiter + 1 more
118
+ │ Next: WebSocket layer + 1 more
119
+
120
+ ├ Decisions ──────────────────────────────────────────────────────
121
+ │ ✓ Express over Fastify — team familiarity, middleware ecosystem
122
+ │ └ Passport.js for auth — proven, supports OAuth + JWT
123
+ │ ✓ Redis for rate limiting — atomic counters, TTL built-in
124
+ │ ✓ ws over Socket.io — lighter, no fallback polling needed
125
+
126
+ ├ Assumptions ────────────────────────────────────────────────────
127
+ │ ? Single Redis instance sufficient for current scale
128
+ │ ? WebSocket clients handle reconnection gracefully
129
+
130
+ ├ Tradeoffs ──────────────────────────────────────────────────────
131
+ │ + Redis rate limiting: sub-ms response, horizontal scaling
132
+ │ − Extra infrastructure dependency to operate
133
+
134
+ ├ Reasoning ──────────────────────────────────────────────────────
135
+ │ Auth must be production-grade from day one — Passport.js
136
+ │ handles OAuth/JWT without custom crypto. Redis rate limiting
137
+ │ chosen over in-memory because the API will be multi-process.
138
+ │ ws chosen over Socket.io to avoid 200KB bundle overhead.
139
+ └──────────────────────────────────────────────────────────────────
140
+ ```
141
+
142
+ **What gets extracted from the plan file:**
143
+
144
+ | Field | Source | Example |
145
+ | --- | --- | --- |
146
+ | Project name | H1 title before `:` | `my-project` |
147
+ | Purpose | First `**Primary goal**:` line, or first prose paragraph | Full text, word-wrapped |
148
+ | Sections | H2 headings (excluding `Detail:` sections) | `Context, Architecture, ...` |
149
+ | Progress | `### Step N:` headings with `- [x]` / `- [ ]` counts | `Done (10/18): Auth, Rate limiter` |
150
+ | Done steps | Steps where all items are `[x]` | Capped at 2 names + `N more` |
151
+ | Next steps | Steps with pending items | First name + `N more` |
152
+
153
+ ## methodology
154
+
155
+ How [claude-augur-mcp](https://github.com/Vvkmnn/claude-augur-mcp) [reads](https://github.com/Vvkmnn/claude-augur-mcp/tree/main/src) plans:
156
+
157
+ ```
158
+ 📐 claude-augur-mcp
159
+ ━━━━━━━━━━━━━━━━━━━
160
+
161
+ Claude writes a plan
162
+ augur_explain
163
+
164
+
165
+ ┌─────────────────┐
166
+ │ read plan file │ from disk (read-only)
167
+ │ (session.ts) │
168
+ └────────┬────────┘
169
+
170
+ ├── title → project name (before ":")
171
+ ├── purpose → **Primary goal**: or first prose
172
+ ├── sections → H2 headings
173
+ └── progress → ### Step N: with [x]/[ ] counts
174
+
175
+ ┌────────▼────────┐
176
+ │ render template │ left-gutter format
177
+ │ (render.ts) │ [FILL] markers for Claude
178
+ └────────┬────────┘
179
+
180
+ ┌────────────┴────────────┐
181
+ ▼ ▼
182
+ block 1 block 2
183
+ summary template
184
+ (visible collapsed) (Claude renders inline)
185
+ │ │
186
+ ▼ ▼
187
+ plan.md · 10/18 done ┌ 📐 project · plan.md ──
188
+ │ purpose...
189
+ ├ Progress ────────────
190
+ │ Done (10/18): Auth + 1
191
+ ├ Decisions ───────────
192
+ │ [FILL]
193
+ ├ Assumptions ─────────
194
+ │ [FILL]
195
+ └──────────────────────
196
+
197
+
198
+ TEMPLATE SEEDING:
199
+
200
+ Regex extraction of Claude's thinking blocks produces garbage —
201
+ free-form prose has no structured patterns to match.
202
+
203
+ Augur takes a different approach: extract plan structure (the
204
+ deterministic part), seed a template, let Claude fill reasoning
205
+ (the part only Claude knows). Structure from MCP, content from
206
+ Claude. Consistent format, accurate reasoning.
207
+
208
+ MCP pre-renders Claude fills
209
+ ────────────── ────────────
210
+ header + purpose decisions
211
+ progress counts assumptions
212
+ section labels tradeoffs
213
+ formatting rules reasoning
214
+ ```
215
+
216
+ **Two-block return**: MCP tool results get collapsed in Claude Code UI. Block 1 is a one-line summary visible even when collapsed. Block 2 is the full template that Claude renders inline in its response — visible to the user without expanding.
217
+
218
+ **Read-only**: `augur_explain` only reads the plan file. No disk writes, no state, no side effects. Works in plan mode.
219
+
220
+ **Architecture:**
221
+
222
+ ```
223
+ claude-augur-mcp/
224
+ ├── package.json
225
+ ├── tsconfig.json
226
+ ├── src/
227
+ │ ├── index.ts # MCP server, 1 tool
228
+ │ ├── types.ts # PlanStructure interface
229
+ │ ├── session.ts # Plan file parser + step progress extractor
230
+ │ └── render.ts # Template generator with left-gutter format
231
+ └── demo/
232
+ ├── demo.cast # asciinema recording
233
+ └── demo.gif # animated demo
234
+ ```
235
+
236
+ **Design principles:**
237
+
238
+ - **Template seeding over regex extraction** — regex on thinking blocks produced garbage; template seeding lets Claude fill its own reasoning accurately
239
+ - **Inline over collapsed** — tool results get collapsed in Claude Code UI; inline rendering keeps the abstract visible
240
+ - **Read-only** — no disk writes, no state, works in plan mode
241
+ - **Single tool** — `augur_explain` does one thing well; no CRUD, no storage, no insight management
242
+ - **Left-gutter format** — `┌│├└` vertical bar with no right border; can't misalign, renders cleanly in any terminal width
243
+ - **Never truncate** — purpose and header always render in full; word-wrapped, never cut
244
+
245
+ **Design influences:**
246
+
247
+ - [Architecture Decision Records](https://adr.github.io/) — structured format for capturing decisions with context and consequences
248
+ - [Y-Statement ADR variant](https://medium.com/olzzio/y-statements-10eb07b5a177) — concise decision format: "In context X, facing Y, we decided Z, accepting C"
249
+ - Roman [Augurs](https://en.wikipedia.org/wiki/Augur) — priests who interpreted signs and patterns to reveal meaning hidden from ordinary observation
250
+
251
+ ## development
252
+
253
+ ```bash
254
+ git clone https://github.com/Vvkmnn/claude-augur-mcp && cd claude-augur-mcp
255
+ npm install && npm run build
256
+ ```
257
+
258
+ **Scripts:**
259
+
260
+ | Command | Description |
261
+ | --- | --- |
262
+ | `npm run build` | TypeScript compilation (`tsc && chmod +x dist/index.js`) |
263
+ | `npm run dev` | Watch mode (`tsc --watch`) |
264
+ | `npm start` | Run MCP server (`node dist/index.js`) |
265
+ | `npm run clean` | Remove build artifacts (`rm -rf dist`) |
266
+ | `npm run typecheck` | TypeScript validation without emit |
267
+ | `npm test` | Type-check |
268
+
269
+ Contributing:
270
+
271
+ - Fork the repository and create feature branches
272
+ - Follow TypeScript strict mode and [MCP protocol](https://modelcontextprotocol.io/specification) standards
273
+
274
+ Learn from examples:
275
+
276
+ - [Official MCP servers](https://github.com/modelcontextprotocol/servers) for reference implementations
277
+ - [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) for best practices
278
+ - [Creating Node.js modules](https://docs.npmjs.com/creating-node-js-modules) for npm package development
279
+
280
+ ## license
281
+
282
+ [MIT](LICENSE)
283
+
284
+ <hr>
285
+
286
+ <p align="center"><a href="https://en.wikipedia.org/wiki/Tomb_of_the_Augurs"><img src="logo/tomb-of-the-augurs.jpg" alt="Tomb of the Augurs" width="340"></a></p>
287
+
288
+ <p align="center">
289
+
290
+ _**[Tomb of the Augurs](https://en.wikipedia.org/wiki/Tomb_of_the_Augurs)**, fresco (Tarquinia, ~530 BCE). Claudius — emperor, scholar, and member of the Augural College — wrote [Tyrrenika](https://en.wikipedia.org/wiki/Tyrrenika), a lost 20-volume history of Etruscan civilization and their methods of divination. The augurs' role was not to predict the future, but to interpret the signs and reveal whether a proposed course of action had merit._
291
+
292
+ </p>
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP server for claude-augur-mcp.
4
+ *
5
+ * Single tool: augur_explain — extract plan structure,
6
+ * return template for Claude to fill inline.
7
+ */
8
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP server for claude-augur-mcp.
4
+ *
5
+ * Single tool: augur_explain — extract plan structure,
6
+ * return template for Claude to fill inline.
7
+ */
8
+ import { createRequire } from 'module';
9
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
10
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
11
+ import { z } from 'zod';
12
+ import { readFileSync } from 'node:fs';
13
+ import { extractPlanStructure } from './session.js';
14
+ import { renderTemplate, renderSummary } from './render.js';
15
+ const require = createRequire(import.meta.url);
16
+ const { version } = require('../package.json');
17
+ const SERVER_INSTRUCTIONS = `\ud83d\udcd0 Augur \u2014 Plan Reasoning
18
+
19
+ Surface Claude's reasoning chain as scannable summaries:
20
+ \u2022 augur_explain(plan_path) \u2014 Extract decisions, tradeoffs, assumptions and render as ASCII summary
21
+
22
+ After writing/editing plan files, call augur_explain to generate a reasoning abstract.
23
+ Insights use \u2605 Insight boxes. Save notable discoveries with augur_save.`;
24
+ const server = new McpServer({ name: 'claude-augur-mcp', version }, { instructions: SERVER_INSTRUCTIONS });
25
+ server.tool('augur_explain', 'Extract plan structure and return a template for inline rendering. Call after writing/editing plan files. Render the filled template INLINE in your response (not in a code block).', {
26
+ plan_path: z.string().describe('Absolute path to the plan file'),
27
+ }, async ({ plan_path }) => {
28
+ let planContent;
29
+ try {
30
+ planContent = readFileSync(plan_path, 'utf-8');
31
+ }
32
+ catch {
33
+ return { content: [{ type: 'text', text: `Error: Cannot read plan file at ${plan_path}` }] };
34
+ }
35
+ const structure = extractPlanStructure(planContent);
36
+ const summary = renderSummary(structure, plan_path);
37
+ const template = renderTemplate(structure, plan_path);
38
+ return {
39
+ content: [
40
+ { type: 'text', text: summary },
41
+ { type: 'text', text: template },
42
+ ],
43
+ };
44
+ });
45
+ async function main() {
46
+ const transport = new StdioServerTransport();
47
+ await server.connect(transport);
48
+ }
49
+ main().catch((error) => {
50
+ console.error('Fatal error:', error);
51
+ process.exit(1);
52
+ });
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAEtE,MAAM,mBAAmB,GAAG;;;;;;6EAMiD,CAAC;AAE9E,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,EACrC,EAAE,YAAY,EAAE,mBAAmB,EAAE,CACtC,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,qLAAqL,EACrL;IACE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;CACjE,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;IACtB,IAAI,WAAmB,CAAC;IACxB,IAAI,CAAC;QACH,WAAW,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,mCAAmC,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC;IACxG,CAAC;IAED,MAAM,SAAS,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,aAAa,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAEtD,OAAO;QACL,OAAO,EAAE;YACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,EAAE;YACxC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC1C;KACF,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Template generator for plan abstracts.
3
+ *
4
+ * Generates a left-gutter format with section headers and [FILL] markers.
5
+ * MCP pre-renders header, purpose, and progress.
6
+ * Claude fills decisions, assumptions, tradeoffs, reasoning inline.
7
+ */
8
+ import type { PlanStructure } from './types.js';
9
+ export declare function renderTemplate(structure: PlanStructure, planPath: string): string;
10
+ export declare function renderSummary(structure: PlanStructure, planPath: string): string;
package/dist/render.js ADDED
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Template generator for plan abstracts.
3
+ *
4
+ * Generates a left-gutter format with section headers and [FILL] markers.
5
+ * MCP pre-renders header, purpose, and progress.
6
+ * Claude fills decisions, assumptions, tradeoffs, reasoning inline.
7
+ */
8
+ const W = 66;
9
+ const CONTENT_W = W - 2; // width after "│ " prefix
10
+ /** Word-wrap text to multiple lines — never truncates, always includes all words */
11
+ function wrap(text, maxWidth) {
12
+ const words = text.split(' ');
13
+ const lines = [];
14
+ let current = '';
15
+ for (const word of words) {
16
+ const test = current ? current + ' ' + word : word;
17
+ if (test.length > maxWidth && current) {
18
+ lines.push(current);
19
+ current = word;
20
+ }
21
+ else {
22
+ current = test;
23
+ }
24
+ }
25
+ if (current)
26
+ lines.push(current);
27
+ return lines;
28
+ }
29
+ /** Section header: ├ Name ─────────── (exact W width) */
30
+ function sec(name) {
31
+ const trail = '\u2500'.repeat(Math.max(3, W - name.length - 3));
32
+ return `\u251c ${name} ${trail}`;
33
+ }
34
+ export function renderTemplate(structure, planPath) {
35
+ const { project, purpose, doneLine, nextLine, sections } = structure;
36
+ const file = planPath.split('/').pop() || planPath;
37
+ // Header: ┌ 📐 project · file trail (never truncated)
38
+ const label = `${project} \u00b7 ${file}`;
39
+ const trail = '\u2500'.repeat(Math.max(3, W - label.length - 5));
40
+ const purposeLines = wrap(purpose, CONTENT_W).map(l => `\u2502 ${l}`).join('\n');
41
+ const sectionList = sections.slice(0, 6).join(', ');
42
+ return `Include this abstract in your response (not in a code block). Header and progress are pre-rendered \u2014 fill the remaining sections.
43
+
44
+ \u250c \ud83d\udcd0 ${label} ${trail}
45
+ ${purposeLines}
46
+ \u2502
47
+ ${sec('Progress')}
48
+ \u2502 ${doneLine}
49
+ \u2502 ${nextLine}
50
+ \u2502
51
+ ${sec('Decisions')}
52
+ \u2502 [FILL: 2-4 decisions, format: "\u2713 choice \u2014 reason"]
53
+ \u2502 [child decisions use: " \u2514 choice \u2014 reason"]
54
+ \u2502
55
+ ${sec('Assumptions')}
56
+ \u2502 [FILL: 1-2 assumptions, format: "? statement"]
57
+ \u2502
58
+ ${sec('Tradeoffs')}
59
+ \u2502 [FILL: 1-2 lines, "+" for pro, "\u2212" for con]
60
+ \u2502
61
+ ${sec('Reasoning')}
62
+ \u2502 [FILL: 2-3 lines explaining WHY]
63
+ \u2514${'\u2500'.repeat(W)}
64
+
65
+ Rules:
66
+ - Every content line starts with "\u2502 "
67
+ - ~60 chars max per line after "\u2502 "
68
+ - Terse: verb phrases, no articles, no filler
69
+ - Plan sections: ${sectionList}`;
70
+ }
71
+ export function renderSummary(structure, planPath) {
72
+ const { doneCount, itemCount } = structure;
73
+ const file = planPath.split('/').pop() || planPath;
74
+ return `\ud83d\udcd0 ${file} \u00b7 ${doneCount}/${itemCount} done`;
75
+ }
76
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Plan structure extractor.
3
+ *
4
+ * Reads plan files and extracts metadata for template generation.
5
+ * Computes progress lines (Done/Next) from step headings + checkboxes.
6
+ */
7
+ import type { PlanStructure } from './types.js';
8
+ /**
9
+ * Extract structured metadata from a plan file.
10
+ * Reads title, purpose, section headings, checkbox counts, and step progress.
11
+ */
12
+ export declare function extractPlanStructure(planContent: string): PlanStructure;
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Plan structure extractor.
3
+ *
4
+ * Reads plan files and extracts metadata for template generation.
5
+ * Computes progress lines (Done/Next) from step headings + checkboxes.
6
+ */
7
+ /** Truncate text at a word boundary, not mid-word */
8
+ function truncAtWord(text, maxLen) {
9
+ if (text.length <= maxLen)
10
+ return text;
11
+ const cut = text.substring(0, maxLen);
12
+ const sp = cut.lastIndexOf(' ');
13
+ return sp > maxLen * 0.4 ? cut.substring(0, sp) : cut;
14
+ }
15
+ /** Extract a short name from a step heading like "### Step 2: Pivot to template approach (from live test)" */
16
+ function extractStepName(heading) {
17
+ let name = heading.replace(/^###\s+/, '');
18
+ name = name.replace(/^Step\s+\d+:\s*/i, '');
19
+ name = name.replace(/\*\*/g, '');
20
+ // Cut at first delimiter for brevity
21
+ for (const sep of [' — ', ' - ', ' (', ' + ']) {
22
+ const idx = name.indexOf(sep);
23
+ if (idx > 0) {
24
+ name = name.substring(0, idx);
25
+ break;
26
+ }
27
+ }
28
+ // Trim trailing punctuation/spaces after word-boundary truncation
29
+ return truncAtWord(name.trim(), 18).replace(/[\s+\-]+$/, '');
30
+ }
31
+ /**
32
+ * Extract structured metadata from a plan file.
33
+ * Reads title, purpose, section headings, checkbox counts, and step progress.
34
+ */
35
+ export function extractPlanStructure(planContent) {
36
+ const lines = planContent.split('\n');
37
+ let title = 'Untitled Plan';
38
+ let purpose = '';
39
+ const sections = [];
40
+ let itemCount = 0;
41
+ let doneCount = 0;
42
+ let foundPurpose = false;
43
+ const steps = [];
44
+ let currentStep = null;
45
+ for (const line of lines) {
46
+ const trimmed = line.trim();
47
+ if (trimmed.startsWith('# ') && title === 'Untitled Plan') {
48
+ title = trimmed.replace(/^#\s+/, '');
49
+ continue;
50
+ }
51
+ if (trimmed.startsWith('## ')) {
52
+ const section = trimmed.replace(/^##\s+/, '');
53
+ if (!section.startsWith('Detail:')) {
54
+ sections.push(truncAtWord(section, 30));
55
+ }
56
+ }
57
+ if (trimmed.match(/^###\s+Step\s+\d/i)) {
58
+ if (currentStep)
59
+ steps.push(currentStep);
60
+ currentStep = { name: extractStepName(trimmed), items: 0, done: 0 };
61
+ }
62
+ if (trimmed.startsWith('- [')) {
63
+ itemCount++;
64
+ if (currentStep)
65
+ currentStep.items++;
66
+ if (trimmed.startsWith('- [x]')) {
67
+ doneCount++;
68
+ if (currentStep)
69
+ currentStep.done++;
70
+ }
71
+ }
72
+ if (!foundPurpose && trimmed.length > 15) {
73
+ const goalMatch = trimmed.match(/\*\*(?:Primary goal|How it works)\*\*:\s*(.+)/);
74
+ if (goalMatch) {
75
+ purpose = goalMatch[1];
76
+ foundPurpose = true;
77
+ }
78
+ else if (!purpose &&
79
+ !trimmed.startsWith('#') &&
80
+ !trimmed.startsWith('**Progress') &&
81
+ !trimmed.startsWith('-') &&
82
+ !trimmed.startsWith('|') &&
83
+ !trimmed.startsWith('```') &&
84
+ !trimmed.startsWith('---')) {
85
+ purpose = trimmed;
86
+ }
87
+ }
88
+ }
89
+ if (currentStep)
90
+ steps.push(currentStep);
91
+ // Build progress lines
92
+ const doneSteps = steps.filter(s => s.items > 0 && s.done === s.items).map(s => s.name);
93
+ const pendingSteps = steps.filter(s => s.items === 0 || s.done < s.items).map(s => s.name);
94
+ const doneNames = doneSteps.slice(0, 2).join(', ');
95
+ const doneExtra = doneSteps.length > 2 ? ` + ${doneSteps.length - 2} more` : '';
96
+ const doneLine = `Done (${doneCount}/${itemCount}): ${doneNames || 'none yet'}${doneExtra}`;
97
+ let nextLine;
98
+ if (pendingSteps.length === 0) {
99
+ nextLine = 'Next: all done!';
100
+ }
101
+ else if (pendingSteps.length === 1) {
102
+ nextLine = `Next: ${pendingSteps[0]}`;
103
+ }
104
+ else {
105
+ nextLine = `Next: ${pendingSteps[0]} + ${pendingSteps.length - 1} more`;
106
+ }
107
+ // Extract project name from title (before ":" if present)
108
+ const colonIdx = title.indexOf(':');
109
+ const project = colonIdx > 0 ? title.substring(0, colonIdx).trim() : title;
110
+ return {
111
+ title,
112
+ project,
113
+ purpose: purpose || 'No description',
114
+ sections,
115
+ itemCount,
116
+ doneCount,
117
+ doneLine,
118
+ nextLine,
119
+ };
120
+ }
121
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * JSONL storage for insights and explanations.
3
+ *
4
+ * Location: ~/.claude/teacher/
5
+ * insights.jsonl — persistent educational insights
6
+ * explanations.jsonl — plan reasoning history
7
+ */
8
+ import type { Insight, InsightDepth, Explanation } from './types.js';
9
+ /**
10
+ * Save an insight. Deduplicates by topic + content substring match.
11
+ * Returns the saved insight, or null if it was a duplicate.
12
+ */
13
+ export declare function saveInsight(insight: string, topic: string, tags?: string[], depth?: InsightDepth, project?: string): Insight | null;
14
+ /**
15
+ * Search insights by keyword (in insight text) and/or topic filter.
16
+ */
17
+ export declare function recallInsights(query?: string, topic?: string, limit?: number): Insight[];
18
+ /**
19
+ * Get topic breakdown with counts for learning progress overview.
20
+ */
21
+ export declare function reviewInsights(): Record<string, {
22
+ count: number;
23
+ depths: Record<string, number>;
24
+ }>;
25
+ /**
26
+ * Remove an insight by ID. Returns true if found and removed.
27
+ */
28
+ export declare function forgetInsight(id: string): boolean;
29
+ /**
30
+ * Save a plan explanation for history.
31
+ */
32
+ export declare function saveExplanation(planPath: string, title: string): Explanation;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * JSONL storage for insights and explanations.
3
+ *
4
+ * Location: ~/.claude/teacher/
5
+ * insights.jsonl — persistent educational insights
6
+ * explanations.jsonl — plan reasoning history
7
+ */
8
+ import { readFileSync, appendFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+ import { homedir } from 'node:os';
11
+ import { randomUUID } from 'node:crypto';
12
+ const STORE_DIR = join(homedir(), '.claude/teacher');
13
+ const INSIGHTS_FILE = join(STORE_DIR, 'insights.jsonl');
14
+ const EXPLANATIONS_FILE = join(STORE_DIR, 'explanations.jsonl');
15
+ function ensureDir() {
16
+ if (!existsSync(STORE_DIR)) {
17
+ mkdirSync(STORE_DIR, { recursive: true });
18
+ }
19
+ }
20
+ // ── Insights ────────────────────────────────────────────────────
21
+ function readInsights() {
22
+ ensureDir();
23
+ if (!existsSync(INSIGHTS_FILE))
24
+ return [];
25
+ try {
26
+ return readFileSync(INSIGHTS_FILE, 'utf-8')
27
+ .trim()
28
+ .split('\n')
29
+ .filter(Boolean)
30
+ .map((line) => JSON.parse(line));
31
+ }
32
+ catch {
33
+ return [];
34
+ }
35
+ }
36
+ /**
37
+ * Save an insight. Deduplicates by topic + content substring match.
38
+ * Returns the saved insight, or null if it was a duplicate.
39
+ */
40
+ export function saveInsight(insight, topic, tags = [], depth = 'intro', project) {
41
+ ensureDir();
42
+ const existing = readInsights();
43
+ // Dedup: same topic + first 30 chars of insight match
44
+ const prefix = insight.substring(0, 30).toLowerCase();
45
+ const isDuplicate = existing.some((e) => e.topic === topic && e.insight.substring(0, 30).toLowerCase() === prefix);
46
+ if (isDuplicate)
47
+ return null;
48
+ const entry = {
49
+ id: randomUUID(),
50
+ insight,
51
+ topic,
52
+ tags,
53
+ depth,
54
+ project,
55
+ created: new Date().toISOString(),
56
+ recalled: 0,
57
+ };
58
+ appendFileSync(INSIGHTS_FILE, JSON.stringify(entry) + '\n');
59
+ return entry;
60
+ }
61
+ /**
62
+ * Search insights by keyword (in insight text) and/or topic filter.
63
+ */
64
+ export function recallInsights(query, topic, limit = 5) {
65
+ const all = readInsights();
66
+ let filtered = all;
67
+ if (topic) {
68
+ filtered = filtered.filter((i) => i.topic === topic);
69
+ }
70
+ if (query) {
71
+ const q = query.toLowerCase();
72
+ filtered = filtered.filter((i) => i.insight.toLowerCase().includes(q) || i.tags.some((t) => t.toLowerCase().includes(q)));
73
+ }
74
+ // Most recently created first
75
+ filtered.sort((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime());
76
+ return filtered.slice(0, limit);
77
+ }
78
+ /**
79
+ * Get topic breakdown with counts for learning progress overview.
80
+ */
81
+ export function reviewInsights() {
82
+ const all = readInsights();
83
+ const topics = {};
84
+ for (const i of all) {
85
+ if (!topics[i.topic]) {
86
+ topics[i.topic] = { count: 0, depths: {} };
87
+ }
88
+ topics[i.topic].count++;
89
+ topics[i.topic].depths[i.depth] = (topics[i.topic].depths[i.depth] || 0) + 1;
90
+ }
91
+ return topics;
92
+ }
93
+ /**
94
+ * Remove an insight by ID. Returns true if found and removed.
95
+ */
96
+ export function forgetInsight(id) {
97
+ const all = readInsights();
98
+ const filtered = all.filter((i) => i.id !== id);
99
+ if (filtered.length === all.length)
100
+ return false;
101
+ ensureDir();
102
+ writeFileSync(INSIGHTS_FILE, filtered.map((i) => JSON.stringify(i)).join('\n') + '\n');
103
+ return true;
104
+ }
105
+ // ── Explanations (plan reasoning history) ───────────────────────
106
+ /**
107
+ * Save a plan explanation for history.
108
+ */
109
+ export function saveExplanation(planPath, title) {
110
+ ensureDir();
111
+ const entry = {
112
+ id: randomUUID(),
113
+ plan_path: planPath,
114
+ title,
115
+ created: new Date().toISOString(),
116
+ };
117
+ appendFileSync(EXPLANATIONS_FILE, JSON.stringify(entry) + '\n');
118
+ return entry;
119
+ }
120
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Shared types for claude-teacher-mcp.
3
+ *
4
+ * Single domain: plan structure extraction for template seeding.
5
+ */
6
+ export interface PlanStructure {
7
+ title: string;
8
+ project: string;
9
+ purpose: string;
10
+ sections: string[];
11
+ itemCount: number;
12
+ doneCount: number;
13
+ doneLine: string;
14
+ nextLine: string;
15
+ }
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shared types for claude-teacher-mcp.
3
+ *
4
+ * Single domain: plan structure extraction for template seeding.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "claude-augur-mcp",
3
+ "version": "0.1.0",
4
+ "description": "An MCP server that surfaces Claude's reasoning chain as scannable plan abstracts and persists educational insights",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "bin": {
8
+ "claude-augur-mcp": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc && chmod +x dist/index.js",
17
+ "dev": "tsc --watch",
18
+ "start": "node dist/index.js",
19
+ "clean": "rm -rf dist",
20
+ "typecheck": "tsc --noEmit",
21
+ "test": "npm run typecheck"
22
+ },
23
+ "keywords": [
24
+ "claude",
25
+ "claude-code",
26
+ "mcp",
27
+ "mcp-server",
28
+ "model-context-protocol",
29
+ "anthropic",
30
+ "reasoning",
31
+ "plan-summary",
32
+ "insights",
33
+ "augur",
34
+ "typescript",
35
+ "nodejs"
36
+ ],
37
+ "author": "Vvkmnn",
38
+ "license": "MIT",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/Vvkmnn/claude-augur-mcp.git"
42
+ },
43
+ "publishConfig": {
44
+ "registry": "https://registry.npmjs.org/",
45
+ "access": "public"
46
+ },
47
+ "engines": {
48
+ "node": ">=20.0.0"
49
+ },
50
+ "dependencies": {
51
+ "@modelcontextprotocol/sdk": "^1.12.0",
52
+ "zod": "^3.24.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^25.3.0",
56
+ "typescript": "^5.9.3"
57
+ }
58
+ }