Commit Graph

37 Commits

Author SHA1 Message Date
Julius Brussee d6c1cd39af fix(cli): launch direct when a foreign process owns the proxy port
A foreign listener on 127.0.0.1:8787 used to get the banner but still
receive the routed launch, which would send the operator's provider
keys to a process caveman does not own (#945). Treat it like a gate
mismatch and fall back to a direct launch.

Also: Claude Code refuses Remote Control behind any non-first-party
ANTHROPIC_BASE_URL, so `caveman claude remote-control` launches direct
and the limitation is documented (#947); caveman-compress reads the
first text block instead of content[0] so a leading tool_use block no
longer crashes after a paid call (closes #932's report); hook checksum
manifest regenerated after #794.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:25:28 +02:00
Julius Brussee c24123dd2b Merge remote-tracking branch 'origin/main'
# Conflicts:
#	README.md
#	docs/technical/agent-profile-registry.md
#	packages/cli/src/index.ts
#	packages/cli/tests/subscription-recovery.runtime.mjs
#	proxy/internal/gateway/chatgpt.go
#	proxy/internal/gateway/proxy.go
#	proxy/internal/gateway/retrieve_tool.go
#	proxy/internal/gateway/server.go
#	proxy/internal/gateway/subscription_live_zone_test.go
2026-09-02 15:19:57 +02:00
Julius Brussee d9faebc2b2 docs(readme): rewrite the front door around measured savings
Two-size install story, a What-you-save section with static SVG charts
rendered from the committed benchmark table, and plain-language copy
for non-programmers. Charts regenerate with benchmarks/render_charts.py.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:18:19 +02:00
Julius Brussee 41819dcba0 feat(proxy): prove MCP recovery from the request tool list
A bare proxy serves whichever client connects, so a machine-level MCP
install marker can never bind to one request. Read the namespaced
caveman retrieve tool out of the request's own tool list instead, so
subscription and OAuth sessions on a standalone proxy reach the live
zone when their agent carries the tool (#908).

Cache-breakpoint planning and the provider-native cache optimizers now
default on in optimization modes; explicit off and unknown values still
fail closed, and record mode never runs them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:18:19 +02:00
Zsolt Gaspar 455f462407 docs(proxy): document built-in opencode-go compat mount
The proxy now registers /compat/opencode-go/ with a default upstream
and the OPENCODE_API_KEY credential variable. Add the mount and the
user override to the provider docs. Add the variable to the
credential list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>
2026-09-01 21:49:47 +02:00
Julius Brussee be2f788161 fix(cli): guard Kilo managed routing 2026-08-30 06:07:35 +02:00
Julius Brussee ca51a04ed2 fix(cli): guard Kilo route overrides 2026-08-30 05:46:42 +02:00
Julius Brussee facc597029 fix(cli): guard Qwen route overrides 2026-08-30 05:29:20 +02:00
Julius Brussee 9d5028bfae docs(proxy): document Qwen Code wrapping 2026-08-30 01:44:53 +02:00
Julius Brussee d11cce7354 docs(proxy): document Kilo Code wrapping 2026-08-30 01:05:12 +02:00
Julius Brussee e11d0029f9 fix: harden weekly integrations and prepare v2.4.0 2026-08-29 21:57:23 +02:00
Julius Brussee aaef42dbe9 Merge remote-tracking branch 'origin/pr/904' into codex/weekly-triage-20260829 2026-08-29 21:31:33 +02:00
Julius Brussee 81536f57b3 Cleanup 2026-08-25 01:31:19 +02:00
Pavel Filippenko f436843949 fix: scope caveman mode to the session
Mode was applied per session but stored in one file per machine
($CLAUDE_CONFIG_DIR/.caveman-active). Four bugs followed from that one
fact: parallel windows shared a mode; deactivation was spelled "no flag
file", so SessionStart re-derived the configured default and undid an
explicit "stop caveman" after every auto-compaction; the statusline badge
rendered whichever window wrote last; and "off" could not survive a
SessionStart at all.

payload's `source`, but it read the legacy flag, where off is absence — a
deactivated session found nothing stored and fell back to getDefaultMode()
regardless. The other three are consequences of the storage shape, not of
when the hook re-derives.

State now lives in .caveman-sessions/<session_id>.mode, keyed by the
session_id Claude Code puts in every hook payload and in the statusline's
stdin JSON. The legacy flag stays as a last-write-wins compat mirror and
never receives the literal 'off': an older hook reading that would inject
"CAVEMAN MODE ACTIVE (off)" and an older statusline would render
[CAVEMAN:OFF]. Both spellings of off are read everywhere — a missing file
(old) and a literal 'off' (new, durable).

caveman-config.js gains the primitives: validateSessionId (a whitelist,
because a session id becomes part of a path), resolveActiveMode,
readSessionModeRaw, writeSessionMode, per-session prev for one-shot skills
(#599), gcSessionStore, and a session_id-tagged recordModeChange (#601).
Every one takes a sessionId that may be null or malformed and degrades to
the previous machine-wide behavior — the old code path IS the fallback
branch, which is why the existing suites, nonid,
pass unchanged.

SessionStart re-derives the default only on `startup` and `clear`; compact,
resume, fork, an unrecognized source and the n`
read the stored value. Grouping `clear` with the resets deliberately
differs from #691's comment: per-session storage makes the distinction
cheap, and nothing else in the conversation survives /clear either. The
watchdog must not reset, or a slow payload on a compaction re-arms a
session the user turned off.

The three entrypoints resolve the new helpers individually instead of
demanding them in their requireSibling shape checks (#848): a
caveman-config.js from before this change satisfies those checks, so
hard-failing would trade "machine-wide mode, no
state at all" on exactly the plugin-cache drift that guard exists for.

Both statusline ports take session_id from the stdin JSON with bounded,
TTY-guarded reads (integer timeout — bash 3.2 rejects fractional read -t)
and render nothing for a deactivated session. verify_repo.py greps them
against SESSIONS_DIRNAME and SESSION_ID_RE, tws
badge. caveman-stats filters the transition l
window's switches no longer skew another's es
(bin/install.js, uninstall.sh, uninstall.ps1) removes the session store;
.caveman-history.jsonl is kept on purpose. opide
behaviour — it writes its own flag in its own config dir and never sees a
Claude Code session_id.

Tests: 25 unit cases in tests/hooks/caveman-config.test.mjs,
SessionStartSourceTests, SessionScopedModeTests, 5 statusline cases, and
tests/manual/session-mode-smoke.sh (22 checks, end-to-end against a
throwaway config dir). docs/testing-session-modes.md carries the full plan
including the live-Claude-Code checks. Hook ced.

npm test 197/197 · tests/*.js clean · unittesss
· smoke 22/22

Signed-off-by: Pavel Filippenko <filippenko.ps@phystech.edu>
2026-08-24 09:54:58 +03:00
Julius Brussee 6d58b762c5 skill + docs update 2026-08-23 10:07:56 +02:00
Julius Brussee d5c5628e2b chore(docs): remove the GitHub Pages landing page
Delete docs/index.html and docs/.nojekyll. The remaining docs/ tree is Markdown
read on GitHub; nothing in .github/workflows references either file.

Note: if GitHub Pages is configured to serve from main /docs, merging this takes
the published site down. Revert this commit before merging if the site is still
wanted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 10:01:36 +02:00
Julius Brussee 588b353727 docs: add the Cursor Tier 1 support plan
Cursor is the one agent where the distribution table in CLAUDE.md claims more
than caveman delivers: the table says always-on rule, but a Cursor user gets a
per-repo .mdc only via --with-init and the global skills install may not land.

Plan documents ground truth verified on this machine — the empty
~/.cursor/skills, the plugin cache that loaded caveman as an Agent Plugin (skills
and MCP only, hooks ignored), and the IDE transcript format that carries no
usage block — then maps each Cursor surface to its Claude Code counterpart.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 10:01:19 +02:00
Julius Brussee 4164e62eff docs: mark learn v3 as shipped
Record what landed against each item in the plan, where it lives, and the one
item that did not: F6 (learn to runtime policy). The emitter is trivial but
nothing in the wrap or the hooks reads a policy file, so shipping it alone would
be scaffolding for a reader that does not exist. It needs a decision about where
enforcement lives first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 10:01:19 +02:00
Julius Brussee 4a96dc67b7 readme + logo changes 2026-08-21 05:19:51 +02:00
Julius Brussee ce6850dbc6 fix(pi-extension): close the recovery, hook and context leaks; ship on pi-v*
Recovery client. ensure() assigned probed/child only after an await, so N
concurrent callers ran N probes and N spawns and tracked only the last child
— the rest stayed alive as orphans holding ccr.db. One in-flight bring-up is
now shared, dispose() reaps a child that lands late, and a child that fails
or never finishes the handshake is reaped instead of left for the next spawn
to collide with. The handshake also stops borrowing the 30s retrieve budget:
it is awaited inside session_start, so an MCP that starts but never answers
initialize froze Pi startup for the full 30s. 2s, then the session degrades
to "no recovery available".

caveman_retrieve output is no longer shrunk. Its result IS the recovered
original, so masking it hands the model a fresh ccr:// handle and recovery
loops instead of terminating — and registering the tool disables the proxy's
server-side retrieve loop, so nothing else would strip it.

pending context from tool calls accumulates across a whole turn and drains
only at the next before_agent_start; MAX_CONTEXT_BYTES capped one response,
not the join, so a tool-heavy turn built an unbounded system prompt. It now
caps the accumulation.

The stamped hook argv is tried first but no longer alone: it bakes an
absolute [node, …/dist/index.js] at enable time, so an nvm switch made every
hook call ENOENT and the session degraded to permanent silent direct mode.
PATH candidates follow it. Both copies of resolveWindowsCommand (here and in
the CLI) now apply PATHEXT to a *path* too — returning the extensionless
~/.caveman/bin/caveman straight to execFile is the EFTYPE they exist to
prevent.

Release: `pi-v*` tags publish @caveman-ai/pi, with a smoke check that the
tarball actually carries the bundled extension package.json names, plus the
registry-resolved package-lock.json `npm ci` needs (the one generated inside
the pnpm workspace linked to ../../node_modules/.pnpm and would have failed
on a clean checkout). README gains the Pi wrap row (eight native agents) and
drops the Sponsors section.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmbqWDtNexzDfH5V3BMRz
2026-08-20 04:14:49 +02:00
Julius Brussee 216e685646 feat(cli): wire pi as a native host — wrap, enable, doctor, conformance
Pi joins every host surface: NativeAgent unions, capability matrix (incl.
post_tool_rewrite; PostToolUseFailure now returns raw responses for pi and
opencode), native-hook output contracts, Go validAgent +
directOutputRewriteAgent, doctor/status/enable/disable/expectedRoute rows,
and the porcelain agent list (visible cap 7 → 8: '+1 more' rendered longer
than the id it hid).

Wrap door: buildPiWrapArgs prepends the profile-declared loader flag plus the
bundled extension (CAVEMAN_PI_EXTENSION → dist/caveman-pi-extension.mjs),
stamps CAVEMAN_PI_HOOK_CMD + CAVE_GATEWAY_URL, and skips the generic base-URL
env spray — pi routing is extension-side, behind its recovery gate. Missing
asset fails open to a direct launch with a warning; the bundler script fails
the build instead of silently shipping without the asset.

Enable door: journaled write of banner + baked hook invocation + bundle to
~/.pi/agent/extensions/caveman-native.js (Pi auto-discovers only .ts/.js;
.mjs would journal fine and never load). settings.json stays byte-identical.
Status/doctor: pi route health = on-disk artifact ends with the currently
shipped bundle (catches stale bundles after CLI upgrades; the gateway is
resolved at runtime by the extension through the same chain as gatewayURL(),
so enable-time route recording would only manufacture false drift).
hooks install/uninstall pi exit 0 and point at enable/disable — the rewrite
surface ships inside the native extension.

Conformance: pi joins the matrix — a real wrap through the real proxy build
compresses via /w/pi/openai/v1 with a CCR handle booked under agent_slug=pi,
and the stub refuses to run if wrap failed open.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ez7w7BBtKrMZCiZz9ea4cb
2026-08-20 04:14:48 +02:00
Julius Brussee fc7a3cfc92 docs: plan for native Pi integration (@caveman-ai/pi)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ez7w7BBtKrMZCiZz9ea4cb
2026-08-19 11:07:24 +02:00
Julius Brussee 5e3d6b8c27 feat(learn): add multi-source outcome tracking
Upgrade `caveman learn` from a Claude/Codex setup linter into a broader local optimizer. It now scans Gemini, opencode, and opt-in aider history, uses catalog-backed context windows and measured turn-1 prefix evidence, adds new behavioral detectors, and ranks grouped portfolio moves without mixing historical totals into forward rates.

The CLI/proxy/TUI now support `learn applied`, `learn simulate`, `--repo`, per-repo reporting, and confirmed longitudinal fix verdicts (`improved`, `unchanged`, `regressed`, `insufficient_data`). Docs, the embedded `caveman-learn` skill, and tests were updated to cover the new learn v2 behavior and planning artifacts.
2026-08-17 16:59:35 +02:00
Julius Brussee 77257e82c1 README: landing-page rewrite around learn and the proxy
Proxy-first two-choice install, caveman learn section with a report
screenshot, skills-as-images promoted, agent SDK section moved out
with its repo, deep-dive detail collapsed or linked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bn1A1mU7TX9dsDb5mbSBE3
2026-08-16 21:21:25 +02:00
Julius Brussee ee3199bca8 docs: add technical manual, cross-link existing docs
Twenty-chapter manual under docs/technical/ with a docs/README.md index;
existing docs and package READMEs now link into it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bn1A1mU7TX9dsDb5mbSBE3
2026-08-16 21:21:25 +02:00
Julius Brussee 82864c8f4c feat: ship Caveman 2.0.0 — engine, proxy, SDKs, unified CLI
Single-commit port of the Caveman 2 tree onto the original repo history
(candidate caveman-2@88878a4 applied over main@3098342). No unrelated-history
merge; original history untouched.

Preserved v1 surfaces:
- skills/caveman/SKILL.md byte-for-byte, plus plugin mirror and caveman.skill zip
- legacy CI (Node 18/20/22 installer + Python 3.11 suites) alongside engine-ci
- cli/install.js compatibility shim forwarding to bin/install.js
- .codex/config.toml ships both hooks and codex_hooks for older Codex (#617)
- README Trendshift + Skills.sh badges and local star-history asset
- v1.10.0-pinned curl installs; benchmarks/tmp-starcharts ignore rules

Fixed for public same-repo release:
- SECURITY.md vulnerability reporting points at this repository
- release-binaries.yml publishes to this repo via job-scoped GITHUB_TOKEN
  (cross-repo PAT removed); binary-release environment still gates signing
- packages/cli/PUBLISHING.md rewritten for packages/ layout and same-repo flow
- profile-contract and provider-catalog lanes skip lane-scope gates on
  initial import so the launch PR can gate on their real validation steps
- ANNOUNCEMENT.md network claim corrected: compression is local; requests
  still go to the provider you configured

Caveman 2 stays opt-in: bin-v1.0.0 binaries and @caveman-ai/cli publish
separately after this lands and soaks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLvb5QniwYjmcawyssQNw9
2026-08-11 16:46:10 +02:00
Julius Brussee 7066cc8154 chore: use local star history image in README 2026-08-03 15:34:49 +02:00
Julius Brussee ed1fbb7f4c fix(install): rename bin/ to cli/, harden Windows quoting, clean uninstall
Marketplace fix (#712, #705): Claude Desktop rejects plugins containing a
top-level bin/ directory, and .claude-plugin/marketplace.json packages the
repo root, so the installer directory is now cli/. Every reference updated
(package.json bin entry + files, shims, docs, tests, caveman-init require
path). Supersedes PR #726.

Security (PR #717 verified): quoteWinArg only quoted on whitespace/quotes,
leaving cmd.exe metacharacters (& | ^ < > % parens) unescaped on the
shell:true Windows spawn path. Attacker-influenced arguments (--with-init
cwd, --with-mcp-shrink value) could chain commands. Trigger regex now
covers the metacharacter set; quoting logic split into a platform-
independent, unit-tested helper.

Also:
- uninstall removes .caveman-active.prev, .caveman-mode-log.jsonl,
  .caveman-statusline-suffix, .caveman-nudge-shown; keeps
  .caveman-history.jsonl with a printed note; dry-run now says
  'would remove' instead of lying (#635, supersedes PRs #693 #636)
- Array.isArray guard in rewriteLegacyManagedHookCommands — malformed
  hook event no longer crashes the installer mid-run (supersedes PR #646)
- gemini extensions install --consent: the security prompt hung every
  piped/non-interactive install forever (#676, part of PR #664)
- OpenClaw skill stamps the real PINNED_REF version instead of hardcoded
  1.0.0; new --no-always flag for load-on-demand installs (supersedes
  PR #720)
- shims scope NPM_CONFIG_ALLOW_GIT=all to the npx call — npm >=12
  defaults allow-git to none and EALLOWGITs github: installs (#698)
- .codex/config.toml ships hooks + codex_hooks keys so auto-activation
  works on both sides of the codex-cli rename (#617)
- caveman-help card shows the Windows config path (%APPDATA%) (#723)
- caveman-parse.js added to HOOK_FILES, opencode payload (.cjs), and the
  regenerated checksums.sha256; manifest now matches shipped hook
  contents — release must bump PINNED_REF to a tag containing these files

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ySX6TBWZuvFze4ajf7Hpf
2026-07-21 02:01:27 +02:00
Julius Brussee e2c09c9a7e docs: flatten savings claim to a flat 65% across all surfaces; bump PINNED_REF to v1.9.1
Replace the ~50-65% range and the ~50%-vs-terse figure with a single 65%
(the measured average output reduction vs verbose baseline) on every product
surface: README hero + ASCII card + benchmark blurb, plugin.json,
marketplace.json, gemini-extension.json, caveman SKILL.md + skill README,
caveman-init rule frontmatter, and the docs site (index.html telemetry widget
+ marquee still showed the old 75%). Trim HONEST-NUMBERS.md to match. Raw
benchmark/eval snapshots and the eval-harness methodology docs are untouched.

Bump PINNED_REF v1.9.0 -> v1.9.1 so the standalone hook-download fallback
fetches cavecrew-model-overrides.js from the release tag instead of 404ing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0163QczkBHKpYgxx3sBc7X3b
2026-07-03 13:07:25 +02:00
Julius Brussee dc95e915c5 Caveman Updated Skill + Readme 2026-07-03 12:29:48 +02:00
Julius Brussee 335ab56dea docs: HONEST-NUMBERS.md — when caveman saves, when caveman costs (#145, #550, #506)
Plain-truth page: measured output reduction (65% avg vs verbose,
~50% median vs terse control), the ~1-1.5k/turn input cost of the
injected rules, net-negative cases (terse Q&A per #145, per-request
billing per #506, adverse tool-side counters per #550), and how to
A/B it yourself. /caveman-stats savings labeled as estimates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011kmm2umRGb5nLxdimrwweZ
2026-07-02 15:31:53 +02:00
Julius Brussee baf10366f6 Add Sponsors section and Atlas Cloud logos
Add a Sponsors section to README promoting Atlas Cloud with a centered logo, link, and a call to sponsor the project. Include two new SVG assets (atlas-cloud.svg and atlas-cloud-dark.svg) under docs/assets for light/dark mode logo display.
2026-06-12 14:05:15 +02:00
Julius Brussee 46de578a7e fix(docs): escape user input in demo terminal (XSS)
Folds in #438 — the docs demo terminal interpolated user input via innerHTML (real reflected/DOM XSS); build nodes with textContent instead. (PR title 'CLI input handler' was a misnomer.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 21:04:58 +02:00
Julius Brussee 2422bbe59c docs: add caveman-code promo banner + dancing-rock branding
Add a prominent caveman-code callout to the README hero and a
caveman-code row to the ecosystem table. Swap the rock emoji for
the dancing-rock SVG logo across the README, the compress skill
README, and the docs-site cursor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:36:09 +02:00
Julius Brussee e843518438 Improve installer idempotency and opencode fencing
Refactor and harden the unified Node installer and related docs. Major changes:

- bin/install.js: validate --only ids, expand ~ for --config-dir, make Claude/install flows async (await hooks/init), add many CLI flags (--no-mcp-shrink, --with-hooks/--no-hooks, --skip-skills, --config-dir docs), preserve original backups once, avoid overwriting plugin/command files unless --force, and add opencode AGENTS.md fenced begin/end markers so installs/uninstalls can append/strip cleanly. Also add opencode idempotency probes for claude/gemini uninstall paths and better handling of opencode plugin payload.
- bin/lib/settings.js: safer removeCavemanHooks that validates shapes before mutating hooks.
- runInit/installHooks/downloadTo calls made async and awaited; runInit returns promise now.
- Docs and README/INSTALL/CONTRIBUTING/CLAUDE.md/src/hooks/README.md: update user-facing text to match new flags/behaviour, standardize use of $CLAUDE_CONFIG_DIR, clarify --with-init semantics, and note opencode/openclaw handling. Change command name usages from `/caveman:compress` to `/caveman-compress`.
- opencode: write fenced caveman block to AGENTS.md and handle legacy unfenced blocks; tests updated to expect fence markers.

These changes improve idempotency, safer upgrades/uninstalls, clearer UX around per-repo vs per-user init, and make the opencode rule block removable without destroying user content.
2026-05-10 15:50:33 +02:00
Julius Brussee ec7ce3614b Better install docs+scripts 2026-05-01 02:14:49 +02:00
Julius Brussee ae7a3e7c33 feat: add GitHub Pages landing site 2026-04-06 01:57:03 +02:00