Local control data for agent tool use. agentctl validates reviewed tool
catalogs, detects catalog drift, evaluates local policy, records approvals and
audit data, and compiles one reviewed MCP tools/list capture into a catalog.
It is local-only. It does not connect to a host, execute tools, infer tool risk, or enforce host behavior.
The problem: An agent host can expose tools, but a developer needs reviewed, stable local data before the host acts on a tool call.
The solution: agentctl validates a catalog, locks it, detects drift, and
evaluates one declared call. It can also create local approval and audit records
and import a catalog from one reviewed MCP capture.
| Feature | What it does |
|---|---|
| Reviewed catalogs | Validates tool identity, input schemas, risk kind, and review data. |
| Deterministic locks | Creates a stable lockfile from a validated catalog. |
| Drift checks | Reports safe and unsafe changes before policy evaluation. |
| Local approvals | Records one durable approval request and resolution. |
| Audit chain | Verifies local, append-only approval and action-report records. |
| MCP import | Compiles one complete captured tools/list result with human review data. |
# Inspect the machine-readable contract.
python3 -m agentctl capabilities --json
# Compile one complete saved MCP tools/list result and a human review file.
python3 -m agentctl adapters plan \
--adapter=mcp-tools-list-v1 \
--input=capture.json \
--review=review.json \
--destination=agent-tools.json \
--json > plan.json
# Write the reviewed catalog, then make a deterministic lockfile.
python3 -m agentctl tools import --plan=plan.json --json
python3 -m agentctl tools lock \
--catalog=agent-tools.json --out=agent-tools.lock.json --json
# Check the catalog before an agent host makes a policy request.
python3 -m agentctl tools diff \
--lock=agent-tools.lock.json --catalog=agent-tools.json --json- Local control data: Catalogs, locks, approvals, and audit records are local files.
- Human review supplies risk: A capture does not set or override risk, approval, writable-root, or command-allowlist data.
- Fail closed: Unknown, partial, malformed, or unreviewed input fails.
- Stable automation: JSON results use one envelope on standard output.
- Host separation: The host remains responsible for discovery, execution, and enforcement.
agentctl needs Python 3.11 or later and uses the Python standard library at
runtime.
git clone https://github.com/Ozhiaki/agentctl.git
cd agentctl
python3 -m pip install .
agentctl capabilities --jsonpython3 -m venv .venv
. .venv/bin/activate
python3 -m pip install .
python3 -m agentctl doctor --jsonpython3 -m pip wheel . --no-deps --wheel-dir dist
python3 -m pip install dist/agentctl-0.4.0-py3-none-any.whlThere is no package-manager formula or install script at this time.
- Create a reviewed catalog or create a plan from one complete MCP capture.
- Validate and lock the catalog.
- Run
tools diffwhen freshness matters. - Run
policy checkfor one declared tool call. - When policy returns
ask, use the durable approval workflow if the host needs a local approval record.
python3 -m agentctl tools validate --catalog=agent-tools.json --json
python3 -m agentctl tools lock --catalog=agent-tools.json --out=agent-tools.lock.json --json
python3 -m agentctl policy check \
--lock=agent-tools.lock.json \
--tool=github.create_issue \
--args=args.json \
--cwd=/absolute/path \
--jsonv0.4 adds one explicit, reviewed JSON profile. It binds the catalog and lock
that a project uses. It can also select local agent and host labels and apply
narrow approval overlays. A profile is not discovered from the environment or a
home directory. Pass its path with --policy-profile every time.
Do not put secrets, tokens, keys, or personal data in identity metadata. Metadata is returned by inspection and policy results.
- Validate the reviewed catalog and read
data.catalog_hash. - Create or verify the lock and read
data.lock_hash. - Create a
project_policy_profile.v1JSON file at or above the catalog and lock. Use only relative POSIX paths below the profile directory. - Validate it before a host uses it.
python3 -m agentctl tools validate --catalog=agent-tools.json --json
python3 -m agentctl tools lock \
--catalog=agent-tools.json --out=agent-tools.lock.json --json
# Copy the two returned hashes into policy.json. Do not hash file bytes.
python3 -m agentctl profiles validate --policy-profile=policy.json --json
python3 -m agentctl profiles show \
--policy-profile=policy.json --fields=profile,catalog,rules --jsonA minimal profile has empty agents, hosts, and rules, with both identity
defaults set to null:
{
"profile_version": "1",
"profile_id": "example-project",
"catalog": {"path": "agent-tools.json", "hash": "sha256:..."},
"lock": {"path": "agent-tools.lock.json", "hash": "sha256:..."},
"identity_defaults": {"agent_id": null, "host_id": null},
"agents": [],
"hosts": [],
"rules": []
}Use the profile for a decision and use policy explain to review the selected
rule. The command decides local policy only. It does not prove host execution.
python3 -m agentctl policy check \
--policy-profile=policy.json --tool=docs.read --args=args.json \
--cwd=/absolute/project --json
python3 -m agentctl policy explain \
--policy-profile=policy.json --tool=docs.read --args=args.json \
--cwd=/absolute/project --jsonFor JSON pipelines, use --from-stdin instead of a file path:
printf '%s' '{"path":"README.md"}' | python3 -m agentctl policy check \
--policy-profile=policy.json --tool=docs.read --from-stdin \
--cwd=/absolute/project --json--catalog=- and policy check --args=- remain available in v0.4, but emit
DEPRECATED. Use the declared --from-stdin form. In JSON mode the warning is
only in the envelope. In human mode it is one standard-error line.
All commands support --json. JSON output goes to standard output. On an
error, the first error message also goes to standard error.
| Area | Commands | Purpose |
|---|---|---|
| Contract | capabilities, schema, doctor, robot-docs guide, conformance |
Inspect the declared CLI contract and local health. |
| Catalog | tools validate, tools lock, tools diff |
Validate, lock, and compare reviewed catalog data. |
| Profiles | profiles validate, profiles show |
Validate and inspect an explicitly selected project policy profile. |
| Policy | policy check, policy explain |
Evaluate and explain one lock-only or profile-aware policy decision. |
| State | state init |
Create an explicit local state directory. |
| Approvals | approvals create, list, show, resolve, cancel, report-action |
Record a local approval lifecycle and host action reports. |
| Audit | audit list, audit verify |
Inspect and verify the local audit chain. |
| Adapters | adapters list, adapters plan, tools import |
Plan and import one reviewed MCP capture. |
Use agentctl capabilities --json for every declared flag, input type, error
code, schema, and example.
mcp-tools-list-v1 accepts one complete JSON object with only a tools array.
Each captured tool has name, description, and inputSchema. The separate
review file supplies server_id, review metadata, and exactly one item for
each captured tool.
If an MCP response has nextCursor, first save all pages and create one input
object with the combined tools array. agentctl does not read additional
pages or combine server captures.
reviewed catalog ──> validate ──> lock ──> diff ──> policy check
│
└──> approval and audit records
saved MCP tools/list + human review ──> adapters plan ──> tools import ──> catalog
The plan command is read-only. Import writes only the reviewed catalog. Neither command starts a host, runs a tool, or creates an audit event.
| Capability | agentctl | MCP host | Manual JSON files |
|---|---|---|---|
| Execute a tool | No | Yes | No |
| Validate reviewed tool metadata | Yes | Host-specific | Manual |
| Lock and detect catalog drift | Yes | Host-specific | Manual |
| Local approval and audit records | Yes | Host-specific | No |
| Connect to live MCP | No | Yes | No |
Use agentctl when a cooperating host needs local reviewed control data. Use a
host when you need discovery, transport, or execution.
Check the input path and ensure its parent directory exists for output files.
python3 -m agentctl tools validate --catalog=agent-tools.json --jsonThe review must contain each captured tool source name exactly once. Add the missing review item or remove the extra item.
The target has different catalog content. Inspect the difference before an explicit replacement.
python3 -m agentctl tools import --plan=plan.json --dry-run --json
python3 -m agentctl tools import --plan=plan.json --force --yes --jsonCreate and pass an explicit absolute state directory.
python3 -m agentctl state init --state-dir=/absolute/state --jsonUse --json before or after the command path. Read diagnostics from standard
error, not standard output.
- No live MCP discovery, paging, host plug-ins, remote registry, or network use.
- No tool execution, sandboxing, or host enforcement.
- No automatic risk or approval classification.
- One plan represents one server capture; catalog merge is not supported.
- Import does not prove a catalog came from its stated capture or review file.
No. A cooperating host executes tools and enforces its own rules.
No. It reads a saved, complete MCP tools/list result from a local file or
standard input.
No. Import writes reviewed catalog data and does not use the durable state directory.
No. The review file supplies all policy-relevant facts.
Yes. Catalog, lock, diff, policy, and adapter commands work without a state directory.
python3 -m unittest discover -s tests
python3 -m agentctl conformance --profile=release-self-check --jsonAbout Contributions: Please don't take this the wrong way, but I do not accept outside contributions for any of my projects. I simply don't have the mental bandwidth to review anything, and it's my name on the thing, so I'm responsible for any problems it causes; thus, the risk-reward is highly asymmetric from my perspective. I'd also have to worry about other "stakeholders," which seems unwise for tools I mostly make for myself for free. Feel free to submit issues, and even PRs if you want to illustrate a proposed fix, but know I won't merge them directly. Instead, I'll have Claude or Codex review submissions via gh and independently decide whether and how to address them. Bug reports in particular are welcome. Sorry if this offends, but I want to avoid wasted time and hurt feelings. I understand this isn't in sync with the prevailing open-source ethos that seeks community contributions, but it's the only way I can move at this velocity and keep my sanity.
Apache-2.0. See LICENSE.