@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 +21 -0
- package/README.md +179 -0
- package/ROADMAP.md +324 -0
- package/bin/syn +8 -0
- package/dist/cli/index.js +4284 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/dashboard/index.js +602 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/server/index.js +2933 -0
- package/dist/server/index.js.map +1 -0
- package/package.json +63 -0
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)
|