0ef5fcb1c5
Security / Dependency audit (pip-audit) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
Security / CodeQL (python) (push) Has been cancelled
Security / Secret scan (gitleaks) (push) Has been cancelled
rust / test (ubuntu) (push) Has been cancelled
rust / simulator e2e (macos-latest) (push) Has been cancelled
rust / simulator e2e (ubuntu-latest) (push) Has been cancelled
rust / simulator e2e (windows-latest) (push) Has been cancelled
rust / wheels (aarch64-apple-darwin) (push) Has been cancelled
rust / wheels (x86_64-unknown-linux-gnu) (push) Has been cancelled
rust / wheels (x86_64-apple-darwin) (push) Has been cancelled
rust / audit (push) Has been cancelled
rust / parity (nightly, allowed to fail during Phase 0) (push) Has been cancelled
CI / commitlint (push) Has been skipped
Dev Containers / validate (.devcontainer/devcontainer.json, default) (push) Failing after 0s
Dev Containers / validate (.devcontainer/memory-stack/devcontainer.json, memory-stack) (push) Failing after 0s
Dev Containers / validate-worktree (push) Failing after 0s
CI / changes (push) Failing after 4s
Deploy Documentation / validate (push) Has been skipped
Deploy Documentation / deploy (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, claude) (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, codex) (push) Failing after 1s
Install Native E2E / install-native (ubuntu-latest) (push) Failing after 1s
OpenCode Plugin / typecheck + build + test (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, copilot) (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
Wrap E2E / docker-wrap-e2e (push) Failing after 1s
Wrap Native E2E / wrap-native (ubuntu-latest) (push) Failing after 1s
Init E2E / docker-init-e2e (push) Failing after 4s
Merge Conflicts / merge-conflicts (push) Failing after 4s
CI / lint (push) Has been cancelled
CI / build-wheel (push) Has been cancelled
CI / build-wheel-windows (push) Has been cancelled
CI / prefetch-model (push) Has been cancelled
CI / test-dashboard-ui (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test-extras (push) Has been cancelled
CI / test-agno (push) Has been cancelled
CI / build (push) Has been cancelled
CI / workflow-validation (push) Has been cancelled
CI / docker-native-e2e (push) Has been cancelled
CI / windows-native-wrapper (push) Has been cancelled
CI / macos-native-wrapper (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / promote-latest (push) Has been cancelled
Init Native E2E / init-native (macos-latest, claude) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, codex) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, copilot) (push) Has been cancelled
Install Native E2E / install-native (macos-latest) (push) Has been cancelled
Wrap Native E2E / wrap-native (macos-latest) (push) Has been cancelled
123 lines
4.8 KiB
Markdown
123 lines
4.8 KiB
Markdown
# RTK architecture — why wrap-CLI only
|
|
|
|
**Status:** decided. Locked at Phase G PR-G3 (2026-05).
|
|
**Owner:** Headroom realignment.
|
|
|
|
## TL;DR
|
|
|
|
**RTK is a wrap-CLI hook, not a proxy-side compressor.** The Headroom
|
|
proxy does NOT invoke RTK on tool-result content. Future contributors
|
|
who consider moving RTK into the proxy hot path: read this doc first.
|
|
|
|
## Background
|
|
|
|
RTK (Realtime Token Kompress) rewrites shell **commands** at exec
|
|
time so that a `git diff` or `grep` invocation emits a more
|
|
compressed output before the agent ever ingests it. RTK runs in the
|
|
wrap-CLI tail — `headroom wrap claude`, `headroom wrap codex`, etc.
|
|
— where it installs a `~/.rtk/bin/rtk` shim ahead of the agent CLI
|
|
and intercepts shelled-out subprocesses.
|
|
|
|
It surfaces value in two places:
|
|
1. **Tokens saved per invocation** — measured by `rtk gain --format json`.
|
|
2. **Tokens saved per session** — aggregated at wrap-session end.
|
|
|
|
Both signals feed `wrap_rtk_invocations_total` and
|
|
`wrap_rtk_tokens_saved_per_session` (registered by the Rust proxy's
|
|
observability surface so a single `/metrics` scrape exposes the full
|
|
picture).
|
|
|
|
## Proxy-side RTK was considered and rejected
|
|
|
|
At Phase G scoping, three reviewers floated the idea of invoking
|
|
RTK on the **proxy** side: when a `tool_result` block flows
|
|
upstream, dispatch it through RTK to shrink the content before it
|
|
hits the model.
|
|
|
|
**Decision: rejected.** Three load-bearing reasons.
|
|
|
|
### 1. Cache hot zone risk
|
|
|
|
The proxy's Phase B cache-safety contract pins `tool_result`
|
|
content as part of the cache hot zone. Compression there bursts
|
|
the prompt cache because the rewritten bytes diverge from the
|
|
canonical wire bytes the upstream cached. Phase B PR-B2 → PR-B7
|
|
spent ~3000 LOC carving the live-zone-only surface specifically
|
|
to prevent this class of cache-invalidation. Inserting RTK
|
|
proxy-side would re-introduce it.
|
|
|
|
### 2. Parallel implementation with `log_compressor.rs`
|
|
|
|
The Rust proxy already has a `crates/headroom-core/src/transforms/log_compressor.rs`
|
|
that compresses **tool output text** in the live zone. It uses the
|
|
same heuristics RTK uses (whitespace de-dup, line de-dup,
|
|
file-listing collapse) but invoked at the proxy's per-block
|
|
dispatcher rather than at the shell exec boundary. Adding RTK
|
|
proxy-side would mean two implementations of the same compression
|
|
in the same hot path; "no silent fallbacks, no parallel impls" is
|
|
explicit project policy.
|
|
|
|
### 3. Command-rewrite vs output-rewrite — different value propositions
|
|
|
|
RTK rewrites **commands** before they execute. The
|
|
`git log --oneline` you typed becomes `git log --oneline -n 50`
|
|
because RTK has learned that the first 50 commits are usually
|
|
enough context. That's a fundamentally different mechanism from
|
|
compressing the **output** of an unmodified command. A proxy-side
|
|
invocation would skip the command-rewrite half — the half that
|
|
generates the largest savings on heavy shell workloads — and only
|
|
catch the output side, which is already covered by
|
|
`log_compressor` and `code_compressor`.
|
|
|
|
## What the proxy does provide
|
|
|
|
Per Phase G PR-G3, the proxy exposes RTK-derived metrics via its
|
|
registry:
|
|
|
|
- `wrap_rtk_invocations_total{tool}` — driven by the wrap-CLI
|
|
polling `rtk gain --format json` and incrementing the registered
|
|
counter by the delta since last poll.
|
|
- `wrap_rtk_tokens_saved_per_session` — emitted at wrap-session
|
|
close.
|
|
|
|
This keeps the operator dashboard single-pane-of-glass without
|
|
re-implementing RTK inside the proxy.
|
|
|
|
## What the wrap CLI does
|
|
|
|
Every `headroom wrap <agent>` subcommand:
|
|
|
|
1. Ensures the RTK binary is installed via `_ensure_rtk_binary()`.
|
|
2. Injects the `<!-- headroom:rtk-instructions -->` block into the
|
|
agent's instruction file (e.g. `AGENTS.md`, `.cursorrules`).
|
|
3. Spawns the proxy and the agent CLI side-by-side.
|
|
4. Polls `rtk gain --format json` on a 5-second memoization window
|
|
and feeds the delta into the proxy's metric registry.
|
|
|
|
See `headroom/cli/wrap/` for the per-agent shims.
|
|
|
|
## Re-litigation policy
|
|
|
|
A change to this architecture should:
|
|
|
|
1. Quote the live-zone-only contract from
|
|
`REALIGNMENT/04-phase-B-live-zone.md` and explain why the
|
|
cache-burst risk is acceptable.
|
|
2. Show measurements (not estimates) that proxy-side RTK adds value
|
|
beyond `log_compressor.rs` on real production traffic.
|
|
3. Have an exit ramp: a CLI flag to disable proxy-side RTK without
|
|
reverting the wrap-CLI integration.
|
|
|
|
Without all three, treat the proposal as a regression and link this
|
|
doc.
|
|
|
|
## References
|
|
|
|
- `REALIGNMENT/09-phase-G-rtk-observability.md` — Phase G plan.
|
|
- `REALIGNMENT/04-phase-B-live-zone.md` — cache hot-zone contract.
|
|
- `headroom/cli/wrap/` — wrap-CLI implementation.
|
|
- `crates/headroom-core/src/transforms/log_compressor.rs` — the
|
|
proxy-side log compressor RTK would parallel.
|
|
- 2026-05-01 user direction message archived in
|
|
`project_compression_realignment_2026_05` memory note.
|