Skip to content

kcp-commands

No description provided.

Field Value
GitHub https://github.com/Cantara/kcp-commands
Language Java
Stars 7
Last updated 2026-03-15

README

kcp-commands

Not a CLI — typed knowledge infrastructure for 289 CLIs. Saves 33% of Claude Code's context window by injecting syntax context before execution and filtering noise after.

kcp-commands is a Claude Code hook — it runs invisibly around CLI tools, not as one. It intercepts every Bash tool call and applies three phases:

Phase When What it does
A -- Syntax injection Before execution Injects compact flag/syntax guidance so the agent picks the right flags immediately, never wastes a round trip on --help
B -- Output filtering After execution Strips noise (boilerplate, permission errors, hundreds of irrelevant lines) before the output reaches the context window
C -- Event logging After execution Writes every Bash call to ~/.kcp/events.jsonl for kcp-memory to index as episodic memory

Measured across a typical agentic coding session: 67,352 tokens saved -- 33.7% of a 200K context window recovered, equivalent to 33 additional tool call results fitting in the same context.

289 bundled manifests. Part of the Knowledge Context Protocol ecosystem. Read the release post for the full benchmark methodology and design rationale.


Why this works

Claude Code is designed to prefer shell commands (grep, find, ls) over reading full files — it reaches for the terminal first to narrow scope before loading content. This is the right instinct for token efficiency.

The gap is that Claude arrives at each Bash call with no pre-loaded knowledge of the command it is about to run:

  • Phase A injects syntax context at the moment Claude is already planning the command — it lands in exactly the right place in the reasoning chain, before the call is issued.
  • Phase B removes the noise that Claude cannot filter itself — raw command output arrives in the context window as-is, and there is no built-in mechanism to strip it before it consumes space.
  • Phase C fills the cross-session gap — Claude Code starts each session with an empty context window. The event log gives kcp-memory the raw material to reconstruct what happened across sessions.

kcp-commands does not change how Claude reasons. It gives Claude better inputs at the Bash tool boundary and cleaner outputs on the way back.


How it works

Phase A -- Command syntax context (before execution)

When Claude is about to run ps aux, the hook injects a compact additionalContext block:

[kcp] ps: Report a snapshot of running processes
Key flags:
  aux: All processes, all users, with CPU/memory  -> Default
  -ef: All processes, full format with PPID       -> Need parent PIDs
  --sort=-%cpu: Sort by CPU descending            -> Finding CPU hogs
Prefer:
  ps aux          # Find any process or check what's running
  ps aux | grep <name>  # Find a specific process

The agent picks the right flags immediately. No --help lookup, no man page parsing, no wasted round trip. Average saving: 532 tokens per avoided --help call.

Phase B -- Output noise filtering (after execution)

Large command outputs are piped through the manifest's noise filter before reaching the context window. Only the signal gets through:

Command Raw output After filter Reduction
ps aux 30,828 tokens 652 tokens 98%
find . -maxdepth 3 1,653 tokens 755 tokens 54%
git status 60 tokens 43 tokens 28%
git log -6 78 tokens 78 tokens 0% (already small)

The filter adds zero overhead on commands whose output is already concise. It only activates when there is noise to remove.

Phase C -- Event logging (after execution)

Every Bash hook call is appended to ~/.kcp/events.jsonl as a single JSONL line:

{"ts":"2026-03-03T16:04:24Z","session_id":"ad732c58-...","project_dir":"/src/myproject","tool":"Bash","command":"cat /tmp/daemon.log","manifest_key":"cat"}

Fields: ts (ISO-8601), session_id (Claude Code session UUID), project_dir (working directory), tool (always "Bash"), command (raw command, truncated to 500 chars), manifest_key (resolved manifest or null).

The write is asynchronous (virtual thread) and never blocks the hook response or raises an error. kcp-memory v0.2.0+ indexes these events to provide tool-level episodic memory across sessions.


Install

Both options download pre-built artifacts from GitHub Releases and install to ~/.kcp/. No source clone required.

curl -fsSL https://raw.githubusercontent.com/Cantara/kcp-commands/main/bin/install.sh | bash -s -- --java

Requires Java 21. Hook latency: ~12ms per call.

Node.js only

curl -fsSL https://raw.githubusercontent.com/Cantara/kcp-commands/main/bin/install.sh | bash -s -- --node

Requires Node.js 18+. Hook latency: ~250ms per call.

The installer places hook.sh, the daemon JAR, and cli.js in ~/.kcp/, then registers bash "$HOME/.kcp/hook.sh" as a PreToolUse hook in ~/.claude/settings.json. Restart Claude Code to activate.

Upgrade

# Re-run the installer to pull the latest release:
curl -fsSL https://raw.githubusercontent.com/Cantara/kcp-commands/main/bin/install.sh | bash -s -- --java
pkill -f kcp-commands-daemon; nohup java -jar ~/.kcp/kcp-commands-daemon.jar > /tmp/kcp-commands-daemon.log 2>&1 &

For contributors / local development

git clone https://github.com/Cantara/kcp-commands.git
cd kcp-commands
./bin/install.sh   # interactive prompt: --java or --node

When running from a clone, the installer falls back to a local Maven build if the release download fails.

Verify it's working

After restarting Claude Code, run any Bash command. You should see a [kcp] context block injected before it executes (visible in the hook output). To confirm all three phases:

# Phase A: daemon responds to health check
curl -sf http://localhost:7734/health && echo "daemon running"

# Phase C: events are being logged
tail -1 ~/.kcp/events.jsonl

Phase B is transparent -- you'll notice it when a normally noisy command like ps aux returns a concise, filtered result.


Performance

Backend Mean latency p95 Notes
Java daemon (warm) 14ms 17ms 19x faster than Node.js
Node.js (per-call) 265ms 312ms No JVM required
Baseline (cat) 2.3ms 3.1ms Pure OS overhead

Java daemon cold start is ~537ms (one-time per session). Break-even: 2 hook calls -- the daemon pays for itself within the first git status + ls.

Full methodology and raw numbers: docs/benchmark-results.md.


Supported commands

Bundled manifests (289 primed)

Gitgit log · git diff · git status · git add · git commit · git push · git pull · git fetch · git branch · git checkout · git stash · git merge · git rebase · git clone · git reset · git tag · git remote · git show · git cherry-pick · git bisect · git worktree · git submodule

Linux / macOSls · ps · find · cp · mv · rm · mkdir · cat · head · tail · grep · chmod · df · du · tar · ln · rsync · top · kill · systemctl · journalctl · lsof · netstat · ss · ping · free · watch · wget · dig · openssl · scp

Text processingjq · sed · awk · sort · uniq · wc · cut · xargs · tee · tr · diff · make · yq · base64 · sha256sum · envsubst · nl · xxd · strings · xmllint · column

Build toolsmvn · gradle · cargo · go build · go test · go mod · ant · sbt · dotnet

Package managersnpm · yarn · pnpm · bun · pip · brew · apt · yum · gem · conda · snap · pacman · composer · poetry · bundle

Runtimesnode · python3 · ruby · java · npx · mix

GitHub CLIgh pr · gh issue · gh repo · gh workflow · gh run · gh release · gh auth · gh api · gh gist

Dockerdocker ps · docker images · docker logs · docker build · docker run · docker exec · docker compose · docker network · docker volume · docker system · docker inspect · docker pull · docker push · docker tag

Kuberneteskubectl get · kubectl logs · kubectl describe · kubectl apply · kubectl exec · kubectl port-forward · kubectl delete · kubectl rollout · kubectl scale · kubectl top · kubectl config · kubectl create

Cloud / IaCaws · gcloud · az · terraform · helm · ansible · ansible-playbook · vagrant · pulumi · serverless · minikube · kind · packer · eksctl

Database CLIspsql · mysql · redis-cli · sqlite3 · mongosh · influx · pg_dump · pg_restore · mysqldump · duckdb

Securitygpg · ssh-keygen · ssh-add · certbot · keytool · age · vault · consul

System diagnosticstop · htop · vmstat · dstat · iotop · strace · dmesg · lsblk · iostat · uptime · id · who · crontab · tmux

Networkingnmap · nc · traceroute · ip · mtr · nslookup · whois

Modern CLIfzf · rg · fd · bat · delta · eza · hyperfine · tldr · jless · parallel · lazygit

Linters / CIshellcheck · hadolint · act · k9s

GitOps / K8s extraskustomize · argocd · flux

Deployment platformsfly · vercel · wrangler · heroku · doctl

Version managersasdf · mise · nvm · pyenv · rustup

Build & testcmake · ffmpeg · pytest · mkdocs · rclone

Developer HTTPhttp (HTTPie)

AI / LLMollama

System toolszip · unzip · gzip · date · env · chown

Windowsdir · tasklist · taskkill · ipconfig · netstat · where · robocopy · type · xcopy · winget (all include PowerShell equivalents)

Linters / formattersruff · eslint · prettier · mypy · golangci-lint · yamllint · markdownlint

Testingjest · vitest · playwright · cypress · k6 · grpcurl

Containers+podman · trivy · cosign

Monorepo / task runnersnx · turbo · just · bazel · task

Secrets / configsops · op · direnv

Modern CLI+zoxide · btm · dust · procs

Package managers+uv · apk · dnf · pipx

Runtimes+deno · go run · php · swift

Dev workflowpre-commit · gh codespace

Phase B output filtering is enabled on the high-noise commands: ps, find, top, df, du, grep, journalctl, systemctl, lsof, netstat, ss, rsync, npm, yarn, pnpm, pip, brew, apt, yum, mvn, gradle, cargo, go test, make, docker ps, docker images, docker logs, docker build, docker compose, kubectl get, kubectl logs, kubectl describe, aws, gcloud, az, terraform, dig, openssl, dir, tasklist, nmap, ansible-playbook, conda, sbt, vmstat, dstat, iotop, strace, iostat, psql, mysql, ffmpeg, pytest, cmake, rclone, eksctl, packer, dbt, duckdb.

Auto-generated manifests

When the hook encounters an unknown command, it runs <cmd> --help, parses the output, and saves a generated manifest to ~/.kcp/commands/ for future sessions. The agent gets syntax context on the very next invocation — no manual authoring needed.


Manifest format

Manifests are YAML files, one per command or subcommand:

# .kcp/commands/mvn.yaml
command: mvn                          # command name (must match what the agent runs)
platform: all                         # "all", "linux", "macos", or "windows"
description: "Apache Maven build tool"  # one-line summary shown in [kcp] context block

syntax:                               # ── Phase A: injected before execution ──
  usage: "mvn [options] [<goal(s)>]"
  key_flags:
    - flag: "test"
      description: "Run tests"
      use_when: "Verify the build"    # optional: helps the agent choose the right flag
    - flag: "-pl <module>"
      description: "Build specific module"
    - flag: "-DskipTests"
      description: "Skip test execution"
      use_when: "Fast build when tests are known good"
  preferred_invocations:
    - invocation: "mvn test -pl <module>"
      use_when: "Run tests for one module"

output_schema:                        # ── Phase B: applied after execution ──
  enable_filter: true
  noise_patterns:
    - pattern: "^\\[INFO\\] Scanning for projects"
      reason: "Boilerplate startup line"
    - pattern: "^\\[INFO\\] -+$"
      reason: "Separator lines"
  max_lines: 80
  truncation_message: "... {remaining} more Maven lines. Check for BUILD SUCCESS/FAILURE."

Top-level fields: command is the executable name. For subcommands, use a separate file named <command>-<subcommand>.yaml (e.g., git-log.yaml) and add a subcommand: log field. platform controls which OS the manifest applies on; "all" matches everywhere. description is shown in the [kcp] context block the agent sees.

syntax drives Phase A. The hook formats key_flags (up to 5) and preferred_invocations (up to 3) into a compact context block injected before execution.

output_schema drives Phase B. When enable_filter: true, the command's stdout is piped through a filter that removes lines matching noise_patterns (regexes) and truncates beyond max_lines. The {remaining} placeholder in truncation_message is replaced with the count of omitted lines.


Manifest lookup chain

For each Bash command, the hook resolves the manifest in order:

  1. .kcp/commands/<key>.yaml -- project-local override (checked into your repo)
  2. ~/.kcp/commands/<key>.yaml -- user-level (generated manifests land here)
  3. <package>/commands/<key>.yaml -- bundled primed library

First match wins. This lets you override bundled defaults per-project or per-user without modifying the package.


Architecture

hook.sh (thin client)
  |
  +--> Java daemon (localhost:7734) -- 12ms, warm
  |      |
  |      +--> /hook endpoint: resolve manifest, build additionalContext (Phase A)
  |      +--> /filter/{key} endpoint: noise filtering + truncation (Phase B)
  |      +--> EventLogger: async write to ~/.kcp/events.jsonl (Phase C)
  |      +--> /health endpoint: liveness check
  |
  +--> Node.js fallback (dist/cli.js) -- 250ms, cold
         |
         +--> hook.ts: parse command, resolve manifest, build context (Phase A)
         +--> filter.ts: pipe stdout through noise patterns + truncation (Phase B)

hook.sh is the registered hook script. It tries the Java daemon first (HTTP POST to localhost:7734). If the daemon is not running, it starts it from the JAR. If no JAR exists, it falls back to Node.js.

Manifest resolution follows the three-tier lookup chain described above. Unknown commands trigger auto-generation via --help parsing.

Phase B filtering wraps the original command with a pipe: ps aux becomes ps aux | curl -s -X POST http://localhost:7734/filter/ps --data-binary @- (Java daemon) or ps aux | node cli.js filter ps (Node.js fallback). The filter reads stdin, strips noise patterns, truncates to max_lines, and appends a truncation message with the count of omitted lines.

Phase C event logging runs on every hook call, regardless of whether a manifest was found. The Java daemon writes asynchronously on a virtual thread; it never blocks the hook response. Phase C is currently Java-daemon only.


Repository structure

kcp-commands/
  bin/
    hook.sh              # thin client: daemon -> Node.js fallback
    install.sh           # registers hook in ~/.claude/settings.json
  typescript/            # Node.js hook + filter implementation
    src/
      hook.ts            # Phase A: parse command, inject context
      filter.ts          # Phase B: noise filtering + truncation
      resolver.ts        # three-tier manifest lookup
      generator.ts       # auto-generate from --help
      parser.ts          # YAML manifest parser
      model.ts           # TypeScript interfaces
      cli.ts             # CLI entry point
    dist/                # compiled output
    package.json
  java/                  # Fast daemon (12ms/call warm)
    pom.xml
    src/
      .../HookHandler.java   # Phase A + B: manifest resolution, context injection, filter piping
      .../EventLogger.java   # Phase C: async JSONL event writer
      .../ManifestResolver.java
      .../ManifestGenerator.java
    target/
  commands/              # bundled primed manifests (289)
    ls.yaml
    ps.yaml
    find.yaml
    git-log.yaml
    git-diff.yaml
    ...
  tools/
    benchmark.py         # latency benchmark script
    benchmark_agent.py   # token savings benchmark script
  docs/
    benchmark-results.md # full benchmark methodology and data
  .github/
    workflows/
      release.yml        # builds JAR + Node.js, publishes GitHub release on tag

Writing your own manifests

  1. Create a YAML file following the manifest format above.
  2. Place it in .kcp/commands/ (project-local) or ~/.kcp/commands/ (user-global).
  3. The hook picks it up on the next Bash call -- no restart needed.

Good candidates for custom manifests: - Build tools your team uses daily (mvn, gradle, cargo, go build) - Cloud CLIs with verbose output (aws, gcloud, az, kubectl) - Project-specific scripts where you want the agent to know the right flags


Releases

Version Manifests Notes
v0.1.0 18 Initial: git, Linux/macOS basics, curl, ssh, docker, kubectl
v0.2.0 32 Windows, extended git, networking
v0.3.0 62 Full initial library
v0.4.0 114 Text processing, build tools, package managers, cloud/IaC
v0.5.0 214 System tools, DB CLIs, security, modern CLI, monitoring
v0.6.0 244 ollama, HTTPie, ffmpeg, pytest, cmake, mkdocs, rclone, pg_dump/restore, mysqldump, glab, fly/vercel/wrangler/heroku/doctl/eksctl, vault/consul/packer, kustomize/argocd/flux, asdf/mise/nvm/pyenv/rustup, dbt, lazygit
v0.6.1 244 Fix: index.txt now auto-generated by Maven — v0.4.0–v0.6.0 shipped with only 62 manifests in the daemon due to a stale index. Install path changed to ~/.kcp/ (no source clone needed). cli.js now released as a downloadable artifact.
v0.7.0 244 README install section clarifications; Releases changelog table; v0.6.1 patch documented in blog post.
v0.8.0 283 uv, apk, dnf, pipx, winget, deno, go-run, php, swift, ruff, eslint, prettier, mypy, golangci-lint, yamllint, markdownlint, podman, trivy, cosign, nx, turbo, just, bazel, task, sops, op, direnv, jest, vitest, playwright, cypress, k6, grpcurl, zoxide, btm, dust, procs, pre-commit, gh-codespace
v0.9.0 283 Phase C: EventLogger — writes every Bash hook call to ~/.kcp/events.jsonl (async, virtual thread, ReentrantLock); consumed by kcp-memory v0.2.0+ for tool-level episodic memory
v0.12.0 284 KCP 0.9 Federation Release. knowledge.yaml bumped to kcp_version: "0.9", added manifests block (federation link to KCP spec). New manifest: duckdb (in-process analytical SQL engine). Aligned with kcp-mcp@0.12.0.
v0.13.0 289 +5 manifests: gws, gws-auth, gws-gmail, gws-calendar, gws-drive — Google Workspace CLI (gmail.modify, calendar, drive scopes)
v0.14.0 289 KCP 0.10 Discovery & Versioning Release. knowledge.yaml bumped to kcp_version: "0.10". KCP 0.10 adds RFC-0007 Query Vocabulary (normative pre-invocation discovery), federation version pinning (version_pin + version_policy), instruction file bridge guide, and kcp init spec.

Knowledge manifest

This repository ships a knowledge.yaml and llms.txt for AI agent navigation.


License

Apache 2.0 -- see LICENSE.

Copyright 2026 Cantara / eXOReaction AS.