PageSourceSearch

https://betterctx.com/assets/ShellHook-Bi691twj.js

js betterctx.com collected 2026-10-02 01:24:38 UTC 10,643 bytes, 74 lines download raw bytes

1import{u as d,j as e,G as a,c as l,H as o,P as r,I as i,D as c,C as t,a as p}from"./index-w5Cc7F-Q.js";import{u as m}from"./seo-CUHZUJgV.js";const h=[["VCS","git, gh, jj","80–95%","Diff summaries, log abbreviation, status compaction"],["Build","cargo, go, make, typescript, gradle, bazel, zig, flutter, swift, vite, nx, buf, rustfmt, django, dotnet, turbo","65–90%","Error extraction, warning deduplication, progress stripping"],["Test","jest, playwright, pytest, vitest, ruby, rspec","70–90%","Failure-first output, passing test collapse, stack trace trimming"],["Lint","clippy, eslint, ruff, mypy, golangci, biome, prettier, stylelint, hadolint, trivy, semgrep, grype, cosign, syft, swiftlint, rubocop, pylint, flake8","55–85%","Severity grouping, duplicate warning collapse, line-number anchoring"],["Package","npm, pnpm, yarn, bun, pip, poetry, uv, deno, gem, composer, mix","60–80%","Install log compression, version table compaction, audit summary"],["Infra","kubectl, docker, helm, terraform, aws, az, gcloud, ansible, pulumi, argocd, vercel, fly, supabase, wrangler, skaffold, linkerd","60–85%","Resource table compaction, event stream filtering, apply-plan diffing"],["Database","mysql, psql, prisma, redis, mongosh","55–75%","Query result pagination, schema diff compaction, migration log trimming"],["AI / Data","mlflow, ollama, dbt, spark, alembic, flyway","50–70%","Training log sampling, metric table filtering, lineage compaction"],["Security","trivy, grype, syft, cosign, snyk","50–75%","CVE deduplication, severity grouping, suppressed-item collapse"],["System","curl, wget, env, jq, sysinfo, systemd, mise","50–75%","Header stripping, JSON key filtering, service table compaction"]],u=[["BCTX_BYPASS=1 <cmd>","Skip compression for a single command in the current shell"],[".bctx-bypass (file)","Place in project root — disables bctx for that entire directory"],["bctx read --mode full -- <cmd>","Run a command through bctx but apply the passthrough (no-op) lens"],["BCTX_MODE=full","Shell-wide default — routes all commands through bctx but skips compression"]],b=()=>{const{dark:s}=d([{id:"how-it-works",label:"How it works"},{id:"ecosystem",label:"Full ecosystem"},{id:"examples",label:"Compression examples"},{id:"recipes",label:"Custom recipes"},{id:"bypass",label:"Bypass methods"}]);return m({title:"Shell hook — betterCTX",description:"Transparent token compression at the shell layer. Drop-in for fish, zsh, and bash. Compresses agent context before it hits the model.",path:"/shell-hook"}),e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.3em] font-semibold mb-3",style:{color:"#ff6f00"},children:"Core Concepts · Shell compression"}),e.jsxs("h1",{className:"text-4xl lg:text-5xl font-semibold tracking-[-0.025em] leading-[1.05] mb-4",children:["Compresses every command."," ",e.jsx(a,{children:"Before any model sees it."})]}),e.jsx("p",{className:l("text-[16px] leading-[1.65] mb-8 max-w-2xl",s?"text-white/60":"text-black/60"),children:"The shell hook intercepts CLI output transparently. git diffs, npm installs, cargo builds, docker logs — all compressed to their essential information before your agent reads them. No aliases to memorise, no flags to remember."}),e.jsxs("div",{className:"flex gap-8 mb-12 font-mono text-[13px]",children:[e.jsxs("span",{children:[e.jsx("span",{className:"text-2xl font-semibold tracking-tight",children:e.jsx(a,{children:"10"})})," categories"]}),e.jsxs("span",{children:[e.jsx("span",{className:"text-2xl font-semibold tracking-tight",children:e.jsx(a,{children:"110+"})})," patterns"]}),e.jsxs("span",{children:[e.jsx("span",{className:"text-2xl font-semibold tracking-tight",children:e.jsx(a,{children:"60–90%"})})," reduction"]})]}),e.jsx(o,{id:"how-it-works",dark:s,children:"How it works"}),e.jsxs(r,{dark:s,children:["When you install the shell hook via"," ",e.jsx(i,{dark:s,children:"bctx init --agent <shell> --shell-hook"}),", bctx writes a shell function that wraps interceptable commands. When you run"," ",e.jsx(i,{dark:s,children:"git status"}),", the hook routes it through"," ",e.jsx(i,{dark:s,children:"bctx git status"})," automatically. The FilterMesh matches the command pattern to a domain-specific compressor, applies the Lens pipeline, and returns the compressed output. Your terminal sees the compressed version; your agent sees the compressed version."]}),e.jsx("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-3 mb-8",children:[{n:"1",t:"Command runs",b:"Agent or user runs git status"},{n:"2",t:"Hook intercepts",b:"bctx receives the raw output"},{n:"3",t:"FilterMesh matches",b:"Domain compressor identified"},{n:"4",t:"Agent sees compressed",b:"60–95% fewer tokens"}].map(n=>e.jsxs("div",{className:l("p-4 rounded-xl border text-center",s?"bg-white/[0.02] border-white/[0.06]":"bg-white border-black/[0.06]"),children:[e.jsxs("div",{className:"text-[10px] uppercase tracking-[0.3em] font-bold mb-1",style:{color:"#ff6f00"},children:["Step ",n.n]}),e.jsx("div",{className:"text-[13px] font-semibold mb-1",children:n.t}),e.jsx("p",{className:l("text-[11.5px] leading-snug",s?"text-white/55":"text-black/55"),children:n.b})]},n.n))}),e.jsx(o,{id:"ecosystem",dark:s,children:"Full ecosystem — 110+ patterns across 10 categories"}),e.jsx(r,{dark:s,children:"Each tool has a domain-specific compressor that understands its output structure — not generic line-trimming. The FilterMesh routes by command prefix to the right compressor automatically."}),e.jsx(c,{dark:s,headers:["Category","Tools","Savings","Compression approach"],rows:h}),e.jsx(o,{id:"examples",dark:s,children:"Compression examples"}),e.jsx(r,{dark:s,children:"Three real before/after comparisons showing what the compressor str
1ips vs. keeps."}),e.jsxs("div",{className:"space-y-4 mb-6",children:[e.jsxs("div",{className:"grid md:grid-cols-2 gap-3",children:[e.jsx(t,{dark:s,filename:"git status — raw · ~580 tokens",code:`On branch feature/auth
2Your branch is ahead of 'origin/feature/auth'
3by 3 commits.
4  (use "git push" to publish your local commits)
5
6Changes to be committed:
7  (use "git restore --staged <file>..." to unstage)
8        new file:   src/session.ts
9        modified:   src/login.ts
10        modified:   src/api.ts
11
12Changes not staged for commit:
13        modified:   src/session.ts
14
15Untracked files:
16        src/session.test.ts`}),e.jsx(t,{dark:s,filename:"git status — compressed · ~75 tokens",code:`feature/auth ↑3
17staged:    +session.ts  ~login.ts  ~api.ts
18unstaged:  ~session.ts
19untracked: session.test.ts
20
21[534 tok saved · 87%]`})]}),e.jsxs("div",{className:"grid md:grid-cols-2 gap-3",children:[e.jsx(t,{dark:s,filename:"cargo test — raw · ~3,200 tokens",code:`   Compiling bctx v0.1.7 (/home/user/project)
22    Finished test [unoptimized + debuginfo] target(s) in 4.83s
23     Running unittests src/lib.rs (target/debug/deps/bctx-abc123)
24
25running 47 tests
26test vault::tier::test_immediate_trace_eviction ... ok
27test vault::tier::test_resonant_promotion ... ok
28test vault::tier::test_crystallize_after_3_confirmations ... ok
29[... 42 more ok lines ...]
30test auth::jwt::test_expired_token ... FAILED
31
32failures:
33
34---- auth::jwt::test_expired_token stdout ----
35thread 'auth::jwt::test_expired_token' panicked at 'assertion failed: ...
36  left: Err(TokenExpired { exp: 1715000000, now: 1716000000 })
37 right: Ok(Claims { sub: "user123", exp: 1715000000 })
38note: run with RUST_BACKTRACE=1 for a backtrace.
39
40test result: FAILED. 46 passed; 1 failed; 0 ignored`}),e.jsx(t,{dark:s,filename:"cargo test — compressed · ~280 tokens",code:`cargo test · 47 tests
41✗ auth::jwt::test_expired_token
42  panicked: assertion failed
43  left:  Err(TokenExpired { exp: 1715000000, now: 1716000000 })
44  right: Ok(Claims { sub: "user123" })
45
46result: 46 passed, 1 FAILED
47
48[2,920 tok saved · 91%]`})]}),e.jsxs("div",{className:"grid md:grid-cols-2 gap-3",children:[e.jsx(t,{dark:s,filename:"kubectl get pods — raw · ~940 tokens",code:`NAME                                          READY   STATUS    RESTARTS   AGE
49api-deployment-7d4f8b9c6-xk2pq               1/1     Running   0          2d
50api-deployment-7d4f8b9c6-mn8rt               1/1     Running   0          2d
51api-deployment-7d4f8b9c6-pq7ws               1/1     Running   0          2d
52worker-deployment-6c5d7b8a9-ab1cd            0/1     Pending   0          14m
53worker-deployment-6c5d7b8a9-ef2gh            1/1     Running   0          2d
54redis-statefulset-0                          1/1     Running   0          5d
55postgres-statefulset-0                       1/1     Running   0          5d
56postgres-statefulset-1                       1/1     Running   0          5d`}),e.jsx(t,{dark:s,filename:"kubectl get pods — compressed · ~140 tokens",code:`pods: 8 total  7 Running  1 Pending
57
58⚠ worker-deployment-6c5d7b8a9-ab1cd  Pending  14m
59
60api × 3 · redis × 1 · postgres × 2 · worker × 2
61
62[800 tok saved · 85%]`})]})]}),e.jsx(o,{id:"recipes",dark:s,children:"Custom recipes"}),e.jsxs(r,{dark:s,children:["Domain compressors are written in the Recipe DSL — TOML files that define pattern matching rules for specific commands. You can add project-level recipes in"," ",e.jsx(i,{dark:s,children:".bctx/recipes/"})," or global recipes in"," ",e.jsx(i,{dark:s,children:"~/.config/bctx/recipes/"}),". Recipes stack on top of the built-in compressors."]}),e.jsx(t,{dark:s,lang:"toml",filename:".bctx/recipes/my-build.toml",code:`# Suppress verbose webpack output from a custom build script
63[[rule]]
64match = ["./scripts/build.sh"]
65lens = "aggressive"
66strip_prefix = ["webpack", "HMR", "asset"]
67keep_pattern = ["ERROR", "WARNING", "Built in"]`}),e.jsxs(p,{type:"tip",title:"FilterMesh auto-selects for 110+ commands",dark:s,children:["You only need custom recipes for commands that bctx doesn't already intercept. Run ",e.jsx(i,{dark:s,children:"bctx modes --demo signatures"})," to see what the built-in compressors produce before writing a recipe. The shell hook installs with ",e.jsx(i,{dark:s,children:"bctx init --agent <shell> --shell-hook"}),"."]}),e.jsx(o,{id:"bypass",dark:s,children:"Bypass methods"}),e.jsx(r,{dark:s,children:"Compression is opt-out per command — never silent and never sticky. Use any of the methods below when you need unmodified output."}),e.jsx(c,{dark:s,headers:["Method","Scope"],rows:u}),e.jsx(t,{dark:s,lang:"bash",code:`# Skip compression for one command
68BCTX_BYPASS=1 git log --oneline -50
69
70# No compression for this entire project
71touch .bctx-bypass
72
73# Full passthrough lens — bctx runs but applies no transforms
74bctx read --mode full -- cat src/generated.rs`})]})};export{b as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.