agent-control-plane-core weekly downloads statistics
By AlexanderMattTurner · npm · Claude Code
Vendor-neutral control-plane contract for coding agents: a normalized ToolCallEvent/Verdict schema with per-agent adapters (Claude Code, Codex, Amp, Gemini CLI) and a conformance suite.
agent-control-plane-core has 21,300 recorded weekly downloads on npm, a decrease of 29.0% over the past 30 days.
It ranks #735 of 2,255 tracked npm listings by weekly downloads.
Over 90 days, weekly downloads changed by +1118%.
PluginStats has 121 daily observations since Jun 19, 2026; the latest is from Oct 17, 2026.
About agent-control-plane-core
agent-control-plane-core
**One shape for "a coding agent is about to run a tool" and "here's what my guardrail decided" — so you write your tool once and it works across every agent.**
The problem this solves
Coding agents — Claude Code, Codex, Gemini CLI, opencode, Amp, and friends — all let you hook into their tool-call loop: before a shell command runs, after a file is written, when a prompt is submitted. That's where you'd plug in a security guardrail, an audit log, a secret redactor, a policy engine.
But every agent speaks its own protocol. One sends you tool_name + tool_input on stdin and wants {"permissionDecision":"deny"} back plus exit code 2. Another names the fields differently, blocks by throwing inside a plugin, or can only _observe_ and not veto. The field names differ, the "block this" signal differs, and each one drifts on its own release cadence.
So if you build a tool that touches more than one agent, you end up writing and maintaining N copies of the same logic — one per agent — and re-testing all of them every time an agent ships a new field. That's the tax this package removes.
What it gives you
• ToolCallEvent — one normalized, agent-agnostic view of "an agent event" (a tool about to run, a tool that just ran, a prompt, a session start). • Verdict — one normalized way to say what your guardrail decided: allow / deny / ask, optionally with a rewritten input or extra context. • Adapters — a thin { parse, render } translator per agent, plus the declaration of what that agent's transport cannot carry. parse turns that agent's raw hook payload into a ToolCallEvent; render turns your Verdict back into the real native signal that agent enforces (the right JSON body, exit code, or thrown error — not just a print).
You write your logic once against the normalized types. Adding support for a new agent is a new adapter (~one file + fixtures), not a rewrite of your tool. The agent-specific field names live only inside that agent's adapter.
Who wants this
Anyone building a tool that sits in the tool-call loop of more than one coding agent, and doesn't want to fork it per agent:
• Security guardrails — deny-listers, command/path sanitizers, permission gates. • Observability & audit — log or replay every tool call in a uniform shape. • Redaction / DLP — strip secrets from tool inputs or outputs before they move. • Policy engines — one rule set enforced identically no matter which agent runs.
If you only ever target a single agent, you don't need this — just use that agent's native hooks. The value is entirely in the _N-agents_ case.
Not a security boundary. A Verdict is advisory: a useful first filter, never the last line of defense. Some agents can't enforce a deny at all (the adapter marks those observe_only), so a real deployment still needs a sandbox underneath. Treat the control plane as a policy layer on top of isolation, not a replacement for it.
Install
The model
An Adapter is { AGENT, COVERAGE, UNRENDERED_FIELDS, NATIVE_ASK_TIER, parse, render }:
Read NATIVE_ASK_TIER instead of keeping a list of which agents to escalate an ask to a deny on: a guardrail that must not let an ask through escalates it where the flag is false, and leaves it alone where the host does the asking. It describes the HOST, not the verdict — ask renders as enforced: false everywhere — and it names the pre-tool gate, since a tool that already ran has nothing left to suspend. Conformance probes your real render against it, so a true whose ask renders as your abstaining allow fails, and so does a false whose ask renders as anything but your own advisory deny.
readonlySet([]) is the row for a kind that carries all three; UNRENDERED_ON_UNKNOWN is the row for one that carries none. Both come from agent-control-plane-core/contract. Build every row with readonlySet — a plain Set exposes clear(), so a consumer could empty a declaration after conformance certified it, and Object.freeze does not stop that. Freeze the map itself too: an immutable row still leaves a consumer free to swap a whole row for one claiming another channel. A render that ships a field the row declares dropped fails conformance, and so does a row that declares a channel the render does not carry.
Usage
Writing your own hook entry? agent-control-plane-core/runtime publishes the plumbing the four bin/*-hook.mjs entries share — readStdin, renderHookResponse (parse → judge → render, falling back to the failure response THAT host expects) and emit, whose fully-drained write is what stops a large deny body being truncated on a non-blocking pipe and silently becoming an allow.
The core contract and every adapter (claude, codex, amp, gemini) are also on the default entry:
Drift discipline (the point of the seam)
Agent protocols drift additively and independently — N agents, N release cadences. So parse never throws on an event type or tool-input field it does not model: an unrecognized event becomes EventKind.UNKNOWN with its native name kept in meta.native_event, and every unmodelled field survives in input or meta.passthrough. An additive upstream change is a no-op, not an outage.
The core models only the stable middle — four event kinds, three decisions, and the Bash/Edit/Write/Read/WebFetch tool inputs (MODELED_TOOLS). Exotic per-agent tools pass through untouched.
Writing a new adapter
An adapter for cursor/cline/gemini-cli/aider is a thin, independently-pinned translator with its own golden fixtures. It must pass the conformance suite:
The harness pins both directions and rejects a vacuous suite:…
Description from the npm listing.
- claude
- claude-code
- codex
- agent
- control-plane
- hooks
- adapter
- guardrail
Where agent-control-plane-core sits in the listing
Each band is one page of 20. Weekly downloads on a log scale. Placement is projected from weekly downloads, so it can differ from the marketplace's own sort order. Hover a dot to see the listing.
Charts
Images: 30d · 1y · all time · 1600×900 dark
Adoption over time
7/30/90-day growth
Filled points are observed values; hollow points come from Internet Archive snapshots of the listing page. Dashed segments span periods with no observations — values between points are not interpolated.
Recent observations
Full history (121)Similar npm Claude Code plugins
Data source
Weekly downloads (trailing 7 complete days) come from the official npm downloads API. Downloads include CI and mirrors and are not equivalent to installs or users. npm publishes no ratings.
Listing: https://www.npmjs.com/package/agent-control-plane-core. First seen Oct 16, 2026; last successful collection Oct 19, 2026. See the methodology.