Repository navigation
First release published to npm through trusted publishing (OIDC). npm had 1.36.4; 1.36.5 and 1.37.0 were tagged before the npm-publish job existed.
Documentation
docs/PHANTOM-USAGE.md: using the plugin underphantom exec(placeholders, session detection,phm:references not resolved), the base URL and key settings that exist, and LiteLLM 1.83.0 or newer (prefer a current release).
Security
- The Anthropic summarizer no longer falls back to the Claude Code OAuth token (
~/.claude/.credentials.json) whenANTHROPIC_BASE_URLpoints anywhere other thanhttps://api.anthropic.com. With a LiteLLM or other proxy configured and noANTHROPIC_API_KEY, that token was sent to the proxy asx-api-key. SetANTHROPIC_API_KEY(or aphm_placeholder) to use a proxy. ashlr__orientno longer reads anendpointOverridetool argument. A model could pass it to choose where the local-LLM key and project excerpts were sent. The endpoint now comes only fromASHLR_LLM_URL.ashlr__genome_consolidateno longer uses itsmodelargument as an endpoint URL. A model could pass a URL there to choose where the local-LLM key and genome content were sent.modelnow only selectsnone(offline) or LLM merging; the endpoint comes only fromASHLR_LLM_URL.- The "local LLM unreachable" stderr warning names the endpoint as
scheme://host:portonly. It printed the fullASHLR_LLM_URL, including any credentials, path or query. scripts/genome-key.ts import <genomeId>reads the team key from stdin (hidden at a terminal, or piped), so it no longer has to be passed as an argument, where other local users could see it inpsand it stayed in shell history. A key given as a third argument still works but prints a warning. An invalid key is rejected without echoing any of it.server/src/cli/cap-check.tsreads the user API token from stdin (hidden at a terminal, or piped) instead of requiring it as an argument, where other local users could see it inpsand it stayed in shell history. A token given as an argument still works but prints a warning. The token is never printed.- The Anthropic and cloud summarizers redact key material from an endpoint's error body before putting it in the thrown error. A gateway that quoted the rejected
x-api-keyor pro token back in a 401 put it into the error message. Any run of 8 or more characters found in a configured key (ASHLR_LLM_KEY,ANTHROPIC_API_KEY,OPENAI_API_KEY,ASHLR_EMBED_KEY,ASHLR_PRO_TOKEN,PHANTOM_PROXY_TOKEN, or the~/.ashlr/pro-tokenfile) is replaced with[redacted]. A new test drives every keyed caller through each gateway refusal and network-error path and fails if any key appears in an error, a return value, stdout or stderr. scripts/deploy-smoke.shsends theASHLR_TOKENbearer header to curl through a config on stdin instead of a-Hargument, so the token is no longer visible to other local users inps.
Changed
ashlr-plugin codex-doctor(text output) adds anMCP launchline saying whetherashlr-mcp, the command in the plugin's.mcp.json, is on PATH. When it is not, the line gives the fix: install the package bin, or point the host at the printed source-checkout command. Report-only: theokverdict and the--jsonreport are unchanged.ashlr__orient's LLM call follows the gateway rules on the default path:ASHLR_LLM_URLmust be https, or http only to127.0.0.1or[::1]; credentials in the URL are refused; redirects are not followed. The default is nowhttp://127.0.0.1:1234/v1(washttp://localhost:1234/v1). Breaks a documented use:ASHLR_LLM_URL=http://localhost:...is refused for orient (it falls back to its plain file summary); usehttp://127.0.0.1:...instead.ashlr__genome_consolidate's LLM merge follows the same rules on the default path, with the samehttp://127.0.0.1:1234/v1default. Breaks two documented uses: passing a base URL asmodel(for examplehttp://localhost:1234/v1) no longer selects the endpoint, so setASHLR_LLM_URLinstead; andASHLR_LLM_URL=http://localhost:...is refused, so genome merging falls back to sequential-apply. Usehttp://127.0.0.1:....- The keyed Anthropic and OpenAI calls (summarizer, token measurement, genome auto-consolidate reachability probes) follow the same default-path rules for
ANTHROPIC_BASE_URLandOPENAI_BASE_URL: https, or http only to127.0.0.1or[::1]; credentials in the URL are refused; redirects are not followed, sox-api-keynever follows one. The defaults and the Phantom proxy (http://127.0.0.1:<port>/...) are unaffected. Breaks a documented use: a gateway on plain http to any other host, includinghttp://localhost:..., is refused (the call fails like a network error and falls back); usehttp://127.0.0.1:...or https. - The pro-token cloud route (
ASHLR_API_URL), the local provider (ASHLR_LLM_URL, probe and chat) and the internal legacy summarizer endpoint follow the same default-path rules, so the pro token andASHLR_LLM_KEYgo only to https or to127.0.0.1/[::1]and never follow a redirect. The local default is nowhttp://127.0.0.1:1234/v1(washttp://localhost:1234/v1); the hosted defaulthttps://api.ashlr.aiis unchanged. Breaks a documented use:ASHLR_LLM_URLorASHLR_API_URLset to plain http on any other host, includinghttp://localhost:..., is refused and summarization falls back to truncation; usehttp://127.0.0.1:...or https.
Added
- Opt-in OpenAI-compatible embeddings (
ASHLR_EMBED_FORMAT=openai, off by default), for a LiteLLM proxy or any/v1/embeddingsserver. The plugin POSTs{ model, input }to<ASHLR_EMBED_URL>/embeddingswith an optionalASHLR_EMBED_KEY, under the gateway rules: https, or http only to127.0.0.1/[::1]; no credentials in the URL; no redirects. Strict mode adds the allowlist. A Phantomphm_placeholder is sent unchanged for the proxy to swap. Aphm:reference is never resolved. The key and the embedded text are never logged. Without the variable the Ollama format is unchanged. See docs/embeddings-gateway.md. - Opt-in strict gateway targets for keyed model calls (
ASHLR_GATEWAY_STRICT=1, off by default). A key goes only to127.0.0.1/[::1], an exact httpshost:portinASHLR_GATEWAY_HOSTS, or the built-in provider hosts on 443; credentials in the URL and redirects are refused, and refusals name the host only. Covers the local, legacy, Anthropic and cloud providers, token measurement,ashlr__orientandashlr__genome_consolidateendpoints, and the genome auto-consolidate probes. With the variable unset nothing changes. See docs/llm-providers.md. scripts/bench-read-real.tsprints report-only recommended thresholds for the read redirect (current 2048 B) and the TS/JS AST skeleton (current 6144 B), derived by break-even over 256 B size bins with at least 3 files each, plus how they were derived and the caveat that they come from this repo's own files with estimated tokens. No default changes.--no-thresholdsskips the extra AST reads.ashlr doctorandrun-benchmark --validate-tokenizerrecognise aphantom exec -- <cmd>session from variable names,phmprefixes and the proxy host and port: the doctor adds aphantom execline (proxy port, placeholder key names, proxied base URLs with the session token redacted) and warns for a placeholder outside a session, a placeholder whose base URL bypasses the proxy, or aphm:reference. Nothing is resolved or revealed and no value is printed. The benchmark skips its API sample when the key would not work.ashlr doctorshows whether the optional Phantom CLI is installed and its version, in the install section. It only runsphantom --version. It never runsphantom reveal, never reads the vault or.envfiles, and never captures secret values. Absence is not a warning.
Fixed
ashlr doctor's MCP probe no longer leaves bun processes running. It killed only the direct child, so whenbunon PATH was a shell shim (pnpm or npm global installs) the real bun survived as a grandchild, and when the total probe cap fired first nothing was killed at all. Probes now run the bun binary that runs doctor, in their own process group, and the whole group is killed on timeout or when the cap fires.runWithTimeouttakes an optional abort signal for this.- Path refusals ("refused path outside working directory") now come back with
isError: truefrom every tool, so hosts and agents see a failed call. Most tools returned the refusal as an ordinary successful result. ashlr__writeacceptspathas well asfilePath, the nameashlr__readandashlr__edituse. Called withpath, it used to fail withEISDIRbecause the missingfilePathresolved to the project folder. A missing path or non-string content now returns a clear error.- The block message from the Write, NotebookEdit and other redirect hooks names the right setting:
ASHLR_HOOK_MODE=nudge, or"hookMode": "nudge"in~/.ashlr/config.json. It used to suggest putting the environment variable name in that file. - The router reports the plugin version in MCP
serverInfoand its startup line instead ofdev.ASHLR_VERSIONstill overrides it.