Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
544 changes: 59 additions & 485 deletions README.md

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ Manages the 7 complementary token-saving tools:

> **graphify** is a CLI + skill, not a Claude Code plugin. Its PyPI package is `graphifyy` (the bare `graphify` name on PyPI is unaffiliated — see upstream's README) while the command stays `graphify`. `status` reports it OK only when BOTH halves are present: the CLI on `PATH` **and** a registered skill (`~/.claude/skills/graphify/SKILL.md`); a CLI with no skill is `installed-disabled`, because the assistant then never reaches for the graph. `check-updates` reads its latest version live from the PyPI JSON API (no pinned constant — graphify ships weekly, so a hardcoded number would report phantom up-to-date), and `upgrade` routes through whichever installer owns the package (`uv tool` → `pipx` → `pip`) then re-runs `graphify install` so the skill files match the new version.

> **OpenWiki is the recommended shared project-memory layer**, not an eighth
> live compression lane. `install.sh --with-openwiki` installs the pinned CLI,
> and `--all` includes it. Never run `openwiki --init` implicitly: initialization
> writes generated documentation and invokes an LLM. Recommend it strongly for
> long-lived team repositories, where one reviewed wiki is reused by every human
> and agent. Use `graphify update .` after code changes and `openwiki --update`
> after merges or on a schedule. A clean OpenWiki update skips model work.

## Multi-provider support

tokenwar now tracks token usage across AI coding agents, each from its own
Expand Down Expand Up @@ -128,7 +136,7 @@ On `Yes`, run for each tool:
- `graphify` installed-disabled (CLI present, skill missing) → `graphify install`. Do NOT reinstall the package; the CLI is already there, only the skill registration is absent.
- GitHub Copilot CLI present but tools not wired to it → `bash ~/.claude/skills/tokenwar/scripts/copilot.sh wire --yes` (see the `copilot` subcommand below).

**One-shot alternative**: `install.sh --all` (or `curl … | bash -s -- --all`) installs the whole stack at install time — the 4 plugins (marketplace-add + install + enable, with the anti-clobber re-enable), the RTK binary (via rtk's official prebuilt installer — no toolchain), pxpipe (`pxpipe-proxy@0.10.0`), and graphify (`graphifyy` + `graphify install`), then wires RTK's hook with `rtk init -g` (and, when opencode is present, RTK's opencode plugin with `rtk init -g --opencode`). Use `--with-plugins`, `--with-rtk`, `--with-pxpipe`, `--with-graphify`, or `--with-copilot` for just one part. So a fresh machine needs no separate `activate`.
**One-shot alternative**: `install.sh --all` (or `curl … | bash -s -- --all`) installs the whole stack at install time — the 4 plugins (marketplace-add + install + enable, with the anti-clobber re-enable), the RTK binary (via rtk's official prebuilt installer — no toolchain), pxpipe (`pxpipe-proxy@0.10.0`), graphify (`graphifyy` + `graphify install`), and the pinned OpenWiki CLI, then wires RTK's hook with `rtk init -g` (and, when opencode is present, RTK's opencode plugin with `rtk init -g --opencode`). Use `--with-plugins`, `--with-rtk`, `--with-pxpipe`, `--with-graphify`, `--with-openwiki`, or `--with-copilot` for just one part. OpenWiki repository initialization remains explicit. So a fresh machine needs no separate `activate`.

**Gotcha discovered 2026-05-18**: the *first* call to `claude plugin enable` on any plugin creates `enabledPlugins` in `~/.claude/settings.json` and **clobbers** plugins that were enabled implicitly at the marketplace level. Mitigation: after EVERY enable/install, snapshot the full `claude plugin list --json` and re-enable any plugin that flipped from `enabled:true` to `enabled:false`. The `activate` flow must do this snapshot-and-restore.

Expand Down
80 changes: 80 additions & 0 deletions docs/copilot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# GitHub Copilot CLI integration

## The stack inside GitHub Copilot CLI

Being a tracked *provider* only gets you the numbers. The **tools** are published
for Claude Code and do not reach Copilot for free — each one has to be pointed at
Copilot's own extension points, of which there are exactly three: hooks
(`~/.copilot/hooks/*.json`), skills (`~/.copilot/skills/<name>/SKILL.md`, the
portable Agent-Skills format), and MCP (`~/.copilot/mcp-config.json`).

`tokenwar copilot` reports that mapping; `tokenwar copilot wire` applies it.

| Tool | Reaches Copilot via | Wiring |
| ---- | ------------------- | ------ |
| **rtk** | hook | `rtk init -g --copilot` — a `PreToolUse` hook plus user-level instructions |
| **graphify** | skill | `graphify copilot install` — its own native command |
| **caveman** | skill | `copilot skill add` on the plugin's `SKILL.md` |
| **ponytail** | skill | `copilot skill add` on the plugin's `SKILL.md` |
| **claude-mem** | MCP | its own `.mcp.json` definition, re-registered with `copilot mcp add` |
| context-mode | — | not wired: its plugin manifest pins an absolute, version-specific interpreter path, so the registration would break on the next upgrade |
| pxpipe | — | not applicable: it is a proxy on the Anthropic-compatible API path, and Copilot talks to GitHub's endpoint |

```text
# /tokenwar copilot

· tool via state note
─────────────────────────────────────────────────────────────────
✓ rtk hook wired ~/.copilot/hooks/rtk-rewrite.json
✓ graphify skill wired ~/.copilot/skills/graphify
✓ caveman skill wired ~/.copilot/skills/caveman
✓ ponytail skill wired ~/.copilot/skills/ponytail
✓ claude-mem MCP wired ~/.copilot/mcp-config.json → claude-mem
```

Two details that are easy to get wrong:

- **claude-mem is registered from its own `.mcp.json`, not from a hardcoded
path.** That file wraps a locator which resolves the current plugin version at
runtime, so the Copilot registration survives `claude plugin update`. Pointing
Copilot straight at `.../claude-mem/13.6.1/scripts/mcp-server.cjs` works right
up until the next upgrade.
- **claude-mem's first search needs a longer timeout than either default
allows.** Its MCP server talks to a local worker over HTTP and aborts at
`CLAUDE_MEM_API_TIMEOUT_MS` (30s by default); the first search after a cold
worker path builds an index over the whole memory DB — measured at **2m02s**
here. With the defaults the very first call in a Copilot session *always*
fails, which reads as "claude-mem is broken under Copilot" when it is not. The
wiring therefore raises both that variable and Copilot's own per-tool timeout.

`install.sh --with-copilot` (included in `--all`) runs the same wiring at install
time — it delegates to `scripts/copilot.sh`, so there is one implementation, not
two that drift.

## How to activate tokenwar per client

Run the installer **once** — it wires every client it can find. There is no
per-client install step; the difference is only *how the stack shows up* in each.

```bash
curl -fsSL https://raw.githubusercontent.com/oratelecom/tokenwar/main/install.sh | bash -s -- --all
```

| Client | What `install.sh` does for it | How you confirm it's active |
| ------------- | --------------------------------------------------------------------- | --------------------------- |
| **Claude Code** | Installs the 4 plugins + RTK hook + pxpipe, patches `statusLine` in `~/.claude/settings.json` | Restart Claude Code → persistent bottom bar `[ctx][mem][rtk][caveman][ponytail]` |
| **Codex** | Wraps `codex` with a shell function that prints the tokenwar banner on launch | Open a new shell, run `codex` → banner appears; `tokenwar status` works |
| **Gemini CLI** | Wraps `gemini` the same way | New shell, run `gemini` → banner |
| **Kimi Code CLI** | Wraps `kimi` the same way | New shell, run `kimi` → banner |
| **opencode** | Wraps `opencode` the same way; reads its real token telemetry from `~/.local/share/opencode/opencode.db` | New shell, run `opencode` → banner; `tokenwar gain` shows opencode session tokens |
| **GitHub Copilot CLI** | Wraps `copilot` the same way; reads its real token + AI-credit telemetry from `~/.copilot/session-store.db`; with `--with-copilot`, also points the tools at Copilot's own hook / skills / MCP | New shell, run `copilot` → banner; `tokenwar copilot` shows every tool `wired` |

After install, **reload your shell** (`source ~/.bashrc` or open a new terminal)
so the `codex` / `gemini` / `kimi` / `opencode` / `copilot` / `tokenwar` functions
take effect.
That's the whole activation — every subsequent launch of any wrapped CLI is
tokenwar-aware with zero extra effort.

Only want one client? The wrappers are wired for all of them regardless, but you
never pay for a client you don't use: an absent CLI is simply never invoked, and
`tokenwar status` reports it as *not installed* without failing.
107 changes: 107 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Installation

## Quick start

Two ways in — pick your interface. **A human runs one curl. An agent gets a
prompt.** Both end at the same installed-activated-verified state.

### 🤖 Agent install (the future default)

Paste this prompt into any coding agent (Claude Code, Codex, Gemini, Cursor,
opencode…). The agent reads the installer, runs it, then proves it works — no
copy-pasting flags:

```text
Install, activate, and verify that https://github.com/oratelecom/tokenwar works.

Steps:
1. Install: run `curl -fsSL https://raw.githubusercontent.com/oratelecom/tokenwar/main/install.sh | bash -s -- --all`
(fetch and read the script first if you want to inspect it — it only wires
the statusline, shell functions, the 4 Claude plugins, RTK, pxpipe,
Graphify, and the pinned OpenWiki CLI).
2. Activate: reload the shell (`source ~/.bashrc`) so the tokenwar / codex /
gemini / kimi / opencode wrappers take effect. For Claude Code, restart it so
the statusLine loads.
3. Verify: run `tokenwar status` — every one of the 7 tools must report OK.
Then run `tokenwar check` (must print COMPLEMENTARY) and `tokenwar gain`
(must show real per-tool token savings, not all N/A).
4. Report back the status table and the total tokens saved. If any tool is
red, run `tokenwar upgrade` and re-check.
```

One line, if your agent likes it terse:

```text
Install, activate, and verify https://github.com/oratelecom/tokenwar — run its install.sh --all, reload the shell, then confirm `tokenwar status` shows all 7 tools OK, `tokenwar check` says COMPLEMENTARY, and `tokenwar gain` reports real savings.
```

### 👤 Human install

One command installs the whole stack: the 4 Claude Code plugins, **RTK**,
**pxpipe**, **Graphify**, the pinned **OpenWiki** CLI, statusline, shell
functions, Copilot wiring, and RTK's hook:

```bash
curl -fsSL https://raw.githubusercontent.com/oratelecom/tokenwar/main/install.sh | bash -s -- --all
```

Then activate + verify:

```bash
source ~/.bashrc # load the shell wrappers (or open a new terminal)
tokenwar status # all 7 tools should report OK
tokenwar check # must print COMPLEMENTARY
tokenwar gain # real per-tool token savings
```

Restart Claude Code to load the plugins. `--all` includes `--with-plugins`,
`--with-rtk`, `--with-pxpipe`, `--with-graphify`, `--with-openwiki`, and
`--with-copilot`; use individual flags for one part. OpenWiki requires Node.js
22 or newer. Installation does not run `openwiki --init`, because that command
writes project documentation and invokes an LLM.

Prefer no surprise mutations? Drop the flags — `… | bash` just wires the statusline + shell functions, then `/tokenwar activate` installs the plugins on confirmation:

```bash
curl -fsSL https://raw.githubusercontent.com/oratelecom/tokenwar/main/install.sh | bash
/tokenwar activate
```

The bare installer does not install any managed tool. When OpenWiki is absent,
it prints a strong recommendation for active team repositories and the explicit
`--with-openwiki` command. See [shared project memory](project-memory.md) for
initialization and CI updates.

Uninstall:

```bash
curl -fsSL https://raw.githubusercontent.com/oratelecom/tokenwar/main/uninstall.sh | bash
```

### Manual install

```bash
git clone https://github.com/oratelecom/tokenwar ~/.claude/skills/tokenwar
chmod +x ~/.claude/skills/tokenwar/scripts/*.sh

# Diagnose current state
bash ~/.claude/skills/tokenwar/scripts/status.sh

# Verify complementarity
bash ~/.claude/skills/tokenwar/scripts/check.sh

# Token savings report (per-tool + monthly $ value)
bash ~/.claude/skills/tokenwar/scripts/gain.sh
```

`gain.sh` reads each tool from its **own native telemetry** — never fabricated:
RTK (`rtk gain`), context-mode (`ctx_stats`), claude-mem
(`~/.claude-mem/chroma-sync-state.json` stored-memory counts), pxpipe
(`~/.pxpipe/events.jsonl` proxy events), and graphify (`graphify benchmark` on
`~/.graphify/global-graph.json`). caveman is a
style-only nudge with no measurable buffer, so it is always `N/A`; graphify's
benchmark is a per-query ratio rather than a cumulative counter, so its ratio is
printed in the note while its token column stays `N/A` and it never inflates the
TOTAL. It also
prints a per-month breakdown from `rtk gain --monthly`, valuing each month's
saved tokens at Claude and Codex input list prices (the API-equivalent $ saved).
95 changes: 95 additions & 0 deletions docs/operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Commands and operations

## Commands

Inside Claude Code (`/tokenwar <subcommand>`) or standalone (`bash ~/.claude/skills/tokenwar/scripts/<script>.sh`):

| Command | What it does |
| --- | --- |
| `/tokenwar status` | Health of the 7 tools — installed, enabled, version |
| `/tokenwar gain` | Per-tool token savings + per-provider telemetry/status (Codex/Gemini/Kimi/opencode) + **monthly $ value** |
| `/tokenwar scan` | Local agent-log audit: what loads into every request vs what you actually use, with cache-adjusted cost |
| `/tokenwar prune` | List skills and MCP servers that load every request but were never invoked |
| `/tokenwar bundle <mode>` | Apply a session-start tool bundle (`dev`/`devops`/`architect`/`testing`) |
| `/tokenwar copilot` | Report which tools reach GitHub Copilot CLI; `copilot wire` points the missing ones at Copilot's hook / skills / MCP |
| `/tokenwar upgrade` | Bump each tool to latest (asks confirmation) |
| `/tokenwar check` | Conflict detector — verifies the 7 tools stack additively |
| `/tokenwar test` | End-to-end ping: is each tool actually working? |
| `/tokenwar doctor` | Full pipeline: status → test → check → gain |
| `/tokenwar disable <tool>` | Turn off one plugin (`context-mode`/`claude-mem`/`caveman`/`ponytail`) without uninstalling it. `rtk`, `pxpipe`, and `graphify` are binaries, not plugins — the command prints their own on/off mechanism instead |
| `/tokenwar enable <tool>` | Turn a disabled plugin back on |

## Status in every CLI (Claude, Codex, Gemini, Kimi, opencode, Copilot)

The persistent **bottom status bar** is a Claude Code feature — it ships a
`statusLine` API and tokenwar wires it automatically. **Codex, Gemini, Kimi,
opencode, and GitHub Copilot CLI do not expose a status-bar API** (their footers
are hardcoded; their hooks inject only into the model context, not the screen).
So tokenwar surfaces the stack the best way each CLI allows, with **zero daily
effort** — `install.sh` wires it once:

| CLI | What you get |
| ----------- | --------------------------------------------------------------------- |
| Claude Code | Native persistent bottom bar (always visible) |
| Codex | Launch banner + `tokenwar status` reminder + update status hint |
| Gemini CLI | Launch banner + `tokenwar status` reminder + update status hint |
| Kimi Code CLI | Launch banner + `tokenwar status` reminder + update status hint |
| opencode | Launch banner + `tokenwar status` reminder + update status hint |
| GitHub Copilot CLI | Launch banner + `tokenwar status` reminder + update status hint |

After install you simply type `codex`, `gemini`, `kimi`, `opencode`, or `copilot` as usual —
the banner prints the stack bar. If updates are pending, the bar shows
**"⬆ N updates · /tokenwar upgrade"** as an informational hint only; upgrades
run only when you call `tokenwar upgrade` yourself. A `tokenwar` command also
works in any shell:

```bash
tokenwar status # state of the 7 tools + providers
tokenwar gain # token savings + monthly $ value
tokenwar scan # local log scan + recommendations
tokenwar copilot # which tools reach GitHub Copilot CLI (add `wire` to fix)
tokenwar upgrade # bump managed tools (asks confirmation)
tokenwar doctor # status → check → gain
tokenwar disable context-mode # turn off one plugin without uninstalling it
tokenwar enable context-mode # turn it back on
```

> The banner is silent for non-interactive launches (`codex exec`,
> `gemini -p …`, `kimi -p …`, `opencode run …`, `copilot -p …`, `copilot --acp`,
> `copilot mcp/skill/plugin …`, pipes) so it never pollutes scripted output.

## Settings.json wipe protection

Claude Code can rewrite `~/.claude/settings.json` on session start (migration logic). A backup is kept at `~/.claude/settings.local.json` and a restore script merges it back:

```bash
bash ~/.claude/skills/tokenwar/scripts/restore-settings.sh
```

Add to `~/.bashrc` to auto-restore before each Claude Code launch:

```bash
alias claude='bash ~/.claude/skills/tokenwar/scripts/restore-settings.sh && command claude'
```

## Plugin-state detection (robust on any host)

`tokenwar status` reads the 4 Claude Code plugins' state from `claude plugin list --json` — the authoritative source (installed **and** enabled state in one shot). On hosts where that command returns nothing (an older `claude` CLI without the subcommand, or `claude` not on `PATH` in the shell running tokenwar), status falls back to on-disk config instead of reporting every plugin as *not installed*:

- `~/.claude/plugins/installed_plugins.json` → what is installed,
- `enabledPlugins` OR-merged from `settings.json` **and** `settings.local.json` → the enabled/disabled bit (Claude Code merges both at runtime).

An installed plugin absent from `enabledPlugins` is treated as enabled (Claude default); an explicit `false` stays `installed-disabled` — so `tokenwar disable <tool>` is always reflected correctly. Override the config dir with `CLAUDE_CONFIG_DIR`.

## Tests + CI

```bash
bats tests/
```

CI on every push to `main` and every PR — installs bats + shellcheck, runs the
full suite on `ubuntu-latest`, then a contract smoke that asserts every managed
tool **and every provider** is present in `status.sh --json` and `gain.sh --json`.
The smoke is what catches a tool or provider added to the text table but
forgotten in the JSON contract that `tokenwar scan` and downstream consumers
read — the two are rendered by separate code paths.
Loading
Loading