@jefuriiij/synthra 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 jefuriiij
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,179 @@
1
+ # Synthra
2
+
3
+ > Local context engine for AI coding assistants. Graph-based context, branch-aware memory, real-time human-activity awareness, a deterministic Grep/Glob gate, and a live token dashboard.
4
+
5
+ Built first for Claude Code (IDE extension + CLI). Anything that speaks the Model Context Protocol can plug in.
6
+
7
+ ```bash
8
+ npm install -g @jefuriiij/synthra
9
+ cd your-project
10
+ syn .
11
+ ```
12
+
13
+ That's the whole install + run. Open the Claude Code IDE extension in the same folder and work normally; `Ctrl+C` the terminal when you're done.
14
+
15
+ ---
16
+
17
+ ## What it does
18
+
19
+ AI coding assistants burn tokens exploring the codebase on every turn — grep, glob, read, repeat. They also lose context between turns and across sessions, and they're blind to what *you* are doing in your editor between AI turns.
20
+
21
+ Synthra is a tiny local CLI that sits between you and your AI:
22
+
23
+ - **Pre-injects** a structured ~4K-token context pack (signatures + top function bodies + linked tests) into every session
24
+ - **Blocks** Grep/Glob calls deterministically at the PreToolUse hook layer when the graph already has the answer — the moat
25
+ - **Remembers** decisions and notes branch-by-branch in a git-tracked `.synthra/` directory so teammates inherit context
26
+ - **Watches** file saves, branch switches, and uncommitted diffs so the AI knows what just changed
27
+ - **Tracks** every token via Claude's transcript and reports estimated cost + savings on a live dashboard
28
+
29
+ When `syn .` runs, you see:
30
+
31
+ ```
32
+ [syn] ✅ scanned 123 files · 490 symbols · 574 edges
33
+ [syn] 🧠 MCP http://127.0.0.1:8080 → registered as 'synthra'
34
+ [syn] 📊 Dashboard http://127.0.0.1:8901
35
+ [syn] 🪝 Hooks installed in .claude/settings.local.json
36
+
37
+ [syn] 🤖 Ready — open the Claude Code IDE extension (or run `claude` in another terminal).
38
+ ```
39
+
40
+ ---
41
+
42
+ ## MCP tools
43
+
44
+ Synthra exposes ten tools to Claude over HTTP MCP. Claude calls these instead of Grep / Glob / Read for navigation:
45
+
46
+ | Tool | Purpose |
47
+ |---|---|
48
+ | `graph_continue(query)` | Return the structured context pack relevant to a query |
49
+ | `graph_read(target)` | Fetch source for a file or `file::symbol` |
50
+ | `graph_register_edit(files)` | Tell Synthra you edited files (boosts their ranking) |
51
+ | `context_remember(text, kind)` | Persist a decision / task / fact, branch-aware |
52
+ | `context_recall(kind?)` | Read previously-stored decisions |
53
+ | `recent_activity(since_ms?)` | What the human just saved / branch-switched / changed |
54
+ | `count_tokens(text)` | Char/4 estimate for prompt budgeting |
55
+ | `blast_radius(target, depth?)` | All files that depend on `target` transitively |
56
+ | `dead_code(limit?)` | Files no other file imports and no test references |
57
+
58
+ ---
59
+
60
+ ## Languages
61
+
62
+ Symbol extraction works for:
63
+
64
+ - **TypeScript / JavaScript** (`.ts`, `.tsx`, `.cts`, `.mts`, `.js`, `.jsx`, `.cjs`, `.mjs`)
65
+ - **Python** (`.py`, `.pyi`)
66
+ - **Svelte** (`.svelte`) — script blocks parsed as TS
67
+ - **Vue** (`.vue`) — same
68
+ - **Go** (`.go`)
69
+ - **Rust** (`.rs`)
70
+ - **Java** (`.java`)
71
+ - **Kotlin** (`.kt`, `.kts`)
72
+ - **PHP** (`.php`)
73
+ - **Ruby** (`.rb`)
74
+ - **C** (`.c`, `.h`)
75
+ - **C++** (`.cpp`, `.cc`, `.cxx`, `.hpp`, `.hh`, `.hxx`)
76
+ - **C#** / .NET (`.cs`)
77
+ - **Dart** (`.dart`) — content indexed; symbol extraction is best-effort in v0.1
78
+
79
+ Files in other languages (HTML, CSS, JSON, YAML, Markdown, etc.) are walked and content-indexed so keyword search still finds them — just no symbol-level granularity.
80
+
81
+ ---
82
+
83
+ ## Commands
84
+
85
+ ```bash
86
+ syn . # Default: scan + MCP + dashboard + hooks + claude mcp add.
87
+ # Terminal blocks on SIGINT; use the IDE extension.
88
+ syn . --launch-cli # Also spawn the `claude` CLI in this terminal.
89
+ syn . --resume <id> # Resume a Claude session (requires --launch-cli to take effect).
90
+ syn scan [path] # Scan only — walk + parse + write graph.
91
+ syn serve [path] # Start the MCP server only.
92
+ syn dashboard [path] # Run only the token dashboard (standalone process).
93
+ ```
94
+
95
+ ---
96
+
97
+ ## Storage layout
98
+
99
+ When `syn .` runs in a project:
100
+
101
+ ```
102
+ your-project/
103
+ ├── .gitignore # appended: .synthra-graph/
104
+ ├── CLAUDE.md # appended: <!-- synthra-policy v1 ... -->
105
+ ├── .claude/
106
+ │ ├── settings.local.json # hooks merged (tagged with meta: "synthra-hook=true")
107
+ │ └── hooks/ # synthra-prime.ps1, synthra-pre-tool-use.ps1, …
108
+ ├── .synthra-graph/ # GITIGNORED — heavy machine-local state
109
+ │ ├── info_graph.json
110
+ │ ├── symbol_index.json
111
+ │ ├── activity.jsonl
112
+ │ ├── token_log.jsonl
113
+ │ ├── gate_log.jsonl
114
+ │ └── mcp_port
115
+ └── .synthra/ # GIT-TRACKED — team's shared memory
116
+ ├── context-store.json # decisions, tasks, facts (default branch)
117
+ ├── CONTEXT.md # narrative summary
118
+ └── branches/<sanitized>/ # per-branch overrides
119
+ ```
120
+
121
+ A global registry at `~/.synthra/projects.json` lists every project where Synthra has run, so `syn dashboard` can show aggregate stats across all of them.
122
+
123
+ ---
124
+
125
+ ## Coexistence
126
+
127
+ Synthra is friendly with other AI-context tools. It only writes to its own `.synthra/` and `.synthra-graph/` paths, only modifies `CLAUDE.md` inside its own `<!-- synthra-policy v1 -->` markers, and tags hook entries with `meta: "synthra-hook=true"` so re-runs strip only its own entries from `settings.local.json`.
128
+
129
+ If another tool (e.g. GrapeRoot) also logs to the dashboard, Synthra dedupes overlapping entries on read.
130
+
131
+ ---
132
+
133
+ ## Configuration
134
+
135
+ Environment variables (all optional):
136
+
137
+ | Variable | Default | Purpose |
138
+ |---|---|---|
139
+ | `SYN_MCP_PORT` | (auto 8080–8099) | Pin the MCP server port |
140
+ | `SYN_DASHBOARD_PORT` | `8901` | Dashboard preferred port (falls back through 8901–8910) |
141
+ | `SYN_HARD_MAX_READ_CHARS` | `4000` | Soft token budget for `graph_continue` packs |
142
+ | `SYN_LOG_LEVEL` | `info` | `debug` / `info` / `warn` / `error` |
143
+ | `SYN_CLAUDE_BIN` | `claude` | Override the `claude` binary location |
144
+ | `SYN_NO_UPDATE_CHECK` | `0` | Set to `1` to skip the daily version-check ping |
145
+
146
+ ---
147
+
148
+ ## How the moat works
149
+
150
+ The PreToolUse hook fires on every `Grep` / `Glob` call. The hook POSTs the tool input to Synthra's local server. The server runs the query through the graph and returns:
151
+
152
+ - `decision: "allow"` if the graph has no confident match (low confidence)
153
+ - `decision: "allow"` if the user just edited a matching file (recent-activity relaxation)
154
+ - `decision: "block"` otherwise, with a reason pointing Claude at `graph_continue`
155
+
156
+ Claude Code honors the block and tries again with the suggested MCP tool. The structured pack is cheaper, faster, and pre-ranked.
157
+
158
+ ---
159
+
160
+ ## Development
161
+
162
+ ```bash
163
+ git clone https://github.com/jefuriiij/synthra
164
+ cd synthra
165
+ npm install
166
+ npm link # makes `syn` available globally; rebuilds reflect immediately
167
+ npm run build # tsup → dist/
168
+ npm run dev # tsup --watch
169
+ npm test # vitest
170
+ npm run typecheck # tsc --noEmit
171
+ ```
172
+
173
+ See [`ROADMAP.md`](./ROADMAP.md) for the milestone history (M1 scanner → M6 dashboard) and the v0.2 backlog.
174
+
175
+ ---
176
+
177
+ ## License
178
+
179
+ [MIT](./LICENSE)
package/ROADMAP.md ADDED
@@ -0,0 +1,324 @@
1
+ # Synthra — Implementation Plan
2
+
3
+ ## Context
4
+
5
+ **Why this exists.** AI coding assistants (Claude Code, Codex, Cursor) burn tokens exploring codebases on every turn — grep, glob, read, repeat. They also lose context between turns and sessions, and they are blind to what the human is doing in their editor between AI turns. The user wants to build **Synthra** (CLI: `syn`) — a local context engine that addresses all three problems.
6
+
7
+ **Key capabilities:**
8
+
9
+ 1. **Deterministic enforcement via PreToolUse hooks** — block AI Grep/Glob calls when the graph already has the answer, instead of relying on CLAUDE.md prose policy. The hook returns `{"decision":"block","reason":"..."}` and the AI literally cannot disobey.
10
+ 2. **Branch-aware, git-tracked context store** — `.synthra/` is committed to the repo (default-on), partitioned by branch. Teammates inherit decisions; cross-machine resumption works.
11
+ 3. **Human-activity awareness** — chokidar file-watcher + `.git/HEAD` + `git status` watcher feeds a recent-activity log. AI sees "user saved auth.ts 12s ago, here's the diff" automatically.
12
+ 4. **Per-turn cost transparency** — dashboard breaks down every turn into (system prompt / conversation history / Synthra context / your message / response) with a live "savings vs. baseline" delta computed from blocked-Grep counts.
13
+ 5. **Test ↔ source co-retrieval** — when packing context for `getUser.ts`, automatically include `getUser.test.ts`. Free win.
14
+ 6. **Fully MIT open-source** — engine and launcher.
15
+
16
+ **Locked decisions (from conversation):**
17
+ - **Name:** Synthra (synthesis + -ra suffix, two-syllable brand-style)
18
+ - **CLI:** primary `syn`, alias `synthra`
19
+ - **Stack:** TypeScript / Node (chosen over Python for cleaner Windows install, npm distribution, future VS Code extension reuse)
20
+ - **First AI target:** Claude Code via HTTP MCP
21
+ - **Parsers v0.1:** TS/JS, Python, Svelte, Vue (tree-sitter via WASM)
22
+ - **License:** MIT (fully open-source, both engine and launcher)
23
+ - **Repo:** new public repo at `github.com/jefuriiij/synthra`, cloned to `C:\Users\Jeff\Desktop\personal-project\synthra` — completely separate from `Optima-Solutions-Dev/Skills` (which is a private org repo for Claude Code skills, not standalone tools)
24
+ - **Storage split:** `.synthra-graph/` (gitignored, heavy machine-state) + `.synthra/` (git-tracked, branch-partitioned, shared team memory)
25
+ - **Ctrl+C UX:** catches latest session JSONL from `~/.claude/projects/<encoded-cwd>/`, prints `syn --resume <id>`
26
+
27
+ ---
28
+
29
+ ## Implementation order
30
+
31
+ Six milestones, each independently testable.
32
+
33
+ ### M1 — Skeleton + Scanner (the foundation)
34
+
35
+ Output: `syn .` scans the current directory, writes `.synthra-graph/info_graph.json` + `symbol_index.json`, updates `.gitignore`, patches `CLAUDE.md` with a versioned policy block, creates `.synthra/` if missing. No AI integration yet.
36
+
37
+ Build:
38
+ - Repo skeleton (package.json, tsconfig, LICENSE, README, .gitignore, bin/syn)
39
+ - `src/cli/index.ts` + `src/cli/bootstrap.ts`
40
+ - `src/scanner/walker.ts` (respects .gitignore + .synthraignore)
41
+ - `src/scanner/parser.ts` + per-language parsers (TS/JS, Python, Svelte, Vue) using tree-sitter WASM
42
+ - `src/scanner/extract.ts` — produces graph nodes (files, symbols) + edges (imports, calls)
43
+ - `src/scanner/keywords.ts` — rare-word/TF-IDF keyword extraction per file
44
+ - `src/graph/store.ts` — writes JSON files with a stable schema (so the dashboard and downstream tools can reuse it)
45
+ - `src/hooks/claude-md.ts` — idempotent CLAUDE.md policy block with `<!-- synthra-policy v1 BEGIN/END -->` markers
46
+
47
+ **Verification:** Run `syn .` in `windsor-stables`. Inspect generated `info_graph.json` — for a 191-file project, expect roughly 1000+ symbols and 1700+ edges. Verify `.gitignore` has `.synthra-graph/` added with comment. Verify `CLAUDE.md` has the policy block. Verify `.synthra/` exists.
48
+
49
+ ### M2 — HTTP MCP server + Context Packer
50
+
51
+ Output: `syn serve` starts a Hono HTTP server on 8080-8099, exposes MCP tools (`graph_continue`, `graph_read`, `graph_register_edit`), plus the routes hooks need (`/prime`, `/log`, `/pack`, `/gate`). Test via curl, not Claude yet.
52
+
53
+ Build:
54
+ - `src/server/http.ts` (Hono, free-port discovery 8080-8099)
55
+ - `src/server/mcp.ts` (MCP-over-HTTP protocol handler)
56
+ - `src/server/routes/prime.ts`, `pack.ts`, `log.ts`, `gate.ts`, `activity.ts`
57
+ - `src/server/port.ts` (writes `.synthra-graph/mcp_port`)
58
+ - `src/graph/retrieve.ts` (query → ranked file list)
59
+ - `src/graph/rank.ts` (keyword + import-distance + recency)
60
+ - `src/packer/index.ts` + `signatures.ts` + `inline.ts` + `format.ts` (~4K-token structured pack)
61
+ - `src/packer/tests.ts` (test ↔ source co-retrieval) ← improvement #5
62
+
63
+ **Verification:** Manual `curl http://127.0.0.1:8080/pack -d '{"query":"login"}'`. Inspect returned pack — should be structured (signatures + top function bodies), under 4K tokens, and include matching test files alongside source files.
64
+
65
+ ### M3 — Claude Code integration (the moat)
66
+
67
+ Output: `syn .` registers Synthra's MCP with Claude Code via `claude mcp add`, installs the four hooks (SessionStart, PreToolUse, PreCompact, Stop) into `.claude/settings.local.json` + `.claude/hooks/`, and launches `claude`. Pre-injection works. PreToolUse blocking works.
68
+
69
+ Build:
70
+ - `src/hooks/installer.ts` — writes scripts + edits `.claude/settings.local.json` to register hooks
71
+ - `src/hooks/scripts/prime.{ps1,sh}` — `GET /prime` → stdout primer
72
+ - `src/hooks/scripts/pre-tool-use.{ps1,sh}` — `POST /gate` with the tool call payload → if response is `block`, exit 2 with reason (Claude treats this as deny)
73
+ - `src/hooks/scripts/pre-compact.{ps1,sh}` — `GET /prime` (re-inject after auto-compact)
74
+ - `src/hooks/scripts/stop.{ps1,sh}` — parse transcript JSONL, sum usage, `POST /log`
75
+ - `src/cli/start-claude.ts` — registers MCP + spawns `claude`
76
+ - `src/server/routes/gate.ts` — the moat logic: consult graph, decide block/allow
77
+
78
+ **Verification:** Run `syn .` in `windsor-stables`. Inside Claude, ask "where do we handle expired auth tokens?" Confirm:
79
+ 1. Context primer appears at session start ("Context loaded (port 8080)")
80
+ 2. Claude does NOT call Grep (gate blocks it; reason is shown)
81
+ 3. Claude reads `file::symbol` notation via `graph_read`
82
+ 4. Token usage logged to `token_log.jsonl` on Stop
83
+ 5. Ctrl+C produces `syn --resume <id>` line, MCP server shuts down cleanly
84
+
85
+ ### M4 — Branch-aware Context Store
86
+
87
+ Output: `.synthra/` is git-tracked by default. Decisions made on a feature branch are scoped to that branch and merge naturally. `CONTEXT.md` updates at session end (via Stop hook).
88
+
89
+ Build:
90
+ - `src/memory/context-store.ts` — reads/writes `.synthra/context-store.json` or `.synthra/branches/<branch>/context-store.json`
91
+ - `src/memory/branches.ts` — detects current branch, routes reads/writes to correct file
92
+ - `src/memory/context-md.ts` — Stop hook generates/updates CONTEXT.md
93
+ - Update `src/hooks/scripts/stop.{ps1,sh}` to also POST to a new `/context-update` route
94
+
95
+ **Verification:** Switch to a feature branch, log a decision via Claude. Verify it lands in `.synthra/branches/<branch>/context-store.json`, not the root. Switch back to main, confirm the feature-branch decision is NOT visible. Merge the branch, confirm the decision merges.
96
+
97
+ ### M5 — Human-activity watcher (the wedge)
98
+
99
+ Output: File saves outside Claude, branch switches, and uncommitted diffs are visible to the AI via a `/activity` MCP tool. The `gate` route also factors recent activity into block decisions ("user just edited auth.ts → don't block grep on auth files").
100
+
101
+ Build:
102
+ - `src/activity/file-watcher.ts` — chokidar on project root, respects `.gitignore`
103
+ - `src/activity/git-watcher.ts` — watches `.git/HEAD` (branch switches), polls `git status --porcelain` every 2s
104
+ - `src/activity/activity-log.ts` — rolling 100-event JSONL in `.synthra-graph/activity.jsonl`
105
+ - `src/server/routes/activity.ts` — `GET /activity?since=<ts>` returns events
106
+ - Update `src/packer/index.ts` — boost recently-touched files in ranking
107
+ - Update `src/server/routes/gate.ts` — relax blocking when topic matches recent activity
108
+
109
+ **Verification:** Run `syn .`. Outside Claude, edit `auth.ts` and save. Inside Claude, ask a question about login. Confirm: (a) the recent edit shows up in the context pack, (b) the response shows awareness of the unsaved change, (c) `activity.jsonl` has the save event.
110
+
111
+ ### M6 — Token dashboard
112
+
113
+ Output: `http://localhost:8901` shows live per-turn breakdown, total session cost, and savings vs. no-optimizer. Standalone process so it survives MCP restarts.
114
+
115
+ Build:
116
+ - `src/dashboard/server.ts` — independent Hono server, listens on 8901, reads `token_log.jsonl`
117
+ - `src/dashboard/delta.ts` — computes estimated "no-optimizer cost" from blocked-Grep counts × avg-tokens-per-Grep
118
+ - `src/dashboard/public/index.html` + `app.js` + `style.css` — single-page UI, polls `/data` every 2s
119
+ - `src/cli/dashboard-command.ts` — `syn dashboard` opens browser
120
+
121
+ **Verification:** Run `syn .` for a few turns. Open `http://localhost:8901`. Confirm each turn appears with breakdown (system / conversation / pack / message / response) and total session cost matches summed `token_log.jsonl`. Confirm "saved" delta is non-zero.
122
+
123
+ ---
124
+
125
+ ## Repo layout (in the new `synthra` repo at `C:\Users\Jeff\Desktop\personal-project\synthra`)
126
+
127
+ ```
128
+ synthra/
129
+ ├── README.md
130
+ ├── LICENSE # MIT
131
+ ├── package.json # bin: { "syn": "./bin/syn", "synthra": "./bin/syn" }
132
+ ├── tsconfig.json
133
+ ├── .gitignore # node_modules, dist, .DS_Store
134
+ ├── tsup.config.ts # or esbuild config
135
+ ├── ROADMAP.md # copy of this plan, scoped for the project
136
+
137
+ ├── bin/
138
+ │ └── syn # #!/usr/bin/env node → ../dist/cli/index.js
139
+
140
+ ├── src/
141
+ │ ├── cli/
142
+ │ │ ├── index.ts # arg parsing (commander or sade)
143
+ │ │ ├── bootstrap.ts # .synthra-graph/, .synthra/, .gitignore, CLAUDE.md
144
+ │ │ ├── start-claude.ts # mcp add + spawn claude + trap SIGINT
145
+ │ │ ├── cleanup.ts # graceful shutdown + resume command print
146
+ │ │ ├── session-discovery.ts # locate latest ~/.claude/projects/<enc>/*.jsonl
147
+ │ │ ├── dashboard-command.ts
148
+ │ │ └── self-update.ts # version check on every run
149
+ │ │
150
+ │ ├── scanner/
151
+ │ │ ├── walker.ts # ignore .gitignore + .synthraignore
152
+ │ │ ├── parser.ts # dispatch by file ext
153
+ │ │ ├── parsers/{typescript,python,svelte,vue}.ts
154
+ │ │ ├── extract.ts # files, symbols, imports → graph
155
+ │ │ ├── keywords.ts # rare-word extraction
156
+ │ │ └── hash.ts # file_hash for incremental update (M1: full re-parse OK)
157
+ │ │
158
+ │ ├── graph/
159
+ │ │ ├── types.ts # Node, Edge, Symbol, GraphSchema
160
+ │ │ ├── store.ts # info_graph.json + symbol_index.json
161
+ │ │ ├── retrieve.ts # query → ranked file list
162
+ │ │ └── rank.ts # keyword + imports + recency + activity boost
163
+ │ │
164
+ │ ├── packer/
165
+ │ │ ├── index.ts # ~4K-token structured pack
166
+ │ │ ├── signatures.ts
167
+ │ │ ├── inline.ts # top function bodies
168
+ │ │ ├── tests.ts # co-retrieve *.test.* (improvement #5)
169
+ │ │ └── format.ts
170
+ │ │
171
+ │ ├── memory/
172
+ │ │ ├── session.ts # this-session: AI read/edit log
173
+ │ │ ├── context-store.ts # structured decisions
174
+ │ │ ├── context-md.ts # CONTEXT.md handler
175
+ │ │ └── branches.ts # branch-aware routing (improvement #2)
176
+ │ │
177
+ │ ├── activity/
178
+ │ │ ├── file-watcher.ts # chokidar (improvement #3)
179
+ │ │ ├── git-watcher.ts # .git/HEAD + status
180
+ │ │ └── activity-log.ts # rolling JSONL
181
+ │ │
182
+ │ ├── server/
183
+ │ │ ├── http.ts # Hono
184
+ │ │ ├── mcp.ts # MCP-over-HTTP
185
+ │ │ ├── port.ts # 8080–8099 discovery
186
+ │ │ └── routes/
187
+ │ │ ├── prime.ts # GET — SessionStart hook
188
+ │ │ ├── pack.ts # POST — context packer
189
+ │ │ ├── log.ts # POST — token usage
190
+ │ │ ├── gate.ts # POST — PreToolUse decision (THE MOAT)
191
+ │ │ ├── activity.ts # GET — recent human edits
192
+ │ │ └── context-update.ts # POST — Stop hook updates CONTEXT.md
193
+ │ │
194
+ │ ├── hooks/
195
+ │ │ ├── installer.ts # writes scripts + claude mcp add
196
+ │ │ ├── claude-md.ts # versioned policy block in CLAUDE.md
197
+ │ │ └── scripts/
198
+ │ │ ├── prime.{ps1,sh}
199
+ │ │ ├── pre-tool-use.{ps1,sh} # THE MOAT (improvement #1)
200
+ │ │ ├── pre-compact.{ps1,sh}
201
+ │ │ └── stop.{ps1,sh}
202
+ │ │
203
+ │ ├── dashboard/
204
+ │ │ ├── server.ts # standalone on 8901
205
+ │ │ ├── delta.ts # savings vs no-optimizer (improvement #4)
206
+ │ │ └── public/{index.html,app.js,style.css}
207
+ │ │
208
+ │ └── shared/
209
+ │ ├── paths.ts # resolves .synthra/ vs .synthra-graph/
210
+ │ ├── logger.ts
211
+ │ └── config.ts # env vars (SYN_*)
212
+
213
+ ├── tests/
214
+ │ ├── scanner.test.ts
215
+ │ ├── packer.test.ts
216
+ │ ├── rank.test.ts
217
+ │ └── fixtures/sample-project/
218
+
219
+ └── docs/
220
+ ├── ARCHITECTURE.md
221
+ └── PROTOCOL.md # HTTP routes + MCP tool schemas
222
+ ```
223
+
224
+ ## What Synthra creates in user projects (e.g., `windsor-stables/`)
225
+
226
+ ```
227
+ your-project/
228
+ ├── .gitignore # auto-amended:
229
+ │ # # added by optimizer
230
+ │ # .synthra-graph/
231
+
232
+ ├── CLAUDE.md # auto-amended with markers:
233
+ │ # <!-- synthra-policy v1 BEGIN -->
234
+ │ # ... policy text ...
235
+ │ # <!-- synthra-policy v1 END -->
236
+
237
+ ├── .claude/
238
+ │ ├── settings.local.json # hooks registered here
239
+ │ └── hooks/ # scripts regenerated each `syn .`
240
+
241
+ ├── .synthra-graph/ # GITIGNORED (machine-local)
242
+ │ ├── info_graph.json
243
+ │ ├── symbol_index.json
244
+ │ ├── session.json
245
+ │ ├── activity.jsonl
246
+ │ ├── token_log.jsonl
247
+ │ ├── mcp_port
248
+ │ ├── mcp_server.log
249
+ │ └── mcp_server.err.log
250
+
251
+ └── .synthra/ # GIT-TRACKED (team's memory)
252
+ ├── context-store.json # default-branch decisions
253
+ ├── CONTEXT.md # default-branch narrative
254
+ └── branches/
255
+ └── <branch>/{context-store.json, CONTEXT.md}
256
+ ```
257
+
258
+ ---
259
+
260
+ ## Tooling choices (proposed; can override at execution)
261
+
262
+ | Decision | Proposed | Why |
263
+ |---|---|---|
264
+ | Package manager | **npm** | Ubiquitous; no extra install step for users |
265
+ | Build | **tsup** (esbuild under the hood) | Single binary output, watches in dev, fast |
266
+ | HTTP framework | **Hono** | Lightweight, fast, works on Node + edge; cleaner than Express |
267
+ | AST parsing | **`web-tree-sitter`** (WASM) | Multi-language from one runtime; works on Windows without native build |
268
+ | File watching | **chokidar** | Battle-tested, handles Windows quirks |
269
+ | CLI args | **sade** or **commander** | Sade is lighter; commander has more docs |
270
+ | Tests | **vitest** | Fast, ESM-native, great DX |
271
+ | Distribution | **npm package** (`synthra`) | `npm install -g synthra` is the install story |
272
+
273
+ ---
274
+
275
+ ## First execution steps (when plan is approved)
276
+
277
+ **A. Create and clone the new repo (NOT inside `Optima-Workspace/Skills/`):**
278
+
279
+ 1. Create new public GitHub repo: `gh repo create jefuriiij/synthra --public --license=mit --description="Local context engine for AI coding assistants — graph-based context, branch-aware memory, real-time human-activity awareness"`
280
+ 2. Clone to `C:\Users\Jeff\Desktop\personal-project\synthra` (alongside other projects, outside the Skills repo).
281
+ 3. From this point, the working directory is `C:\Users\Jeff\Desktop\personal-project\synthra`. All scaffolding happens there.
282
+
283
+ **B. Scaffold M1 inside the new repo:**
284
+
285
+ 4. Create `package.json` (name: `synthra`, bin: `{ "syn": "./bin/syn", "synthra": "./bin/syn" }`).
286
+ 5. Create `tsconfig.json`, `LICENSE` (MIT), `README.md` (with the product positioning), `.gitignore` (node_modules, dist, etc.).
287
+ 6. Create `bin/syn` (shebang Node script → `dist/cli/index.js`).
288
+ 7. Stub every `src/**/*.ts` file from the tree with TODO comments + minimal type signatures (no real logic — navigable skeleton only).
289
+ 8. Run `npm install` for core dependencies (Hono, chokidar, web-tree-sitter, sade, vitest, tsup).
290
+ 9. Copy this plan to `C:\Users\Jeff\Desktop\personal-project\synthra\ROADMAP.md` so it lives with the project.
291
+ 10. Initial commit + push to `origin/main`.
292
+
293
+ **C. Clean up the Skills repo:**
294
+
295
+ 11. Delete the entire `Optima-Workspace/Skills/optimizer/` folder (including `sample-only-delete-later/`). It was always a scratch space — the real work now lives in the new repo.
296
+ 12. Commit the deletion in the Skills repo with a message like "remove optimizer/ scratch folder — work moved to jefuriiij/synthra".
297
+
298
+ **D. Stop and report.** Don't proceed to M1 implementation logic without user check-in. The skeleton + first commit is the first concrete artifact and worth reviewing before flesh.
299
+
300
+ ---
301
+
302
+ ## Verification (end-to-end, after M3)
303
+
304
+ The acceptance test for "Synthra works": run `syn .` in a real repo (`windsor-stables`), open Claude, ask a question that on plain Claude would trigger 3+ Grep/Read tool calls. Expect:
305
+
306
+ - ✅ Context primer appears at session start
307
+ - ✅ Claude answers without calling Grep (PreToolUse gate blocked it; reason printed)
308
+ - ✅ Response quality is equal or better than plain Claude
309
+ - ✅ Token usage logged; dashboard shows savings vs. estimated plain-Claude cost
310
+ - ✅ Ctrl+C prints `syn --resume <session-id>` and shuts down cleanly
311
+ - ✅ `syn --resume <id>` restores both Claude's conversation AND Synthra's session memory
312
+ - ✅ A decision logged mid-session lands in `.synthra/context-store.json` (or branch dir)
313
+ - ✅ Saving a file outside Claude appears in the next turn's context pack
314
+
315
+ ---
316
+
317
+ ## Out of scope for v0.1 (deferred)
318
+
319
+ - IDE companion extension (VS Code / Antigravity / Cursor) — designed for, not built yet
320
+ - Diff-tracked incremental graph updates (M1 does full re-parse; fine for repos under ~500 files)
321
+ - Embedding-based semantic retrieval (keyword scoring is enough to start)
322
+ - Codex CLI / Cursor / Gemini support (same MCP, different launcher — fast follow-on)
323
+ - Self-update mechanism (manually `npm i -g synthra@latest` for now)
324
+ - macOS/Linux platform parity for hooks (write `.sh` versions in M3, but Windows is primary)
package/bin/syn ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import("../dist/cli/index.js")
3
+ .then((mod) => mod.main(process.argv))
4
+ .catch((err) => {
5
+ console.error("[syn] fatal:", err?.message ?? err);
6
+ if (err?.stack) console.error(err.stack);
7
+ process.exit(1);
8
+ });