{"id":51206258,"url":"https://github.com/ymxfl/agent-usage","last_synced_at":"2026-06-28T03:04:42.046Z","repository":{"id":367112885,"uuid":"1278703314","full_name":"ymxfl/agent-usage","owner":"ymxfl","description":"Local-first usage statistics for coding agents — tracks Skill loads and MCP tool calls via native hooks, injected MCP accounting, and a transparent stdio proxy. Opt-in selection, local SQLite storage. Claude Code \u0026 JoyCode.","archived":false,"fork":false,"pushed_at":"2026-06-24T15:08:02.000Z","size":247,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-24T17:07:52.242Z","etag":null,"topics":["claude-code","cli","llm-agents","mcp","model-context-protocol","telemetry","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ymxfl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-24T03:12:44.000Z","updated_at":"2026-06-24T15:10:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ymxfl/agent-usage","commit_stats":null,"previous_names":["ymxfl/agent-usage"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ymxfl/agent-usage","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ymxfl%2Fagent-usage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ymxfl%2Fagent-usage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ymxfl%2Fagent-usage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ymxfl%2Fagent-usage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ymxfl","download_url":"https://codeload.github.com/ymxfl/agent-usage/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ymxfl%2Fagent-usage/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34875390,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude-code","cli","llm-agents","mcp","model-context-protocol","telemetry","typescript"],"created_at":"2026-06-28T03:04:41.988Z","updated_at":"2026-06-28T03:04:42.039Z","avatar_url":"https://github.com/ymxfl.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# agent-usage\n\n**English** | [简体中文](README.zh-CN.md)\n\n**Local-first usage statistics for coding agents.**\n\n`agent-usage` records how often a coding agent loads Skills and calls MCP tools, then\nanswers `/usage-stats` from inside the agent. It is designed to be accurate where an\nagent exposes a real event surface, honest about where it can only estimate, and silent\nabout your prompts and data — it stores counts and metadata, never content.\n\nThe first release targets **Claude Code** and **JoyCode**, with all agent-specific\nbehavior isolated behind a versioned adapter contract so the storage and reporting core\nstays agent-agnostic.\n\n---\n\n## Why\n\nCoding agents increasingly route work through Skills and MCP servers, but there is rarely\na clear answer to *\"which Skills do I actually use, which MCP tools are slow, and which\nones are failing?\"* `agent-usage` gives you that answer locally, without shipping your\ndata anywhere.\n\n## How it works\n\nEach agent adapter picks the best available observation strategy for what it can actually\nsee, and every recorded event is tagged with its **evidence** so reports never collapse\nexact and estimated counts into one misleading number.\n\n| Strategy | What it observes | Evidence | Precision |\n| --- | --- | --- | --- |\n| **Native hooks** (Claude Code) | Exact platform Skill invocations and MCP tool calls through plugin hooks | `native_hook` | `exact` |\n| **Injected MCP accounting** (JoyCode) | A managed instruction that asks the agent to call `record_skill` every time an injected Skill is used | `injected_mcp` | `best_effort` |\n| **stdio MCP proxy** (JoyCode) | A transparent JSON-RPC proxy that relays stdio MCP traffic and records attempts, outcomes, and durations | `mcp_proxy` | `exact` |\n\n### What is counted\n\n- **Injected Skill accounting events** (`skill_session_load`) — the portable\n  best-effort metric used by injected adapters. The event name is retained for schema\n  compatibility, but repeated `record_skill` calls are counted when the agent follows\n  the injected instruction.\n- **Skill invocations** (`skill_invocation`) — every native Skill invocation, where the\n  adapter supports it (Claude Code).\n- **MCP calls** (`mcp_call`) — each tool request is an attempt with an outcome of\n  `success`, `failure`, or `unknown` (started but the connection/process ended before a\n  result).\n\nThe `usage-stats` server's own `record_skill` and `query_usage` calls are excluded from\nMCP totals, and calls denied before execution are not counted as executed calls.\n\n## Supported agents\n\n| Agent | Skills (native hook) | Skills (injected) | MCP (native) | MCP (stdio proxy) | Skill watching |\n| --- | :---: | :---: | :---: | :---: | :---: |\n| `claude-code` | ✅ | ✅ | ✅ | — | — |\n| `joycode` | — | ✅ | — | ✅ | ✅ |\n\n## Privacy\n\nBy design, `agent-usage` **never stores**:\n\n- Prompts or conversation messages\n- Skill body content\n- MCP arguments or results\n- Environment variables, API keys, or auth headers\n\nStored paths are limited to local installation state. Telemetry uses stable IDs and\noptional project display names rather than full paths. The proxy only inspects the\nJSON-RPC method and tool name required for aggregation — nothing more.\n\n## Requirements\n\n- **Node.js ≥ 24** (uses the built-in `node:sqlite`)\n- A supported coding agent (Claude Code and/or JoyCode)\n\n## Build\n\nThe CLI ships as a single bundled ESM file. Clone and build it:\n\n```bash\ngit clone https://github.com/ymxfl/agent-usage.git\ncd agent-usage\nnpm install\nnpm run build      # -\u003e dist/agent-usage.mjs\n```\n\nThen either invoke it directly or make the binary available on your `PATH`:\n\n```bash\nnode dist/agent-usage.mjs --help\n# or\nnpm link           # exposes the `agent-usage` command\n```\n\nUseful npm scripts:\n\n| Script | Purpose |\n| --- | --- |\n| `npm run build` | Bundle `src/cli.ts` to `dist/agent-usage.mjs` (esbuild) |\n| `npm run check` | Type-check with `tsc --noEmit` |\n| `npm test` | Run the Vitest suite |\n| `npm run test:watch` | Watch-mode tests |\n\n## Usage\n\nAll collection is **opt-in**. A fresh install records nothing until you explicitly select\ntargets with `configure`.\n\nFor day-to-day setup, run the interactive wizard and follow the menus:\n\n```bash\nagent-usage\n```\n\nThe wizard lets you choose an operation, choose an agent, and multi-select Skills and\nMCP servers when configuring targets. The explicit commands below remain available for\nscripts and repeatable setup.\n\n### 1. Install for an agent\n\nInstalls the accounting MCP server, the `/usage-stats` command, and (for Claude Code) the\nnative hooks — at user scope by default.\n\n```bash\nagent-usage install claude-code\nagent-usage install joycode\n```\n\n### 2. See what can be observed\n\n```bash\nagent-usage list-targets claude-code\n```\n\nLists discovered Skills and MCP servers with the modes each supports, what is currently\nselected, unresolved patterns, and any issues. `health` reports the same coverage without\nmutating configuration.\n\n### 3. Select what to collect\n\nPatterns are case-sensitive, anchored to the full name, and support `*` wildcards. MCP\nidentifiers use `server` or `server.tool`; selecting a server selects all its tools.\n\n```bash\n# Specific Skills, by evidence mode\nagent-usage configure claude-code --native-skill review --inject-skill deploy\n\n# An MCP server (and its tools)\nagent-usage configure claude-code --mcp 'github.*'\n\n# Or select everything in one shot\nagent-usage configure joycode --all-skills injected_mcp --all-mcp\n```\n\nRepeated options build the **complete desired allowlist** (they replace, they don't\nappend). The resulting policy lives at `~/.agent-usage/config.json` and is shared by the\nCLI, hooks, injectors, watchers, and proxies.\n\n```json\n{\n  \"version\": 1,\n  \"agents\": {\n    \"claude-code\": {\n      \"skills\": { \"native_hook\": [\"review\"], \"injected_mcp\": [\"deploy\"] },\n      \"mcp\": [\"github.*\"]\n    },\n    \"joycode\": {\n      \"skills\": { \"injected_mcp\": [\"deploy\", \"release-*\"] },\n      \"mcp\": [\"github\", \"filesystem\"]\n    }\n  }\n}\n```\n\n### 4. Ask for the report\n\nFrom inside the agent:\n\n```\n/usage-stats\n```\n\n…or from the terminal. Defaults to the last 7 days.\n\n```bash\nagent-usage report              # last 7 days\nagent-usage report today\nagent-usage report 30d --agent claude-code --kind mcp_call\n```\n\nThe report breaks down totals by agent and evidence/precision, lists top Skills, and shows\nMCP attempts with success / failure / unknown outcomes and average duration, plus coverage\nwarnings (`best-effort`, `stdio-only`, read-only Skills, hook policy blocks, pending sync).\n\n```text\nUsage statistics — 7d\n\nTotals\n- claude-code · skill_session_load · [native_hook, exact]: 42\n- claude-code · mcp_call · [native_hook, exact]: 128\n- joycode · skill_session_load · [injected_mcp, best_effort]: 7\n\nSkills\n- claude-code · review: 42\n\nMCP\n- claude-code · github.create_issue: 5 attempts (success 5, failure 0, unknown 0); avg 318 ms\n\nCoverage warnings\n- Injected MCP skill usage is best-effort and may be incomplete.\n```\n\n### 5. Webhooks and local web console\n\nYou can forward every newly recorded usage event to an HTTP webhook. Duplicate events\nignored by the local database are not reported again, and webhook failures never block\nthe agent.\n\n```bash\nagent-usage webhook set https://example.test/usage\nagent-usage webhook show\nagent-usage webhook unset\n```\n\nFor local inspection, start the browser console:\n\n```bash\nagent-usage web\n```\n\nIt listens on `http://127.0.0.1:17891` by default. The page can view targets, run common\ninstall/configure/repair operations, read reports, configure the webhook URL, and set it\nto the built-in local receiver (`/webhook/usage`) so you can watch usage events arrive in\nreal time.\n\n### Lifecycle commands\n\n| Command | Purpose |\n| --- | --- |\n| `install \u003cagent\u003e` | Register the MCP server, command, and hooks |\n| `sync [agent]` | Instrument newly discovered Skills; wrap new stdio MCP servers |\n| `health [agent]` | Report coverage without changing anything |\n| `repair [agent]` | Restore missing managed entries from the manifest |\n| `uninstall \u003cagent\u003e` | Remove managed blocks/entries; preserves unrelated config |\n| `uninstall \u003cagent\u003e --purge-data -y` | Also delete the shared database (after the last adapter is gone) |\n\n`uninstall` preserves `~/.agent-usage/usage.db` by default, so removing one agent never\nerases another's history. `--purge-data` is refused until every adapter is removed and is\nguarded by `--yes` in non-interactive sessions.\n\n### Internal commands\n\n`agent-usage mcp --agent \u003cid\u003e` runs the accounting MCP server (exposing `record_skill` and\n`query_usage`), and `agent-usage proxy --agent \u003cid\u003e --server \u003cname\u003e \u003ccommand…\u003e` runs the\nstdio MCP proxy. These are wired in automatically by `install`/`sync`; you normally don't\ninvoke them by hand.\n\n## Architecture\n\n```text\nAgent session\n  ├─ Agent adapter\n  │   ├─ native hooks, and/or\n  │   ├─ injected Skill accounting, and/or\n  │   └─ stdio MCP proxy\n  ├─ usage-stats MCP server\n  │   ├─ record_skill\n  │   └─ query_usage\n  └─ local core\n      ├─ event normalization\n      ├─ selection policy\n      ├─ deduplication\n      ├─ SQLite WAL storage\n      └─ aggregation / reporting\n```\n\nThe **core** owns event schema validation and migration, stable Skill ID generation,\nSQLite WAL writes with bounded busy retries, deduplication, time-range aggregation, and\nterminal report rendering. It has **no** Claude Code or JoyCode path logic.\n\nEach **adapter** composes three strategy interfaces — `SkillInstrumentationStrategy`,\n`McpObservationStrategy`, and `ConfigMutationStrategy` — and implements the\n[`AgentAdapter`](src/adapters/types.ts) contract:\n\n```ts\ninterface AgentAdapter {\n  readonly id: string;\n  readonly capabilities: Capabilities;\n  discover(): Promise\u003cstring[]\u003e;\n  listTargets(): Promise\u003cDiscoveredTargets\u003e;\n  configure(policy: AgentSelectionPolicy): Promise\u003cOperationResult[]\u003e;\n  install(scope: Scope): Promise\u003cOperationResult[]\u003e;\n  sync(scope: Scope): Promise\u003cOperationResult[]\u003e;\n  repair(scope: Scope): Promise\u003cOperationResult[]\u003e;\n  uninstall(scope: Scope): Promise\u003cOperationResult[]\u003e;\n  health(): Promise\u003cCoverageReport\u003e;\n}\n```\n\n**Adding an agent** requires a new adapter, strategy selection, configuration fixtures,\nand contract tests — never changes to core storage or reporting.\n\nData lives under `~/.agent-usage/`:\n\n```text\n~/.agent-usage/\n├── usage.db            # SQLite (WAL mode)\n├── config.json         # selection policy\n├── state/\n│   ├── installs.json\n│   └── joycode-skills.json\n└── logs/\n    └── errors.log\n```\n\nStorage errors are logged and **never block** the original agent, Skill, or MCP call —\ncollection is fail-open.\n\n## Project structure\n\n```text\nsrc/\n├── cli.ts                  # commander CLI entrypoint\n├── core/                   # agent-agnostic: db, events, query, selection, repository\n├── adapters/\n│   ├── claude/             # Claude Code: native hooks + plugin files\n│   ├── joycode/            # JoyCode: injected accounting + stdio proxy + skill watcher\n│   ├── registry.ts\n│   └── types.ts            # AgentAdapter contract\n├── mcp/                    # usage-stats MCP server + service\n├── proxy/                  # transparent stdio JSON-RPC proxy + protocol observer\n└── report/                 # terminal report rendering\ntests/                      # Vitest — core, adapters, injection, proxy, integration\nscripts/build.mjs           # esbuild bundle\ndocs/superpowers/           # design spec and implementation plans\n```\n\n## Known limitations\n\n- **JoyCode Skill telemetry is best-effort** — it depends on the model following the\n  injected instruction. The instruction requests a `record_skill` call on every Skill\n  use, including repeated uses in one session, but JoyCode can still miss counts if the\n  model reuses cached context or skips the accounting call.\n- **JoyCode remote MCP transports** (HTTP/SSE/Streamable HTTP) are not counted in this\n  release; only stdio MCP traffic that traverses the proxy is observed exactly.\n- A **newly created JoyCode Skill can race** with the watcher during the session it is\n  created; reconciliation is guaranteed for the next invocation or next session, not for\n  zero-loss same-session injection.\n- No HTML or hosted dashboard — the first release is terminal/agent-only.\n\nSee the [design spec](docs/superpowers/specs/2026-06-18-cross-agent-usage-stats-design.md)\nfor the full objectives, counting semantics, and acceptance criteria.\n\n## Development\n\n```bash\nnpm install\nnpm run check     # type-check\nnpm test          # full suite (30 test files)\n```\n\nAll file mutations are transactional at the file level: parse and validate before\nmutation, write to a sibling temp file, preserve permissions, atomically rename into\nplace, and update the state manifest only after success. Conflicting user edits are never\noverwritten silently.\n\n## License\n\n[MIT](LICENSE) © 2026 ymxfl\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fymxfl%2Fagent-usage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fymxfl%2Fagent-usage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fymxfl%2Fagent-usage/lists"}