Documentation
AgentX is a runtime firewall for AI agents. It blocks catastrophic tool calls (DROP TABLE, secret exfiltration, SSRF) before they execute, then coaches the agent to a safe path so the run finishes. Pick your path below and start keyless in 30 seconds.
Try it
01Get started
Pick your language. Each path shows only its own steps, numbered in the order you take them.
This path is for a TypeScript tool your code calls directly, a Vercel AI SDK tool() or any object with an execute function, not behind an MCP server. If your agent reaches its tools through MCP servers instead, the keyless agentx-mcp proxy protects those today with no code change and no key: switch to the MCP tab above.
This path is for MCP servers your client launches itself, the ones with a command entry in your mcp.json (Claude Code, Cursor, Claude Desktop, Windsurf, VS Code). agentx-mcp wraps that command, so every tools/call is screened before it reaches the server. If your tools are Python functions in your own process, the decorator is your path: switch to the Python tab above.
A remote MCP server your client reaches over HTTP is not wrapped this way today. If that is your setup, tell us in our Discord (the bugs and feature requests channel) so we know who needs it.
Wrap a tool in one line. Every call it makes is written down on your machine (tool and argument names, no values), and audit prints what your agent did. Nothing is blocked, so your agent runs as it does today.
npm install @agentx-core/security-sdkimport { agentxWatchAll }
from "@agentx-core/security-sdk";
// was: tools: { runSql, sendEmail }
tools: agentxWatchAll({ runSql, sendEmail })Your tools behave exactly as they do today: the wrap watches and records, and blocks nothing. See what it recorded with npx @agentx-core/security-sdk audit
Inventory first? Lists every tool your agent can call, ranked by risk, with no install:
npx @agentx-core/scan .Step up to the gateway below to block: the in-process guard, set up with you.
One decorator, @agentx_protect, on any tool catches the dangerous call in process RAM before it runs, no key.
pip install agentx-security-sdkfrom agentx_sdk import agentx_protect
@agentx_protect(agent_id="crm")
def call_api(url):
return requests.get(url)
# the agent picks the url at runtime:
call_api("http://169.254.169.254/")The tool behaves exactly as it does today: the wrap watches and records, and blocks nothing. Add posture="enforce" to the decorator above when you want it stopping calls, and it keeps blocking until you delete the argument. See what it recorded with agentx audit
Step up to the gateway below for the full floor and Recover.
One line in mcp.json wraps any server. The dangerous tools/call never reaches it, and the agent is coached to self-correct keyless.
{
"mcpServers": {
"filesystem": {
"command": "uvx",
"args": [
"agentx-mcp", "npx", "-y",
"@modelcontextprotocol/server-filesystem",
"/data"
]
}
}
}Config uses uvx (no install). Want to watch it block something first?
Trying it on servers you already use? A wrapped server records every call and blocks none of them. AGENTX_POSTURE=enforce in that server's env is how you make it start blocking. Add it per server block; the ones you leave alone keep watching. Read it back with uvx agentx-mcp --audit.
This is keyless and it is your protection for MCP servers today. Gateway-backed Recover over MCP is on the roadmap.
Want the gateway to cover your MCP traffic too?
The install is all steps 02 and 03 need. The decorator comes at step 04.
The gateway is an HTTP service, so any language can call it. Your tool sends the call to /v1/evaluate before it runs, and acts on the verdict. That is all our TypeScript guard is, and the same thin client is straightforward in any language.
What you do not get yet is a packaged client for your stack, or a keyless local floor like the Python one. We write that client with you during onboarding.
Which language should we package next?
Or skip the vote and talk to us directly in our Discord and we will wire the gateway into your stack with you.
What you would run
For context, not as a step. The gateway is the service your tools would call, and it is free and runs locally. There is no point standing it up until something in your stack calls it, which is the part we do together.
docker compose up -d # what runs once we have wired your clientWhat your tools call over HTTP, whatever language they are written in. The full deterministic floor (AST parsing, the SSRF normalizer, the whole failure catalog), coached recovery that finishes the run, and team review before a risky action runs.
The floor runs with no key at all. Your own Gemini key turns on Recover, which writes the safe path and runs the retry for you. There is no keyless local option for your language yet.
02Wrap a tool, then see what it recorded
One line around each tool. Your tools run exactly as before; every call is written down in the folder your agent runs from.
import { agentxWatchAll } from "@agentx-core/security-sdk";
const result = await generateText({
model,
tools: agentxWatchAll({ runSql, sendEmail }), // was: tools: { runSql, sendEmail }
prompt,
});Then, from that folder, see which tools your agent called, how many times, what each one touched, which wrapped tools it never reached for, and what is new since you last looked:
npx @agentx-core/security-sdk audit # grouped by tool4 calls across 3 tools since 2026-09-14 15:09
4 tools wrapped. 3 called. 1 never ran.
TOOL CALLS SURFACE ARGUMENTS
-----------------------------------------------------------------------
runSql 2 DB limit, sql
refund 1 - amount, currency, order_id
largest amount passed: ≥100,000
sendEmail 1 - body, to
NEW SINCE YOU LAST LOOKED
sendEmail first time we have seen this toolThe last block is one line per change since the previous read, and absent when nothing changed. A repeat run that does exactly what the last one did prints nothing there.
npx @agentx-core/security-sdk audit --calls # one row per call, newest first--json prints the same data for a program, always complete, with the exit code carrying the CI verdict below.
The file holds tool and argument names, no values. Only wrapped tools appear. Nothing is blocked.
In CI, fail the job when there was nothing to read, so a run where the agent never ran cannot pass as a clean audit:
npx @agentx-core/security-sdk@^0.2.0 audit --require-calls # exits 2 on an empty recordThe whole GitHub Actions job, with the record kept as a build artifact, is in the package README on npm.
To watch a dangerous call get stopped and coached (step 05 adds this to your tools):
Open the playground02See it work
Once the SDK is installed, watch a prompt-injected DROP TABLE get blocked in ten seconds, offline, with no key and no gateway:
agentx demo # watch a prompt-injected DROP TABLE get blockedThen see what audit records, on the same demo. Audit watches every call and blocks nothing:
agentx demo --audit # then: agentx audit03See what it recorded
This screen lists every wrapped tool call: which tool, how many times, and what each call touched. Right now that is the demo run from step 02, our agent and not yours. Wrap one of your own tools in step 04 and its calls land here too.
agentx audit # grouped by toolTOOL CALLS SURFACE ARGUMENTS
-----------------------------------------------------------------------
fetch_invoice_pdf 1 HTTP url
issue_refund 1 - amount, currency +2 more
largest amount passed: >=1,000
run_sql 1 DB db_session, query
2 calls tripped a policy.
1 was stopped while blocking was on; 1 ran because audit was on.--calls gives one row per call, newest first, with the time. Each row ends with what became of the call: ran, stopped, ran, flagged (it tripped a policy and was let through), or retried (it was stopped, and the agent then got there another way).
agentx audit --calls # one row per call, newest firstTIME TOOL STATUS SURFACE ARGUMENTS
2026-08-31
18:00:30 query_orders_db* ran, flagged DB sql
18:00:30 write_ticket_note* ran FS contents, path
18:00:30 run_sql* retried DB db_session, query
* 3 rows above written by AgentX's own demo or examples, not by your agent.Once your own tools are on the screen, each run opens with what is new since you last looked. With more than one agent running, each call also names which one made it.
--limit N and --all set how much you see. --json prints the same data for a program.
--share writes agentx-audit.json: the same data as --json, with your ledger's file path and the trace ids taken out. It prints what is in the file and what is not, so you can check before you send it.
Calls are recorded whether blocking is on or off. Only wrapped tools appear here, so this is not all your agent did.
In CI, --require-calls exits 2 when the ledger holds no calls, so a job where the agent never ran cannot pass as a clean audit. --fail-on-rule-match exits 3 when a recorded call matched a rule you adopted, and names the rule.
agentx audit --require-calls --fail-on-rule-match # for CI: exit 2 on an empty record, 3 on a rule matchThe whole GitHub Actions workflow. Copy it into .github/workflows/, point the "Run the agent" step at your own entry point, and the install line at your own dependency file:
name: agent audit
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install "agentx-security-sdk>=0.5.1" -r requirements.txt
# Your agent, its tools wrapped with @agentx_protect. It writes .agentx.db into whatever
# directory it runs in, and `audit` below reads the one in the same directory.
- name: Run the agent
run: python ./scripts/run_agent.py
# Exits 2 if the record holds no calls, 3 if a call matched one of your rules, so a run
# where the agent silently did nothing, or did the thing you wrote a rule against, cannot
# pass as a clean audit.
- name: What did the agent do
run: agentx audit --require-calls --fail-on-rule-match
# The same data for a program, kept as a build artifact. The step above already decided
# the job, so this one must not fail it a second time, and must not hide its own failure
# either. continue-on-error marks the step red and leaves the verdict to the step above.
- name: Keep the record
if: always()
continue-on-error: true
run: agentx audit --json > agentx-audit.json
# Without this the file is written into the runner and thrown away with it.
- uses: actions/upload-artifact@v4
if: always()
with:
name: agentx-audit
path: agentx-audit.json
Put it on your agent
04Wrap a tool, then choose how it runs
One decorator on the tool function you want vetted. This is the only code change either choice below needs.
from agentx_sdk import agentx_protect
@agentx_protect(agent_id="crm_worker")
def run_sql(query: str, db=None):
...Want your app to behave exactly as it does today? Watch and record tool calls with 4A. To record and block dangerous calls, go with 4B.
Nothing is blocked. Your agent behaves exactly as it does today. This is what a fresh install does, with nothing to set. Every call is still screened and written down, so read it back at step 03.
To block one dangerous tool while the rest keep watching, put posture="enforce" in the decorator. It stays until you delete that argument, and it beats the shell setting either way.
# nothing to set, watching is already on:
python your_agent.pyThe dangerous call never runs. It comes back carrying the coaching your agent retries on, so the run finishes instead of failing. This is the step you take once the catches look right to you. A blocked call comes back as a value, not an error. Check it with is_block() below, or your code will use the block object as if it were your tool's return value.
AGENTX_POSTURE=enforce python your_agent.py # mac/linux$env:AGENTX_POSTURE="enforce"; python your_agent.py # PowerShellA blocked call returns an AgentXBlock (strictly-typed tools raise AgentXSecurityBlock instead). Check it with is_block(), feed its .challenge back to your LLM to revise the action, then retry, threading receipt_id so the recovery is tied to the original incident.
from agentx_sdk import agentx_protect, is_block
@agentx_protect(agent_id="crm_worker", posture="enforce")
def run_sql(query: str, db=None):
return db.execute(query)
# Call the tool, then check the result before you trust it:
out = run_sql(query=agent_query, db=session)
if is_block(out):
# out.challenge says what was unsafe and how to fix it. Hand it to your
# LLM to revise, then call the SAME tool again, passing receipt_id so the
# retry is tied to the original block.
revised_query = your_llm(out.challenge)
out = run_sql(query=revised_query, db=session, receipt_id=out.receipt_id)
# out is now the real return value of your tool, safely.out.policy names the policy that fired; out.safe_path is the preferred alternative when a policy names one (else None). Doing this with your own LLM is the manual version of Recover; the gateway automates it.
Put the statement in an argument named for it (query, sql, command, path, url). Text arguments such as notes or body are never read as SQL or shell, so a ticket note that happens to say delete from is not a block.
02Handle a block
Nothing to write. With the enforce posture set (the one line further down this step), when the floor blocks a tools/call the proxy returns it to the agent as a coaching tool error, and the agent reads the guidance and self-corrects on its next turn. The run keeps going and the dangerous call never reaches the server. Watching, which is the default, the same call is recorded and forwarded.
To watch it happen before you wire your own servers, run the demo. It drives the same proxy your MCP client spawns, against a bundled stub server, and shows a DROP TABLE blocked with coaching and a scoped SELECT allowed through:
uvx agentx-mcp --demo # no key, no gateway, no Node, no checkoutThat coaching is in-band and keyless, and the demo pins the enforce posture to show it. Gateway-backed Recover over MCP (richer, model-coached self-heal) is on the roadmap; today the agentx-mcp proxy is your keyless screen, and your protection once you set the posture below.
Claude Code? It writes the entry for you; the command is the same, our proxy first and your server after it:
claude mcp add filesystem -- uvx agentx-mcp npx -y @modelcontextprotocol/server-filesystem /dataTrying it on servers you already use? Every wrapped server records its calls and blocks none of them, so nothing you add can break a server that already works. To make ONE server block, add this beside args in that server's block, with a comma between them, and repeat it per server you want enforcing:
"env": { "AGENTX_POSTURE": "enforce" }Remove the env line to go back to watching. Every server you did not edit is watching already.
A tool's text arguments (a note, a message, a title) are never read as SQL or shell. The shield reads statements only in arguments named for them (query, command, path, url) or declared so by the server's own schema.
03See what it recorded
This screen lists every wrapped tool call: which tool, how many times, and what each call touched. It reads the servers you wrapped in step 01. The demo is not on it: uvx agentx-mcp --demo runs in a temporary directory of its own and writes nothing here.
uvx agentx-mcp --audit # grouped by toolTOOL CALLS SURFACE ARGUMENTS
-----------------------------------------------------------------------
fetch_invoice_pdf 1 HTTP url
issue_refund 1 - amount, currency +2 more
largest amount passed: >=1,000
run_sql 1 DB db_session, query
2 calls tripped a policy.
1 was stopped while blocking was on; 1 ran because audit was on.--calls gives one row per call, newest first, with the time. Each row ends with what became of the call: ran, stopped, ran, flagged (it tripped a policy and was let through), or retried (it was stopped, and the agent then got there another way).
uvx agentx-mcp --audit --calls # one row per call, newest firstTIME TOOL STATUS SURFACE ARGUMENTS
2026-08-31
18:00:30 query_orders_db* ran, flagged DB sql
18:00:30 write_ticket_note* ran FS contents, path
18:00:30 run_sql* retried DB db_session, query
* 3 rows above written by AgentX's own demo or examples, not by your agent.Once your own tools are on the screen, each run opens with what is new since you last looked. With more than one agent running, each call also names which one made it.
Once a server you wrapped has been called, this screen also says how many tools that server advertises, how many your agent called, and names the ones it never called. Nobody chooses what a third-party server exposes, so a tool your agent could reach and never used is worth a look.
--limit N and --all set how much you see. --json prints the same data for a program.
--share writes agentx-audit.json: the same data as --json, with your ledger's file path and the trace ids taken out. It prints what is in the file and what is not, so you can check before you send it.
Calls are recorded whether blocking is on or off. Only wrapped tools appear here, so this is not all your agent did.
In CI, --require-calls exits 2 when the ledger holds no calls, so a job where the agent never ran cannot pass as a clean audit.
uvx agentx-mcp --audit --require-calls # for CI: exit 2 on an empty record04Install agentx-mcp
The mcp.json in the door uses uvx, so it needs no install. For a persistent install, get the agentx-mcp command however suits your stack. All three run the same keyless Shield:
With pip or pipx, agentx-mcp lands on your PATH; then set command to agentx-mcp and drop the uvx arg.
Recover → Control
The gateway adds the full deterministic floor (AST parsing, the SSRF normalizer, the whole failure catalog) and tracks session state: budget ceilings and no-progress loop breaking that a single stateless call can't see. Its judge catches what keyword rules can't, writes the safe path when your policy carries none, and runs the coach-and-retry for you, so your agent finishes the task instead of dying on a 403. Needs the gateway and your own Gemini key. An install with an AGENTX_API_KEY set enforces by default: what Watch wrote down, Recover stops. Set AGENTX_POSTURE=audit any time you want it watching instead.
guide + continue
Get the gatewayConnect the cloud control plane for team human-in-the-loop and SOC approvals, shared dashboards, and a fleet-wide audit trail. Central oversight for when one machine isn't the whole story.
review + govern
Request AccessBoth run through the gateway, which any language can call over HTTP. There is no keyless rung here yet: that one needs a client we ship for your language, and we have not built yours.
05Watch → Recover → Control
pip install and one decorator on a Python tool, one line in your mcp.json to wrap any MCP server, or npm install @agentx-core/security-sdk and one line around a TypeScript tool. Python and MCP screen every call against the keyless floor (DROP TABLE, secret exfiltration, SSRF) and write down what they find; TypeScript writes down every call. Out of the box nothing is blocked. Set AGENTX_POSTURE=enforce (Python and MCP) and the same floor stops those calls and coaches your agent to self-correct. No LLM key, no signup, runs on your machine.
record + report
The gateway adds the full deterministic floor (AST parsing, the SSRF normalizer, the whole failure catalog) and tracks session state: budget ceilings and no-progress loop breaking that a single stateless call can't see. Its judge catches what keyword rules can't, writes the safe path when your policy carries none, and runs the coach-and-retry for you, so your agent finishes the task instead of dying on a 403. Needs the gateway and your own Gemini key. An install with an AGENTX_API_KEY set enforces by default: what Watch wrote down, Recover stops. Set AGENTX_POSTURE=audit any time you want it watching instead.
guide + continue
Get the gatewayConnect the cloud control plane for team human-in-the-loop and SOC approvals, shared dashboards, and a fleet-wide audit trail. Central oversight for when one machine isn't the whole story.
review + govern
Request Access05Watch → Recover → Control
One line in your mcp.json wraps any MCP server. It screens every tool call against the keyless floor (DROP TABLE, secret exfiltration, SSRF) and writes down what it finds, and out of the box it blocks nothing. Set AGENTX_POSTURE=enforce in that server's env and the same floor stops those calls and coaches your agent to self-correct. No LLM key, no signup, runs on your machine.
record + report
The gateway adds the full deterministic floor (AST parsing, the SSRF normalizer, the whole failure catalog) and tracks session state: budget ceilings and no-progress loop breaking that a single stateless call can't see. Its judge catches what keyword rules can't, writes the safe path when your policy carries none, and runs the coach-and-retry for you, so your agent finishes the task instead of dying on a 403. Needs the gateway and your own Gemini key. An install with an AGENTX_API_KEY set enforces by default: what Watch wrote down, Recover stops. Set AGENTX_POSTURE=audit any time you want it watching instead.
guide + continue
Get the gatewayConnect the cloud control plane for team human-in-the-loop and SOC approvals, shared dashboards, and a fleet-wide audit trail. Central oversight for when one machine isn't the whole story.
review + govern
Request AccessRecover and Control run through the gateway. The keyless Watch rung screens every call and writes down what it finds, and blocks nothing until you ask it to; Recover adds the full deterministic floor, session state (budget ceilings, no-progress loop breaking), and a judge that catches what keywords miss and runs the coach-and-retry for you, so it needs both the gateway and a Gemini key.
Watch is where MCP sits today, and the whole rung is yours with no key. Recover and Control run through the gateway, which does not cover MCP traffic yet, so those two apply to Python and TypeScript tools you write rather than to your MCP servers.
03Watch → Recover → Control
npm install, then one line around your tools: agentxWatchAll({ ... }). Every call is written down on your machine (tool and argument names, no values), and `npx @agentx-core/security-sdk audit` prints what your agent did. Nothing is blocked. No key, no signup.
record + report
The gateway adds the full deterministic floor (AST parsing, the SSRF normalizer, the whole failure catalog) and tracks session state: budget ceilings and no-progress loop breaking that a single stateless call can't see. Its judge catches what keyword rules can't, writes the safe path when your policy carries none, and runs the coach-and-retry for you, so your agent finishes the task instead of dying on a 403. Needs the gateway and your own Gemini key. An install with an AGENTX_API_KEY set enforces by default: what Watch wrote down, Recover stops. Set AGENTX_POSTURE=audit any time you want it watching instead.
guide + continue
Get the gatewayConnect the cloud control plane for team human-in-the-loop and SOC approvals, shared dashboards, and a fleet-wide audit trail. Central oversight for when one machine isn't the whole story.
review + govern
Request AccessRecover and Control run through the gateway. Watch records what your agent did and blocks nothing; enforcement starts at Recover, where the full deterministic floor and session state (budget ceilings, no-progress loop breaking) check each call, backed by a judge that catches what keyword rules miss.
04Run the gateway
The gateway adds the full deterministic floor (AST parsing, the SSRF normalizer, the whole failure catalog), coached recovery, and team review and approval before a risky action runs.
Worth knowing before you run this: it will not carry your MCP traffic. Run it for Python tools you write yourself, or skip it for now.
docker compose up -d # the full floor + Recover run hereStand it up now. Traffic starts flowing through it once we wire your guard, which is the next step.
Gateway protection over MCP is on the roadmap, so the keyless agentx-mcp proxy stays your protection for MCP servers today.
It is free and runs locally: get it self-serve. Questions or something broke? Join the Discord.
Where your guarded TypeScript tools send every call. The full deterministic floor (AST parsing, the SSRF normalizer, the whole failure catalog), coached recovery that finishes the run, and team review before a risky action runs.
The floor runs with no key at all. Your own Gemini key turns on Recover, which writes the safe path and runs the retry for you.
05Turn it on in your code
To stop a call, an in-process guard wraps each tool and checks it against the gateway before it runs. A blocked action never executes, and your agent gets the same coaching to recover that the Python decorator delivers. The guard needs a gateway key, so we set it up with you: say hello in our Discord.
07Close the loop
Every block your agents hit is a chance to teach the firewall. Run agentx review for a one-key pass over what got blocked: adopt the safe-path an agent already found, so AgentX coaches straight to it next time, or label a block right or wrong so the org's picture of what's a real threat sharpens. The protection compounds with use.
agentx review # one key each: adopt a safe-path, or label a blockChanged your mind about one of those answers? agentx review --undo is the way back, and it is the only one. It walks all three things you can decide here: an answer you gave for a whole policy, a detection rule you adopted, and a block you already judged. Adopting arms enforcement, so nothing you do here is a one-way door.
07Close the loop
Blocks and recoveries pile up as your agents run. Walk them with one key each: adopt a safe path an agent already found, or label a block right or wrong, so the protection gets better at your work.
uvx agentx-mcp --review # one key each: adopt a safe-path, or label a blockWorks whether or not you installed anything, and reads the store the proxy wrote, wherever your MCP host launched it from.
Changed your mind? uvx agentx-mcp --review --undo takes it back. Over this door that covers the answers you gave for a whole policy and the blocks you already judged. Adopted rules live in your project, in .agentx/rules.json, so removing one means naming that project in the server's env block first: AGENTX_PROJECT_DIR (on Claude Code, ${CLAUDE_PROJECT_DIR}). The screen prints the exact line to use.
Reference
Concepts
AgentX blocks a dangerous tool call, then hands your agent coaching so the run recovers. A few terms tie it together:
| Policy | A built-in floor: a trigger plus the coaching it delivers on a block. agentx policies lists them (e.g. "Mass Destructive Intent"). |
| Trigger | The deterministic detector that fires the block (a blocked intent or a structural signature). Runs keyless and offline, no LLM. |
| Coaching | What your agent receives on a block: what went wrong plus a safe path to try, so the run recovers. |
| Challenge | The coaching message your agent actually reads (the text of the coaching). |
| Safe path | The concrete alternative the coaching names (e.g. "add a WHERE clause, or snapshot first"). |
Rewrite any policy's coaching by name, keyless, with agentx customize. It applies on both the @agentx_protect decorator and the agentx-mcp proxy. The tier ladder above (Shield, Recover, Control) is orthogonal: it sets how much reasoning backs the block, from the keyless floor up to the gateway judge.
CLI reference
The agentx CLI ships with the Python SDK. Every command runs locally; agentx help prints this list.
| agentx demo | Ten-second offline 'aha': watch a DROP TABLE get blocked (no key, no gateway) |
| agentx audit | What your wrapped tools actually DID, grouped by tool; --calls for one row per call, --json for a program, --limit N or --all for how much, --share for a copy with your ledger path and trace ids stripped |
| agentx share | Turn your most recent block into a postable card + share draft |
| agentx status | Local protection stats + armed policies (live view needs the gateway) |
| agentx insights | Your wrapped tools' blocks, what came after, and the safe-paths learned, ready to adopt |
| agentx adopt | Adopt a learned safe-path so AgentX coaches your agents to it |
| agentx review | One-key pass over pending blocks: adopt a safe-path, or label a block right/wrong |
| agentx policies | List the customizable floor policies + your active coaching (--check to validate) |
| agentx customize | Customize a floor policy's coaching by name, keyless (--text or --edit) |
| agentx pull | Pull your org's policy config from the control plane |
| agentx push | Contribute abstract threat signals to shared immunity (opt-in) |
| agentx sync | pull + push |
Customize the coaching, keyless. A block hands your agent a coaching message (what went wrong plus a safe path), and that wording drives whether it recovers. Run agentx policies to see the built-in floor policies and the coaching each ships with, then override one by name with agentx customize "Mass Destructive Intent" --text "..." (or --edit to open your editor on the current text). It saves to ./.agentx/overrides.json and applies keyless on both the @agentx_protect decorator and the agentx-mcp proxy.