ashlr-plugin 1.36.4 → 1.37.1

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.
Files changed (81) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/README.md +49 -8
  5. package/commands/ashlr-doctor.md +29 -0
  6. package/commands/ashlr-status.md +1 -1
  7. package/docs/PHANTOM-USAGE.md +58 -0
  8. package/docs/architecture.md +5 -5
  9. package/docs/ashlr-handshake.md +36 -0
  10. package/docs/assets/og.svg +1 -1
  11. package/docs/benchmarks-v2.json +226 -177
  12. package/docs/benchmarks.md +20 -10
  13. package/docs/competitive-wozcode.md +2 -2
  14. package/docs/embeddings-gateway.md +39 -0
  15. package/docs/index.html +3 -3
  16. package/docs/legal.md +1 -1
  17. package/docs/llm-providers.md +15 -1
  18. package/docs/multi-host-mcp.md +25 -3
  19. package/docs/phantom-preflight.md +23 -0
  20. package/docs/team-genome.md +2 -1
  21. package/hooks/_hook-timing-ledger.ts +2 -9
  22. package/hooks/hooks.json +3 -106
  23. package/hooks/posttooluse-stale-result.ts +3 -0
  24. package/hooks/pretooluse-common.ts +1 -1
  25. package/hooks/pretooluse-notebookedit.ts +1 -1
  26. package/hooks/pretooluse-write.ts +1 -1
  27. package/hooks/session-start.ts +48 -26
  28. package/package.json +9 -4
  29. package/ports/cursor/mcp.json +1 -1
  30. package/scripts/_read-thresholds.ts +119 -0
  31. package/scripts/ashlr-mcp.mjs +15 -0
  32. package/scripts/ashlr-mcp.ts +3 -0
  33. package/scripts/ashlr-plugin.mjs +59 -0
  34. package/scripts/bench-read-real.ts +90 -0
  35. package/scripts/bootstrap.mjs +14 -4
  36. package/scripts/cli.ts +35 -10
  37. package/scripts/context-status.ts +7 -2
  38. package/scripts/deploy-smoke.sh +8 -4
  39. package/scripts/doctor.ts +171 -42
  40. package/scripts/genome-auto-consolidate.ts +4 -2
  41. package/scripts/genome-init.ts +3 -3
  42. package/scripts/genome-key.ts +64 -7
  43. package/scripts/handshake.mjs +51 -0
  44. package/scripts/hook-bootstrap.mjs +170 -17
  45. package/scripts/mcp-entrypoint.ts +3 -0
  46. package/scripts/ollama-setup.ts +5 -4
  47. package/scripts/run-benchmark.ts +28 -18
  48. package/scripts/upgrade-flow.ts +9 -14
  49. package/servers/_base-urls.ts +48 -0
  50. package/servers/_companions.ts +258 -0
  51. package/servers/_cwd-clamp.ts +38 -1
  52. package/servers/_edit-match.ts +12 -2
  53. package/servers/_embedding-model.ts +77 -0
  54. package/servers/_gateway-target.ts +179 -0
  55. package/servers/_llm-providers/anthropic.ts +10 -4
  56. package/servers/_llm-providers/cloud.ts +9 -7
  57. package/servers/_llm-providers/index.ts +8 -6
  58. package/servers/_llm-providers/local.ts +9 -5
  59. package/servers/_mcp-host.ts +6 -0
  60. package/servers/_miss-tracker.ts +121 -0
  61. package/servers/_phantom-exec.ts +135 -0
  62. package/servers/_phantom-preflight.ts +130 -0
  63. package/servers/_pid-alive.ts +40 -0
  64. package/servers/_pro-token-keychain.ts +149 -0
  65. package/servers/_redact-keys.ts +75 -0
  66. package/servers/_rg-text.ts +111 -0
  67. package/servers/_router.ts +20 -2
  68. package/servers/_run-with-timeout.ts +56 -12
  69. package/servers/_test-watch.ts +1 -10
  70. package/servers/_token-measure.ts +3 -1
  71. package/servers/_tool-base.ts +6 -0
  72. package/servers/bash-server.ts +1 -10
  73. package/servers/edit-server.ts +24 -1
  74. package/servers/efficiency-server.ts +12 -2
  75. package/servers/genome-server-handlers.ts +2 -2
  76. package/servers/genome-server.ts +17 -17
  77. package/servers/grep-server.ts +6 -2
  78. package/servers/orient-server-handlers.ts +3 -2
  79. package/servers/orient-server.ts +16 -9
  80. package/servers/read-server.ts +1 -1
  81. package/servers/write-server-handlers.ts +10 -2
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Open-source Claude Code plugin — 40 token-efficient MCP tools, 34 slash commands, GitHub OAuth sign-in, auto-genome from public repos, cloud-genome pull, per-session accounting, animated status line. MIT, opt-in telemetry.",
9
- "version": "1.36.4"
9
+ "version": "1.37.1"
10
10
  },
11
11
  "plugins": [
12
12
  {
@@ -15,8 +15,8 @@
15
15
  "source": "url",
16
16
  "url": "https://github.com/ashlrai/ashlr-plugin.git"
17
17
  },
18
- "description": "Token-efficient MCP tools for Claude Code — open-source WOZCODE alternative. Mean -57% savings overall on real codebases.",
19
- "version": "1.36.4",
18
+ "description": "Token-efficient MCP tools for Claude Code, open-source WOZCODE alternative. Measured per-call savings: reads about -75%, greps about -50% (not end-to-end).",
19
+ "version": "1.37.1",
20
20
  "author": {
21
21
  "name": "Mason Wyatt",
22
22
  "url": "https://github.com/ashlrai"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ashlr",
3
- "version": "1.36.4",
3
+ "version": "1.37.1",
4
4
  "description": "Open-source Claude Code plugin — 40 MCP tools and 34 slash commands, hybrid LLM summarization (Anthropic Haiku 4.5 default + ONNX offline + local opt-in), GitHub OAuth sign-in, auto-genome from public repos, cloud-genome pull on session start, PreToolUse redirect hooks (ASHLR_HOOK_MODE), unified $/MTok pricing (ASHLR_PRICING_MODEL), per-session token accounting, opt-in telemetry, animated status line, shareable SVG savings badge. MIT.",
5
5
  "author": {
6
6
  "name": "Mason Wyatt",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ashlr",
3
- "version": "1.36.4",
3
+ "version": "1.37.1",
4
4
  "description": "Multi-host AI coding efficiency layer for Codex and Claude Code: 40 MCP tools, Codex skills, nudge-first hooks, genome memory, and token savings accounting.",
5
5
  "author": {
6
6
  "name": "Mason Wyatt",
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # ashlr-plugin
2
2
 
3
- > **Cut Codex and Claude Code token usage by −57% on real codebases.**
4
- > _TS −62% · Python −65% · Rust −44%_ — measured on `vercel/ai`, `pandas`, and `tokio`.
3
+ **Same agent. Fewer tokens.**
4
+
5
+ > **Fewer tokens per tool call in Codex and Claude Code: reads about −75%, greps about −27% on vercel/ai, pandas and tokio (per-call benchmark, not end to end).**
6
+ > _TS −60% · Python −63% · Rust −55%_ — measured on `vercel/ai`, `pandas`, and `tokio`.
5
7
  > 95% CI reported by the benchmark runner. Reproduce with `bun run scripts/run-benchmark.ts --compare`. ([full methodology](docs/benchmarks.md))
6
8
 
7
9
  40 MCP tools that replace high-volume `Read` / `Grep` / `Edit` / `Bash` workflows with versions that return **less** without losing what matters. Claude Code gets automatic PreToolUse redirects (`ASHLR_HOOK_MODE=redirect`); Codex gets first-class plugin packaging, MCP, skills, and nudge-first hooks.
@@ -24,7 +26,7 @@ The npm package exposes `ashlr-plugin` for CLI workflows and `ashlr-mcp` for MCP
24
26
 
25
27
  **Landing page:** [plugin.ashlr.ai](https://plugin.ashlr.ai/) · **Docs:** [plugin.ashlr.ai/docs](https://plugin.ashlr.ai/docs) · **Core library:** [`@ashlr/core-efficiency`](https://github.com/ashlrai/ashlr-core-efficiency) · **License:** MIT
26
28
 
27
- > **Open-source and honestly benchmarked.** The −57% headline is reproducible on your own code with `bun run scripts/run-benchmark.ts --compare` ([methodology](docs/benchmarks.md)). Every ashlr savings figure includes a 95% CI. Telemetry is off by default. Compare against closed, self-benchmarked alternatives with `/ashlr-benchmark --compare`.
29
+ > **Open-source and honestly benchmarked.** The per-call figures are reproducible on your own code with `bun run scripts/run-benchmark.ts --compare` ([methodology](docs/benchmarks.md)). Every ashlr savings figure includes a 95% CI. Telemetry is off by default. Compare against closed, self-benchmarked alternatives with `/ashlr-benchmark --compare`.
28
30
 
29
31
  [![CI (Linux · macOS · Windows)](https://github.com/ashlrai/ashlr-plugin/actions/workflows/ci.yml/badge.svg?branch=main&event=push)](https://github.com/ashlrai/ashlr-plugin/actions/workflows/ci.yml?query=branch%3Amain+event%3Apush)
30
32
 
@@ -32,7 +34,20 @@ The npm package exposes `ashlr-plugin` for CLI workflows and `ashlr-mcp` for MCP
32
34
 
33
35
  ---
34
36
 
35
- ## What's new in v1.36
37
+ ## What's new in v1.37
38
+
39
+ - **Tools act on your project** — MCP tools resolve relative paths and default folders against the folder the host launched them in, not the plugin's install folder. Phantom fleet worktrees are no longer refused.
40
+ - **Faster hooks** — each SessionStart and PostToolUse event starts one `node` launcher instead of one per hook (CPU per native Edit 712 → 319 ms in a Linux container), and SessionStart exits in about 0.6 s instead of 2.1 s.
41
+ - **Claude Code hooks detected correctly** — hooks under Claude Code no longer run in Codex nudge mode.
42
+ - **Works without Bun on PATH** — the npm bins start under node and find or explain Bun instead of failing with `env: 'bun'`.
43
+ - **Readable grep fallback** — `ashlr__grep` without a genome returns plain `path:line:text` matches, says when ripgrep stopped early, and is benchmarked against plain `rg -n` (about −27% per call).
44
+ - **Shorter edit replies** — exact, unique `ashlr__edit` matches return the header only.
45
+ - **New host ids** — `ASHLR_MCP_HOST=gemini-cli` and `cursor`.
46
+
47
+ See the [CHANGELOG](CHANGELOG.md) for the full list.
48
+
49
+ <details>
50
+ <summary>v1.36 highlights</summary>
36
51
 
37
52
  - **Codex-native plugin packaging** — `.codex-plugin/plugin.json`, `.mcp.json`, Codex workflow skills, Codex explorer/worker agent guidance, and portable Codex hooks ship in the same package as the Claude Code plugin.
38
53
  - **Reliable Codex MCP launch** — `ashlr-mcp` starts the router directly with `ASHLR_MCP_HOST=codex-cli`, workspace-aware `cwd` behavior, and `ASHLR_ALLOW_PROJECT_PATHS` support for non-plugin launch directories.
@@ -44,6 +59,8 @@ The npm package exposes `ashlr-plugin` for CLI workflows and `ashlr-mcp` for MCP
44
59
  - **API-measured savings mode** — when `ANTHROPIC_API_KEY` is set, token counts upgrade from `(est.)` to `(API-measured)` once ≥10 calls have been verified via the Anthropic API. Fire-and-forget; SHA-256 cached; never blocks a tool call.
45
60
  - **Benchmark transparency** — `scripts/run-benchmark.ts` now reports a 95% bootstrap confidence interval alongside the headline. New flags: `--compare` (A/B table), `--validate-tokenizer` (API spot-check of the chars/4 heuristic). See [benchmark methodology](docs/benchmarks.md).
46
61
 
62
+ </details>
63
+
47
64
  <details>
48
65
  <summary>v1.33 highlights</summary>
49
66
 
@@ -53,7 +70,7 @@ The npm package exposes `ashlr-plugin` for CLI workflows and `ashlr-mcp` for MCP
53
70
  - **Orchestration retry + handoff budget** — per-node retry-with-backoff; HANDOFF_PAYLOAD capped at 8KB.
54
71
  - **Orchestration central quota accounting** — `orchestration_usage` table for Team-tier soft-throttle.
55
72
  - **Bun ≥ 1.3 prereq surfaced** + wizard restart enforcement — closes 2 fatal first-touch cliffs.
56
- - **Orchestrator overhead bench** — measured ~5-30ms/node, 2.8× parallel speedup vs sequential.
73
+ - **Orchestrator overhead bench** — per-node overhead and parallel speedup are measured by the orchestrator bench; no figure is published here until it is reproducible from this repo.
57
74
  - **Pre-existing tsc errors fixed** + permanent dashboard date-drift fix via clock injection.
58
75
 
59
76
  </details>
@@ -64,13 +81,13 @@ The npm package exposes `ashlr-plugin` for CLI workflows and `ashlr-mcp` for MCP
64
81
  <summary>v1.32 highlights</summary>
65
82
 
66
83
  - **`/ashlr-orchestrate`** — multi-agent task graphs with parallel execution, dry-run renderer, and tier-gated subprocess wiring.
67
- - **`/ashlr-orchestrate-status`** — inspect past orchestration runs with per-node telemetry and 2.8× measured parallel speedup.
84
+ - **`/ashlr-orchestrate-status`** — inspect past orchestration runs with per-node telemetry.
68
85
  - **Live genome** — PR-aware + commit-aware sections via git post-commit hook and GitHub webhook delta sync.
69
86
  - **AI-Native discoveries** — LLM synthesizes `discovery` sections from your commit history automatically.
70
87
  - **Predictive prefetch** *(Pro/Team)* — background warm-cache on every `ashlr__read` cuts repeat-hit latency.
71
88
  - **PR + issue retrieval** — `ashlr__grep --include-prs --include-issues --since-days` pulls live GitHub context.
72
89
  - **Freshness badges** in genome retrieval surface staleness so you trust the answer.
73
- - **Cross-language bench:** TS −61.3% · Python −63.1% · Rust −46.8% (cross-language headline `-57.1%` holds).
90
+ - **Cross-language bench (per-call, not end to end):** TS −61.3% · Python −63.1% · Rust −46.8%, about −57% averaged across tool calls. This is not a measured reduction in total session cost.
74
91
  - **Founder WAD-D dashboard** at `/admin/wad-d` — daily-active records + segment breakdown + discovery propagation.
75
92
 
76
93
  </details>
@@ -270,6 +287,22 @@ cd ~/.claude/plugins/cache/ashlr-marketplace/ashlr && bun install
270
287
 
271
288
  ---
272
289
 
290
+ ## Provider base URLs
291
+
292
+ The plugin's own provider calls (the summarizer and token-count calls to Anthropic, the genome reachability probes for Anthropic and OpenAI, and the Ollama checks in `/ashlr-ollama-setup` and `genome-init`) read the usual environment variables and keep their old defaults when none is set:
293
+
294
+ | Variable | Default | Form |
295
+ |---|---|---|
296
+ | `ANTHROPIC_BASE_URL` | `https://api.anthropic.com` | root, without `/v1` |
297
+ | `OPENAI_BASE_URL` | `https://api.openai.com/v1` | includes `/v1` |
298
+ | `OLLAMA_HOST` | `http://localhost:11434` | `host`, `host:port`, `:port` or a full URL |
299
+
300
+ Trailing slashes are trimmed. Pointing these at a gateway such as a LiteLLM proxy or a Phantom proxy is therefore possible, because the plugin just sends its requests to whatever URL you set. Only the URL handling is covered by tests here; the plugin has not been tested against any specific gateway, and what a gateway does with your keys and requests is documented by that gateway. Not covered: the Ollama probe in the session greeting and the optional `ASHLR_EMBED_URL` embedding endpoint, which keep their own settings.
301
+
302
+ `/ashlr-doctor` also lists whether the optional Phantom CLI is installed and which version. It runs only `phantom --version` and never reads or reveals secret values. To run tools with Phantom placeholder keys and base URLs, start them with `phantom exec -- <cmd>`.
303
+
304
+ Running the doctor and benchmark scripts under Phantom is supported only through `phantom exec`, for example `phantom exec -- bun run scripts/doctor.ts` or `phantom exec -- bun run scripts/run-benchmark.ts --validate-tokenizer`. Inside such a session the doctor's `phantom exec` line reports the proxy port, which provider keys hold `phm_` placeholders and which base URLs point at the local proxy (with the session token redacted). It warns when a key is a `phm_` placeholder outside a session, when a placeholder's base URL does not point at the proxy, or when a key is a `phm:` reference. The plugin never resolves `phm:` references, never runs `phantom reveal` and never prints key values; `run-benchmark --validate-tokenizer` skips the API sample when the key would not work from that process. Detection uses variable names, the `phm` prefixes and the base URL host and port only; it has not been tested against a live Phantom session here.
305
+
273
306
  ## Commands
274
307
 
275
308
  | Command | Description |
@@ -281,7 +314,7 @@ cd ~/.claude/plugins/cache/ashlr-marketplace/ashlr && bun install
281
314
  | `/ashlr-doctor` | 11-check diagnostic — deps, MCP reachability, hooks, settings |
282
315
  | `/ashlr-tour` | 60-second guided walkthrough on your current project |
283
316
  | `/ashlr-benchmark` | Token-savings benchmark against your current project |
284
- | `/ashlr-genome-init` | Initialize `.ashlrcode/genome/` for the −84% grep path |
317
+ | `/ashlr-genome-init` | Initialize `.ashlrcode/genome/` for the genome-backed grep path |
285
318
  | `/ashlr-ollama-setup` | Diagnose Ollama for `--summarize`; pull recommended 3B model |
286
319
  | `/ashlr-settings` | View or change plugin toggles |
287
320
  | `/ashlr-update` | `git pull` + `bun install` + report what changed |
@@ -306,6 +339,14 @@ See [plugin.ashlr.ai/docs/contributing/architecture](https://plugin.ashlr.ai/doc
306
339
 
307
340
  See [CHANGELOG.md](./CHANGELOG.md) for version history.
308
341
 
342
+ ## Part of the Ashlr ecosystem
343
+
344
+ The Ashlr plugin is one of the open-source tools from [Ashlr](https://ashlr.ai), a forward-deployed engineering company. Its siblings: [Lexicon](https://github.com/ashlrai/lexicon), [Locus](https://github.com/ashlrai/locus), [Phantom Secrets](https://github.com/ashlrai/phantom-secrets), [Ashlr Stack](https://github.com/ashlrai/ashlr-stack), [Ashlr Markdown](https://github.com/ashlrai/ashlr-md).
345
+
346
+ ## Contributing
347
+
348
+ Issues and PRs are welcome. Look for [`good first issue`](https://github.com/ashlrai/ashlr-plugin/labels/good%20first%20issue) to get started, and read [CONTRIBUTING.md](CONTRIBUTING.md). Report security problems privately per [SECURITY.md](SECURITY.md).
349
+
309
350
  ## License
310
351
 
311
352
  MIT — [LICENSE](./LICENSE).
@@ -25,6 +25,35 @@ Steps:
25
25
 
26
26
  4. If the script itself exits non-zero (couldn't find the plugin root at all), print the stderr and stop — nothing else will work until that's resolved.
27
27
 
28
+ ## Companions
29
+
30
+ The **companions** section lists the other Ashlr tools on this machine:
31
+ phantom (`phm`), phantom-secrets (`phantom`), locus, lexicon, ashlr-md
32
+ (`mdopener-mcp`) and ashlr-stack (`stack`). Each is asked for
33
+ `--ashlr-handshake --json` with a 2 second timeout and an environment of only
34
+ PATH, HOME, USER, locale and TMPDIR, so no token reaches it.
35
+
36
+ - `✓ locus 0.5.1 ready [capabilities]`: answered and healthy.
37
+ - `· name 0.6.0 health: degraded`, `installed, too old for --ashlr-handshake`,
38
+ `installed, handshake unreadable or timed out`, or `not installed`: shown
39
+ with a one-line `fix:` hint. All probes run in parallel, so the section
40
+ takes about 2 seconds at most.
41
+ - When locus, lexicon or ashlr-md reports health other than `ok` and lists
42
+ the `doctor-fix` capability, its hint is `run locus doctor --fix`,
43
+ `run lexicon doctor --fix` or `run mdopener-mcp doctor --fix` (a dry run;
44
+ `--apply` makes the repairs). The hint keys on the capability only, never on the
45
+ version, and a healthy companion gets nothing extra. Same rule as
46
+ `stack doctor --ecosystem`.
47
+
48
+ These lines are informational: they never count as warnings or failures and
49
+ never change the exit code. `bun run scripts/doctor.ts --json` prints the whole
50
+ report as JSON, with a `companions` array of
51
+ `{ name, command, state, version, capabilities, health, fix, next_steps }`
52
+ where `state` is `ready`, `degraded`, `outdated` (printed no JSON),
53
+ `unknown` (timed out, or printed JSON that is not a v1 handshake) or
54
+ `missing`, `health` is the handshake's `health.status` (null without one),
55
+ and `next_steps` lists capability-gated commands (empty when there are none).
56
+
28
57
  ## Cloud check
29
58
 
30
59
  The report includes a **cloud** section that pings `GET /healthz` on the
@@ -16,7 +16,7 @@ Format:
16
16
  ```
17
17
  ashlr-plugin v0.1.0
18
18
  server: ✓ reachable
19
- genome: ✓ (.ashlrcode/genome found) | ✗ (no genome — run `/genome init`)
19
+ genome: ✓ (.ashlrcode/genome found) | ✗ (no genome — run `/ashlr-genome-init`)
20
20
  core: @ashlr/core-efficiency@0.1.0
21
21
  session: 12 calls, ~8,450 tokens saved
22
22
  ```
@@ -0,0 +1,58 @@
1
+ # Using ashlr-plugin with Phantom
2
+
3
+ This page covers running the plugin under Phantom Secrets (`phantom exec`, `phm_` placeholders) and in front of a model gateway such as LiteLLM. For the full provider and gateway rules see [llm-providers.md](llm-providers.md) and [embeddings-gateway.md](embeddings-gateway.md).
4
+
5
+ ## Running under `phantom exec`
6
+
7
+ Start the agent, or a plugin script, as `phantom exec -- <cmd>`, for example `phantom exec -- claude`. Phantom then does three things:
8
+ - It gives the child fresh `phm_` session placeholders instead of real keys, for example in `ANTHROPIC_API_KEY` and `OPENAI_API_KEY`.
9
+ - It points `ANTHROPIC_BASE_URL` and `OPENAI_BASE_URL` at a local proxy: `http://127.0.0.1:<port>/<route>/_phantom/<token>/`.
10
+ - It sets `PHANTOM_PROXY_PORT`, `PHANTOM_PROXY_TOKEN` and `PHANTOM_SESSION_KEYS`.
11
+
12
+ The plugin sends the placeholder unchanged, and the proxy swaps in the real key on the way out. The proxy URL is loopback http, so it passes the plugin's base URL rules.
13
+
14
+ How the plugin behaves in a session:
15
+ - **Detection by name and prefix only.** `servers/_phantom-exec.ts` detects a session from variable names, the `phm_` and `phm:` prefixes, and the base URL host and port. It never reads or prints a key, and it redacts the proxy token from any URL it reports.
16
+ - **The doctor reports the session.** `/ashlr-doctor` shows a `phantom exec` line and warns, without values, about two cases: a `phm_` placeholder outside a session, and a placeholder whose base URL does not point at the session's proxy.
17
+ - **The benchmark skips unusable keys.** `run-benchmark --validate-tokenizer` skips its API sample when the key would not work, and says why.
18
+ - **`phm:` references are never resolved.** A `phm:` reference in a key variable is not resolved and is never sent. Run under `phantom exec` so the variable holds a placeholder instead.
19
+ - Do not use `phantom reveal` to put a real key into the environment for the plugin.
20
+
21
+ ## Settings that exist
22
+
23
+ | Variable | Default | What it is |
24
+ |---|---|---|
25
+ | `ANTHROPIC_BASE_URL` | `https://api.anthropic.com` | Anthropic root, without `/v1` |
26
+ | `ANTHROPIC_API_KEY` | unset | Anthropic key, or a `phm_` placeholder under `phantom exec` |
27
+ | `OPENAI_BASE_URL` | `https://api.openai.com/v1` | OpenAI-compatible root, with `/v1` |
28
+ | `OPENAI_API_KEY` | unset | OpenAI key, or a `phm_` placeholder |
29
+ | `OLLAMA_HOST` | `http://localhost:11434` | Ollama: `host`, `host:port`, `:port` or a full URL; keyless |
30
+ | `ASHLR_LLM_URL` | `http://127.0.0.1:1234/v1` | Local OpenAI-compatible server for summarization, orient and genome merging |
31
+ | `ASHLR_LLM_KEY` | `local-llm` | Bearer for `ASHLR_LLM_URL` |
32
+ | `ASHLR_LLM_MODEL` | `qwen/qwen3-coder-30b@8bit` | Model name for `ASHLR_LLM_URL` |
33
+ | `ASHLR_API_URL` | `https://api.ashlr.ai` | Ashlr cloud API (Pro) |
34
+ | `ASHLR_PRO_TOKEN` | unset | Ashlr Pro token |
35
+ | `ASHLR_EMBED_URL`, `ASHLR_EMBED_FORMAT=openai`, `ASHLR_EMBED_KEY`, `ASHLR_EMBED_MODEL` | Ollama format | Opt-in OpenAI-compatible embeddings ([embeddings-gateway.md](embeddings-gateway.md)) |
36
+ | `ASHLR_GATEWAY_STRICT=1`, `ASHLR_GATEWAY_HOSTS` | off | Strict allowlist for any call that carries a key |
37
+
38
+ The base rules apply to calls that carry a key, even without strict mode:
39
+ - `https`, or plain `http` only to `127.0.0.1` or `[::1]`. The name `localhost` does not count.
40
+ - No credentials in the URL.
41
+ - No redirects followed.
42
+
43
+ A refused URL makes no request, and the refusal names only the scheme, host and port.
44
+
45
+ ## LiteLLM
46
+
47
+ If a LiteLLM proxy sits between the plugin and the providers, use LiteLLM 1.83.0 or newer, never 1.82.7 or 1.82.8.
48
+
49
+ - **Why 1.83.0:** `litellm` 1.82.7 and 1.82.8 on PyPI were compromised releases that carried credential-stealing code (GHSA-5mg7-485q-xm76, March 2026). 1.83.0, published to PyPI on 2026-03-31, was the first clean release, built by LiteLLM's rebuilt release pipeline ([LiteLLM security update](https://docs.litellm.ai/blog/security-update-march-2026)).
50
+ - **Use a current release, not just 1.83.0.** Later advisories were fixed in later releases (for example GHSA-3cv6-jpf6-8222). On 2026-10-19 the current PyPI release was 1.106.0. Check LiteLLM's security advisories before you pick or upgrade a version.
51
+ - **Install it verifiably.** Use a hash-pinned install (`pip install --require-hashes -r requirements.txt`) or the official `ghcr.io/berriai/litellm` image, checked with `cosign verify` as LiteLLM's README shows. Run it in a container that does not mount your home directory or dotfiles.
52
+ - Keep the provider keys on the LiteLLM side. Give the agent only the proxy URL and, if the proxy needs one, a proxy key that is separate from the provider keys.
53
+
54
+ To route the plugin's local-provider calls through LiteLLM, set `ASHLR_LLM_URL=http://127.0.0.1:4000/v1` (LiteLLM's default port) and `ASHLR_LLM_KEY` to the proxy key. For a remote LiteLLM, use `https://` and, with `ASHLR_GATEWAY_STRICT=1`, list its exact `host:port` in `ASHLR_GATEWAY_HOSTS`.
55
+
56
+ ## What is tested
57
+
58
+ Session detection, the doctor line, the benchmark skip and the URL rules are covered by tests against local stub servers (`__tests__/phantom-exec.test.ts`, `__tests__/doctor-phantom.test.ts`, `__tests__/gateway-target.test.ts`). The plugin has not been tested against a live Phantom session or a live LiteLLM proxy here.
@@ -12,7 +12,7 @@ ashlr-plugin is a multi-host plugin for Codex and Claude Code that wraps file, s
12
12
 
13
13
  Two value propositions:
14
14
 
15
- **Token efficiency.** `ashlr__read`, `ashlr__grep`, and `ashlr__edit` replace the built-in `Read`, `Grep`, and `Edit` tools. Large file reads are snip-compacted or LLM-summarized; grep calls route through a per-project genome index (RAG) when one exists, cutting tokens by ~84% on warm queries; edits send only diffs, not full file contents.
15
+ **Token efficiency.** `ashlr__read`, `ashlr__grep`, and `ashlr__edit` replace the built-in `Read`, `Grep`, and `Edit` tools. Large file reads are snip-compacted or LLM-summarized; grep calls route through a per-project genome index (RAG) when one exists, cutting tokens on warm queries (not covered by the published benchmark); edits send only diffs, not full file contents.
16
16
 
17
17
  **Observability.** Every tool call is accounted in `~/.ashlr/stats.json` (per-session + lifetime counters) and appended to `~/.ashlr/session-log.jsonl`. Claude Code surfaces savings in the status line; Codex surfaces them through MCP tools, CLI commands, and skills. The genome scribe loop extracts architectural knowledge from tool results into `.ashlrcode/genome/`, which feeds back into future grep routing.
18
18
 
@@ -206,7 +206,7 @@ SessionEnd
206
206
  └──► hooks/session-end-stats-gc.ts (drop session bucket, append summary to log)
207
207
  ```
208
208
 
209
- PreToolUse hooks are matcher-filtered — Claude Code only fires them for the named tool. PostToolUse has a pipe-separated matcher covering both native tools and the ashlr MCP variants (canonical prefix `mcp__plugin_ashlr_ashlr__ashlr__*` as of v1.13 router consolidation; all matchers in `hooks/hooks.json` renamed to this form in v1.18 after legacy `mcp__ashlr-efficiency__*` / `mcp__ashlr-multi-edit__*` stopped matching post-router-migration).
209
+ PreToolUse hooks are matcher-filtered — Claude Code only fires them for the named tool. SessionStart and PostToolUse each have one entry that runs `scripts/hook-bootstrap.mjs --group`: a single node launcher starts every hook for the event as its own `bun` process, in parallel, and merges their output. In PostToolUse a `--match` before a hook keeps that hook's own tool filter, and the entry's matcher is the union of them. PostToolUse has a pipe-separated matcher covering both native tools and the ashlr MCP variants (canonical prefix `mcp__plugin_ashlr_ashlr__ashlr__*` as of v1.13 router consolidation; all matchers in `hooks/hooks.json` renamed to this form in v1.18 after legacy `mcp__ashlr-efficiency__*` / `mcp__ashlr-multi-edit__*` stopped matching post-router-migration).
210
210
 
211
211
  ---
212
212
 
@@ -301,7 +301,7 @@ Source: `servers/_summarize.ts`.
301
301
 
302
302
  **When it fires.** Each tool that handles large output (read, grep, edit, bash, sql, diff) checks if the raw result exceeds ~2KB. If so it calls `summarize(content, toolName)`.
303
303
 
304
- **Local-first.** Default endpoint is `http://localhost:1234/v1` (LM Studio). Override via `ASHLR_LLM_URL` + `ASHLR_LLM_KEY` for cloud. Cloud only fires when explicitly set; the plugin has no account requirement and telemetry is off by default.
304
+ **Local-first.** Default endpoint is `http://127.0.0.1:1234/v1` (LM Studio). Override via `ASHLR_LLM_URL` + `ASHLR_LLM_KEY` for cloud. Cloud only fires when explicitly set; the plugin has no account requirement and telemetry is off by default.
305
305
 
306
306
  **Cache.** SHA-256 of the input is used as cache key. Cache files live at `~/.ashlr/summary-cache/<hash>.txt` with a 1-hour TTL. A cache hit costs zero tokens.
307
307
 
@@ -375,7 +375,7 @@ Version bumping is manual: edit `plugin.json:version` and `CHANGELOG.md` before
375
375
 
376
376
  These are the non-obvious decisions baked into the codebase.
377
377
 
378
- **Local-first LLM, opt-in telemetry.** The summarization helper calls `localhost:1234` by default. No summarization payload leaves the machine unless the user explicitly sets `ASHLR_LLM_URL`; telemetry is off by default and has to be enabled separately.
378
+ **Local-first LLM, opt-in telemetry.** The summarization helper calls `127.0.0.1:1234` by default. No summarization payload leaves the machine unless the user explicitly sets `ASHLR_LLM_URL`; telemetry is off by default and has to be enabled separately.
379
379
 
380
380
  **Atomic stats writes.** A two-layer write protocol (in-process Promise chain + `O_EXCL` lockfile + `rename`) ensures that N concurrent MCP servers and hooks never corrupt `stats.json`. Any approach that just does `JSON.parse` → mutate → `writeFile` will lose updates under load. The lockfile spin is capped at 200ms; if it can't acquire, it skips the write rather than blocking the tool call.
381
381
 
@@ -391,7 +391,7 @@ These are the non-obvious decisions baked into the codebase.
391
391
 
392
392
  ## Supported Platforms
393
393
 
394
- ashlr-plugin is tested in CI on three operating systems via a matrix strategy in `.github/workflows/ci.yml`. The `typecheck`, `test`, and `smoke` jobs all run on every OS on every push.
394
+ ashlr-plugin is tested in CI on three operating systems in `.github/workflows/ci.yml`. Typecheck, unit tests and smoke run on Linux for every PR and on macOS and Windows for every push to main, the weekly schedule, and PRs labelled `ci:full-os`.
395
395
 
396
396
  | Platform | Runner | Status |
397
397
  |---|---|---|
@@ -0,0 +1,36 @@
1
+ # Ashlr companion handshake (v1)
2
+
3
+ `ashlr-plugin --ashlr-handshake` prints one JSON object and exits 0. `phm companions`,
4
+ `phm doctor` or an agent can call it instead of parsing `--help`. The same
5
+ contract is implemented by `stack --ashlr-handshake` (ashlr-stack) and
6
+ `locus --ashlr-handshake`.
7
+
8
+ ```json
9
+ {
10
+ "kind": "ashlr.handshake",
11
+ "schema_version": 1,
12
+ "name": "ashlr-plugin",
13
+ "command": "ashlr-plugin",
14
+ "version": "1.37.1",
15
+ "protocols": { "ashlr.handshake": 1, "phantom.agent.preflight": 1 },
16
+ "capabilities": ["token-efficient-tools", "mcp-server", "claude-code-plugin", "codex-install", "savings-stats", "agent-preflight", "doctor"],
17
+ "health": { "status": "ok", "checks": [{ "id": "bun-on-path", "status": "ok" }, { "id": "phantom-on-path", "status": "absent" }] },
18
+ "edits": ["~/.ashlr/", "~/.claude/settings.json", "~/.codex/config.toml"],
19
+ "receipts": []
20
+ }
21
+ ```
22
+
23
+ Rules every implementation follows:
24
+
25
+ - **Fast and local:** no network, no vault or keychain, and no secret values or project contents in the output.
26
+ - **Stable shape:** `kind` and `schema_version` identify the contract. New fields may be added in v1; renames or removals bump `schema_version`.
27
+ - **Ids:** `capabilities` and check `id`s are kebab-case. `protocols` maps a protocol name to the version spoken.
28
+ - **Health:** `health.status` is `ok`, `degraded` (works, something it relies on is missing) or `unknown`. A check status is `ok`, `missing` (counts against health) or `absent` (informational, such as phantom not installed when ASHLR_PHANTOM_PREFLIGHT is off).
29
+ - **Edits:** paths the CLI may write. `~/` is the home directory; other paths are relative to the project.
30
+ - **Receipts:** receipt kinds the CLI emits (none yet; reserved for receipt.v1).
31
+
32
+ The npm launcher (`scripts/ashlr-plugin.mjs`, plain node) answers before it looks for bun, so a machine without bun gets `bun-on-path: missing` and `degraded` instead of an error.
33
+
34
+ ## Consumers
35
+
36
+ `ashlr doctor` reads companions through this handshake (see commands/ashlr-doctor.md, "Companions"), as does `stack doctor --ecosystem`.
@@ -32,7 +32,7 @@
32
32
 
33
33
  <!-- Sub -->
34
34
  <text x="80" y="490" font-family="IBM Plex Sans, sans-serif" font-size="24" fill="#121212" opacity="0.8" font-weight="400">Open-source Codex + Claude Code plugin — token-efficient Read, Grep, Edit.</text>
35
- <text x="80" y="524" font-family="IBM Plex Sans, sans-serif" font-size="24" fill="#121212" opacity="0.55">Mean −57% savings across reference repos.</text>
35
+ <text x="80" y="524" font-family="IBM Plex Sans, sans-serif" font-size="24" fill="#121212" opacity="0.55">Per-call: reads about −75%, greps about −50%.</text>
36
36
 
37
37
  <!-- Bottom strip: install commands -->
38
38
  <line x1="80" y1="570" x2="1120" y2="570" stroke="#121212" stroke-opacity="0.15" stroke-width="1" />