Skip to content
Development
Skill

/furl

How the Furl context-compression plugin works in Claude Code and Codex — the furl_compress / furl_retrieve / furl_stats / furl_purge / furl_search / furl_list MCP tools, the <<ccr:HASH>> retrieval flow, and Claude Code's optional automatic hooks. Use when the user asks what Furl

From plugin
furl-ctx
51 skill1 MCP

Claude Code

$ npx -y skills add omar-y-abdi/furl-ctx --skill furl --agent claude-code

SKILL.md

furl.SKILL.md
name: furl
description: How the Furl context-compression plugin works in Claude Code and Codex — the furl_compress / furl_retrieve / furl_stats / furl_purge / furl_search / furl_list MCP tools, the <<ccr:HASH>> retrieval flow, and Claude Code's optional automatic hooks. Use when the user asks what Furl is doing, how to compress or retrieve content, why Claude Code output looks compressed, or how to tune or disable Furl.
version: 1.4.0

Furl — context compression for Claude Code and Codex

Furl reduces the tokens large tool outputs cost by compressing them, while keeping every dropped byte **retrievable on demand**. It ships these capabilities:

1. An **MCP server** (`furl`) exposing six tools in Claude Code and Codex. 2. A retrieval-aware **skill** in both hosts. 3. **Automatic hooks in Claude Code only.** Codex uses explicit `furl_compress` calls; its separate package root intentionally excludes Claude's incompatible hooks.

**Retrieval is pull-based, not push-based.** The compressed text you read does not contain the dropped rows. To inspect a specific dropped item, call `furl_retrieve` for it by pattern, field, or line range. Retrieval is byte-exact for raw text. A JSON array narrowed by `select`/`fields` comes back re-serialized — semantically complete but pretty-printed, so **not** byte-identical to the source; when byte fidelity matters (hashing, diffing, signature checks) pass `raw: true` on a row-select and each matched row returns byte-identical to its source bytes, the rows rejoined with fresh array punctuation, so each row is exact while the whole blob is not one contiguous slice.

**What actually decides byte-exactness is the offload route, not text-vs-JSON.** Content the router crushes structurally (columnar and tabular arrays) is stored as canonical `json.dumps`, so a full `furl_retrieve` returns canonical bytes — byte-identical only when your input was already canonical. Content offloaded whole-blob (plain text, or JSON too irregular to crush) is stored verbatim and returns byte-exact. One consequence on the crush path: the hash keys the *canonical* form, so two byte-different inputs that canonicalize the same collapse to one stored entry — on the crush path the hash is a semantic identifier, on the whole-blob path a byte one.

Nothing is lost, but a one-off anomaly buried in otherwise-repetitive data will not appear in the compressed view unless you query for it. Trust a compressed summary for the shape of the data, not for surfacing an anomaly you were not already looking for.

Current harness status

**Codex:** call `furl_compress` explicitly. Prefer its `file_path` input for a large artifact so only compressed content enters context. The Codex plugin installs the MCP server and this skill, not automatic hooks.

**Claude Code:** automatic, hands-off compression works on Claude Code 2.1.163 and newer. The PostToolUse hook emits `updatedToolOutput` mirrored to the originating tool's output shape; Claude Code 2.1.163 and newer validate that replacement against the tool's schema, and the mirrored shape passes, so the compressed output reaches the model. Both external audits confirmed this live on 2.1.212. Shape-mirroring was built for [anthropics/claude-code#68951](https://github.com/anthropics/claude-code/issues/68951), where an earlier bare-string replacement was dropped on a schema mismatch. `WebSearch` still passes through uncompressed, because its whole-object result has no single text field to mirror onto. Unaffected on every version: the manual MCP tools furl_compress, furl_retrieve, and the rest, and durable `<<ccr:HASH>>` storage and retrieval. Below 2.1.163 the SessionStart status line and the first-run note say so directly instead of claiming PostToolUse compression is active, naming the detected version; the PreToolUse pipe (below) is unaffected either way. LIBRARY.md carries the canonical harness status.

**Counters:** `furl_stats` shows `store.hook_activity.hook_invocations_seen` and `hook_compressions_applied`, cross-process and cumulative. A rising `hook_compressions_applied` confirms the hook is compressing and, on 2.1.163 and newer, delivering the shorter output the model reads; below the floor it stops incrementing instead, bucketed under `hook_noop:below-version-floor`. `store.post_tool_use_compression` reports the detected host version and whether it can receive a replacement at all, independent of the counters.

**Claude Code real savings now (enabled by default):** a **PreToolUse** pipe compresses a `Bash` command's stdout at the source (so the tool result *is* the compressed form, original retrievable via `furl_retrieve`) — it doesn't use `updatedToolOutput`, so it works today. Disable it with `FURL_PRETOOL_PIPE=0` (`false`/`off`/`no`/`disabled` also work, case-insensitively); unset, empty, or any other value leaves it on. Trade-offs: Bash-only; the rewrite is transcript-visible (a `# furl-pipe` comment); exit code preserved exactly; stderr is not captured and flows live, but stderr/stdout interleaving is not preserved (all stderr precedes the compressed stdout; `2>&1` merges); fail-open (worst case the command runs unwrapped, uncompressed); adds ~0.3–0.5 s per rewritten call (two `uv` resolves; a fresh environment pays a one-time resolve/build on the first call). It rewrites Bash **only when there are zero readable Bash permission rules**: if any `Bash` deny/ask/allow rule exists in any scope Claude Code uses — enterprise managed (incl. the `CLAUDE_CODE_MANAGED_SETTINGS_PATH` override), project (both `CLAUDE_PROJECT_DIR` and the working dir), and user (both `~/.claude` and `CLAUDE_CONFIG_DIR`) settings — it leaves all Bash untouched so your rules apply exactly as native, a total boundary no command shape can bypass. Unreadable settings (or a set-but- unresolvable config-path override) also force passthrough. Residual blindness: CLI `--permission-mode`/`--disallowedTools` flags, SDK `managedSettings`, and API-fetched remote org policy

Read more
Stats
5
Stars
0
Forks
Active
Maintenance
Python
Language
Apache-2.0
License
Last commit
Created

Repo: omar-y-abdi/furl-ctx

@omar-y-abdi
Ships withfurl-ctx

Reversible context compression for AI agents. furl-ctx shrinks large tool outputs, logs, web fetches, and RAG chunks before they fill your agent's context window, and keeps every original byte retrievable on demand.

Stars on GitHub

Momentum

stars in total
5
Star history of omar-y-abdi/furl-ctx on GitHub, a chart by star-history.com

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about furl.

Which coding agents can use furl?
furl installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.