关于 AXIOM
AXIOM 是面向编码 Agent 的事务性写入管控工具,提供 MCP 服务和命令行界面。它通过计划、清单校验、哈希确认的两阶段应用及日志,控制代码库更改。
主要功能
- 01计划编译为规范清单
- 02写入前执行集合检查
- 03哈希门控的两阶段应用
- 04变更日志与回滚
- 05stdio 和 Streamable HTTP 传输
适用场景
- 01在应用前审查多文件代码更改
- 02检查代码库变更是否存在冲突
- 03追踪或回滚已应用的变更
MCP 相关
AXIOM 以 stdio 或 Streamable HTTP 运行 MCP 服务,向编码 Agent 暴露计划、检查、写入、应用、状态和回滚等工具,并可配置核心或完整工具集。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
18收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| plan | object | 是 | Plan 文档(apiVersion axiom.dev/v2、kind Plan) |
详细介绍
@codai/axiom-mcp
AXIOM v2 的 MCP 服务(stdio 或 Streamable HTTP)和 CLI——为编码 Agent 提供事务性写入关卡:
Plan → 规范化的 ManifestBundle → 集合级检查 → 哈希门控的两阶段 apply → 日志。
dist/cli.js(轻量入口)+ dist/cli-main.js(延迟加载引擎;MCP SDK v2 和 zod 打包在
mcp-lazy / http-lazy 分块中);无运行时依赖。
安装与运行
npx @codai/axiom-mcp mcp --root /abs/path/to/repo # stdio MCP server
npx @codai/axiom-mcp mcp --root /abs/path/to/repo --http 127.0.0.1:3411 # Streamable HTTP at /mcp
npx @codai/axiom-mcp --help # CLI verbs
--root 可以重复指定。每个工具的 root 参数都必须等于其中一个目录,或位于其中一个目录下;恰好指定一个
root 时,它就是默认值。不会回退到环境变量或 cwd(ERR_ROOT_REQUIRED / ERR_ROOT_NOT_ALLOWED)。
协议修订版本 — --wire 2026|2025|2026-only
基于 MCP TypeScript SDK v2(@modelcontextprotocol/server 2.0.0)构建。服务端支持
2026-07-28 修订版(无 initialize,每个请求都带 _meta 信封、server/discover、
列表结果包含 ttlMs/cacheScope),以及 2025 年时期的修订版(initialize 握手、
HTTP 会话),并通过同一入口提供服务——SDK 会将每个 stdio 连接固定到客户端打开连接时使用的时期,
或将每个 HTTP 请求路由到对应时期。--wire 2026(默认值)和 --wire 2025 都支持这两个时期;
--wire 2026-only 会拒绝使用 2025 协议打开连接,并返回“不支持的协议版本”错误。使用 SDK v1 的客户端
无需更改。详情:docs/reference/mcp-tools.md。
VS Code — .vscode/mcp.json
{
"servers": {
"axiom": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@codai/axiom-mcp", "mcp", "--root", "${workspaceFolder}"]
}
}
}
Streamable HTTP — --http <host:port>
axiom mcp --root /abs/repo --http 127.0.0.1:3411 # loopback, no token needed
axiom mcp --root /abs/repo --http 0 # random port; URL logged at info level
AXIOM_HTTP_TOKEN=$(openssl rand -hex 32) axiom mcp --root /abs/repo --http 0.0.0.0:3411 --log-level info
- 端点:
POST /mcp(2026-07-28 请求以无状态方式提供服务;2025initialize会打开一个 会话并返回Mcp-Session-Id,之后每个 2025 请求都必须携带该 ID)、GET /mcp(独立 SSE 流,每个 2025 会话一个)、DELETE /mcp(关闭会话)、GET /health→{ ok, name, version }(无需身份验证)。其他请求均返回404JSON。 - 默认绑定到环回地址。 除非环境变量(由
--http-token-env <NAME>指定,默认AXIOM_HTTP_TOKEN)中存在 Bearer 令牌(长度 ≥ 16 个字符),否则非环回主机无法启动。客户端发送Authorization: Bearer <token>;令牌比较采用恒定时间算法。环回地址上无需令牌。 - 对环回绑定启用 DNS 重绑定防护(
Host必须为<host>:<port>、localhost:<port>或127.0.0.1:<port>;否则返回403)。超过 4 MiB 的请求正文返回413。 - 闲置 30 分钟的 2025 会话会被逐出;每个会话(以及每个 2026 请求)都通过同一个工厂创建独立的
服务端实例(roots、发现的子 roots 和防护设置共享)。传输层位于
dist/http-lazy.js,仅在使用--http时加载,并基于原生node:http——运行时不依赖 express/hono。 - VS Code:
{ "type": "http", "url": "http://127.0.0.1:3411/mcp" };设置令牌时添加"headers": { "Authorization": "Bearer ${input:axiom-token}" }。
符合性测试:packages/conformance 会在 CI 中使用预期失败基线(packages/conformance/baseline.yml)
通过此传输运行 @modelcontextprotocol/conformance server。
Claude Desktop — claude_desktop_config.json
{
"mcpServers": {
"axiom": { "command": "npx", "args": ["-y", "@codai/axiom-mcp", "mcp", "--root", "/abs/path/to/repo"] }
}
}
工具
工具集(3.0,D-43)
axiom mcp 默认提供核心工具集——Agent 通过关卡写入所需的六个工具:axiom_write、
axiom_status、axiom_rollback、axiom_check、axiom_apply、axiom_apply_dry_run。使用
--tools full 启动服务端,还会公开下方的计划 / 清单 / 任务相关工具(未标记为核心的每一行)。
spec/tools.json 和 spec/codai-tools.json 列出所有工具,并标注 "toolset": "core" | "full"。
库用户传入 createServer(policy, { toolset: "full" }) / serverFactory(policy, { toolset });
parseToolset(value) 会映射标志值(否则返回 ERR_USAGE)。
| 工具 | 风险 | 输入 | 输出 |
|---|---|---|---|
axiom_plan_validate | READ | { plan } | { ok, planDigest?, errors[] } |
axiom_plan_compile | ACT | { plan, store?: inline|cas, root? } | ManifestBundle(指定 root 时,仅写入 <root>/.axiom/ 下的内容——CAS blob 和存储的清单) |
axiom_manifest_verify | READ | { bundle, root? } | { ok, manifestDigest, canonical, signed, missing[], errors[], signatures?: { trustFile, keyids[], findings[], ok, code? } }——仅当 root 包含 .axiom/trust/keys.json 时才返回 signatures;当 ok 为 false 时,code 为 ERR_SIGNATURE_MISSING | ERR_SIGNATURE_INVALID |
axiom_check 核心 | READ | { bundle, profile?, root? } | CheckReport(verdict: pass|fail|error,preImage: verified|drifted|unverified) |
axiom_check_start | READ | { bundle, profile?, root? } | { taskId, tool, status: "working", pollIntervalMs, ttlMs, elapsedMs }——与 axiom_check 执行相同的评估,并立即作为 任务 返回,因此耗时较长的 guard.external 测试套件(每个 guard 最长 15 分钟)不会受客户端单次调用超时限制(S-406 / D-24) |
axiom_task_get | READ | { taskId } | 任务完成后返回描述符和 result: CheckReport;任务失败或取消后返回描述符和 error: { code, message };ID 未知或已过期时 → ERR_TASK_NOT_FOUND |
axiom_task_cancel | ACT | { taskId } | 描述符;终止所有正在运行的 guard 进程树,任务以 cancelled 状态结束,并返回 ERR_TASK_CANCELLED(对已结束的任务重复调用不会产生影响) |
axiom_plan_begin | ACT | 计划头部:{ name, intent, profile?, capabilities?, checks?, counter?, metadata? } | { sessionId, artifacts: 0, bytes: 0, limits: { maxArtifacts, maxBytes }, ttlMs }——为 JSON 大小会超过 4 MiB 调用上限的计划开启 分块计划会话 |
axiom_plan_add | ACT | { sessionId, artifacts[] }(每次调用 ≤ 4 MiB) | 会话描述符;跨块路径重复 → ERR_INVALID_PLAN;超出预算(2000 个工件 / 64 MiB)或会话已封存 → ERR_PLAN_SESSION_STATE |
axiom_plan_seal | ACT | { sessionId, store?: inline|cas, root? } | ManifestBundle——使用与 axiom_plan_compile 相同的代码路径编译,因此摘要与一次性编译组装后的计划相同(已通过属性测试);会话随即销毁 |
axiom_apply_dry_run 核心 | READ | { bundle, root, profile? } | ApplyResult{mode:"dry-run", diff} |
axiom_apply 核心 | SENSITIVE | { bundle, root, profile?, confirmDigest, mode?, branch?, commitMessage?, lockTimeoutMs? (0..600000), keepBackups? (0..1000) } | ApplyResult——error.details 在 ERR_CONFLICT 时包含 { otherDigest, paths },在 ERR_LOCKED 时包含 { holder, waitedMs, queuePosition } |
axiom_write 核心 | SENSITIVE | { root, files[]: { path, content?, encoding?: utf8|base64, op?: write|delete, mode? }, intent?, profile?, confirmDigest?, lockTimeoutMs?, keepBackups? } | 单工具写入(2.5.0):不提供 confirmDigest → status: "preview"(试运行 + 检查、diff、manifestDigest、next;不会触及 .axiom/ 之外的内容);同一组文件 + confirmDigest → 像 axiom_apply 一样原子应用(日志、单步 axiom_rollback)。预览后目标已更改 → ERR_CONFIRM_DIGEST_MISMATCH。多文件或敏感更改优先使用此工具 |
axiom_rollback 核心 | SENSITIVE | { root, manifestDigest } | { status:"rolled-back", phase, steps } |
axiom_manifest_diff | READ | { a: bundle|"sha256:…", b } | { added[], removed[], changed[] } |
axiom_axm_parse | READ | { source }(.axm 文本) | { plan?, diagnostics: [{ severity, code, message, range: { start: {line, column}, end } }] } |
axiom_roots_list | READ | {} | { roots: [{ path, writable, hasGit }] } |
axiom_status 核心 | READ | { root? } | { root, lock: { held, holder?: { pid, host?, digest?, since?, stale }, queue[], intents[] }, interrupted[], corrupt[], lastApplied?, chain: { ok, entries, head, firstBad?, missingJournals } }——与 axiom status --json 相同;从不获取锁 |
axiom_repo_snapshot | READ | { root?, include?[], exclude?[], maxFiles? (20000, cap 50000), maxBytes? (64 MiB), respectGitignore? (true), withContentDigest? (true) } | RepoSnapshot { snapshotDigest, body: { files: [{ path, bytes, sha256?, mode, kind }], truncated, counts } }——已排序,不含时间戳或绝对路径;始终跳过 .git/、.axiom/;记录符号链接,但绝不跟随(docs/guides/snapshot.md) |
每个工具都带有 MCP annotations(readOnlyHint、destructiveHint、idempotentHint、openWorldHint) | |||
和一个 outputSchema;structuredContent 是完整结果,content[0].text 是简短摘要(摘要、判定、计数、前 20 条发现)。错误以 isError: true 和 { code, message, path? } 的形式返回,错误代码来自封闭的 ERROR_CODES 枚举——处理程序不会抛出异常。spec/tools.json 由同一注册表生成(pnpm build:spec),并由一致性测试校验。spec/codai-tools.json 使用 codai 的 packages/agent-core/spec/tools-v2.json 条目格式 { name, risk, toolset, description, parameters },同样来自该注册表——参见 docs/integration/codai.md。 |
资源:axiom://manifest/{sha}、axiom://report/{sha}、axiom://applied/{sha}、
axiom://profile/{name}、axiom://schema/{Plan|Manifest|ManifestBundle|CheckReport|ApplyResult|Profile|Journal|RepoSnapshot}、
axiom://emitters(通过 --emitter <pkg> 加载的模板生成器——默认为空,自 3.0 起如此;在仓库旁安装
@codai/axiom-emitters-web 并传入 --emitter @codai/axiom-emitters-web,参见 docs/guides/emitters.md),
axiom://lock(为每个允许列表中的根目录提供 { roots: [{ root, held, holder?, queue[], intents[] }] };只读)。
信任模型
- 启动时会对根目录执行 realpath 解析;根目录必须是目录,且目录集合会被冻结。请求的根目录也会执行 realpath 解析(Windows 上进行大小写不敏感的包含检查);任何位于根目录之外的路径都会导致硬错误。
axiom_apply要求confirmDigest === bundle.manifestDigest——回传你在 dry-run 中看到的摘要。 应用前检查会依据配置文件运行(默认是default,或<root>/.axiom/profiles/<name>.json); 若判定不是pass,则会在任何写入发生前以ERR_CHECKS_FAILED中止。- 超过 4 MiB 的负载会立即被拒绝(
ERR_BUNDLE_TOO_LARGE)。 - 任务和计划会话存放在服务的进程中(由该进程服务的所有连接/请求共享;绝不会写入磁盘)。重启后会丢失;
已完成的任务可轮询 10 分钟,空闲会话在 30 分钟后过期;并发运行的任务最多为 8 个(超出时返回
ERR_EBUSY)。停止 服务会中止所有正在运行的任务,并终止其守护进程树。 .axiom/lock确保每个根目录上同时只有一个写入操作;日志记录机制确保操作可安全应对崩溃并可逆。- 标准输出仅承载 JSON-RPC。日志以 JSON 行格式写入标准错误(
--log-level error|warn|info|debug,默认warn)。 - 除非进程以
--allow-guards启动,且配置文件设置了facts.allowGuards: true,否则外部守护程序(guard.external)默认关闭。相对命令必须位于<root>/scripts/下; 绝对命令必须通过--guard-allowlist <abs>明确列出(可重复指定)。守护程序通过参数数组启动(绝不使用 shell),使用经过清理的环境变量和墙钟超时,并且必须输出GuardOutputJSON——参见docs/guides/checks.md。 - 签名清单(
docs/guides/signing.md):根目录可在.axiom/trust/keys.json中固定 Ed25519 公钥;若配置文件设置了manifest.requireSigned,则会拒绝未签名、遭篡改或 不受信任的捆绑包;若设置了antiRollback: true,则会拒绝任何counter ≤ .axiom/trust/state.json#lastCounter。 只有当status: "applied"时,axiom_apply才会更新该状态。私钥绝不会进入服务: 签名通过axiom sign配合AXIOM_SIGNING_KEY或--key-file执行。
CLI
axiom mcp [--root <abs>]... [--allow-guards] [--guard-allowlist <abs>]... [--log-level warn]
[--http <host:port>] [--http-token-env AXIOM_HTTP_TOKEN] [--require-human]
axiom init [--root .] [--harness auto|copilot|claude|codex|vscode|cursor|windsurf|gemini|junie|cline] [--daemon]
[--profile-name <name>] [--force] [--upgrade] [--managed --out <dir>] [--json]
(.vscode/mcp.json + Pre/PostToolUse hooks + .axiom/profiles/<name>.json + .axiom/gate-profile.json + .gitignore; idempotent)
axiom doctor [--root .] [--json] (exit 0 = no failing check, 2 = at least one fail; warnings exit 0)
axiom stats [--root .] [--since 7d] [--json] (gate decisions, p50/p95, per harness; silent-gate alarms)
axiom undo --session <agent> [--root .] [--dry-run] [--force] [--since <iso>] (restore one session's writes; exit 1 = conflicts)
axiom import-guard <guard.ps1> [-o profile.json] (PowerShell guard tables → gate profile "commands")
axiom status [--root .] [--json] (lock holder/queue/intents, interrupted journals, last applied, chain)
axiom log [--root .] [--limit 20] [--json] (journal chain, newest first)
axiom compile <plan.json|plan.yaml|plan.axm> [-o out.json] [--store cas --root .] [--allow-net [--net-allow host[,host]]] [--allow-file]
axiom verify <bundle.json> [--root .] (--root: also verify signatures against .axiom/trust/keys.json)
axiom verify --journal --root . (journal hash chain; broken → exit 1 + code ERR_JOURNAL_CHAIN)
axiom verify <bundle.json> --tree <root> [--pre] [--attest out.intoto.json] (tree matches manifest? docs/guides/verify-tree.md)
axiom check <bundle.json> --root . [--profile p] [--json | --format text|json|sarif] [--allow-guards] [--guard-allowlist <abs>]...
axiom apply <bundle.json> --root . [--dry-run] [--profile p] [--confirm <digest>] [--lock-timeout <ms>] [--keep-backups <n>]
[--pr [--branch b] [--message m]] [--allow-guards] [--guard-allowlist <abs>]...
axiom rollback <digest> --root .
axiom gc --root . [--dry-run] [--older-than 30d] [--keep all-manifests|journal] [--undo-ttl 7d] (CAS garbage collection; CLI only, no MCP tool)
axiom diff <a.json> <b.json>
axiom schema <Plan|Manifest|ManifestBundle|CheckReport|ApplyResult|Profile|Journal|RepoSnapshot>
axiom emitters [--json]
axiom keygen [--out <dir>] [--name <label>] (ed25519; private key → <dir>/axiom-signing-<id>.key 0600, public entry → stdout)
axiom sign <bundle.json> [--key-file <path>] [-o out.json] [--root-id <id>] (key from --key-file or $AXIOM_SIGNING_KEY; --root-id = root-bound envelope)
axiom sign <bundle.json> --keyless [--bound --root . | --root-id <id>] [-o out.json]
(Sigstore via ambient OIDC → bundle.keylessSignatures; no OIDC → exit 1 ERR_KEYLESS_UNAVAILABLE)
axiom trust add <pub.json> --root . | remove <keyid> --root . | list --root . | root-id [<id>|--clear] --root .
axiom gate --stdin [--post] [--format <harness>] [--root <dir>] [--profile <file>] [--fail-open] [--no-shell-scan] [--no-root-discovery]
[--track-reads] [--deny-exit 0|2] [--log-level warn]
axiom serve --hook --root <abs>... [--host 127.0.0.1] [--port 47861] [--token-env <NAME>] [--otel]
axiom migrate v1 <manifest.json> [-o plan.json] [--profile default] [--cas <root>] [--content <dir>] [--overwrite]
(v1 manifest → v2 Plan, lazy chunk; exit 1 = migrated with warnings — docs/guides/migrate.md)
axiom snapshot --root . [-o snap.json] [--include <glob>]... [--exclude <glob>]... [--max-files n] [--max-bytes n] [--no-gitignore] [--no-digest]
axiom snapshot-diff <a.json> <b.json> (RepoSnapshot → { added, removed, changed })
退出代码:0 成功 · 1 判定失败/应用失败/日志链断裂/无密钥时不可用 · 2 用法或错误
(doctor:2 = 检查失败)。非 mcp 动词会将 JSON 输出到 stdout(init、doctor、status、log、check、emitters:除非指定 --json,否则输出人类可读的行)。
ref 来源({ type: "ref", uri, digest })默认离线:已存在于
<root>/.axiom/cas 中的摘要无需联网即可解析,其他情况均为 ERR_NET_DISABLED。--allow-net
仅获取 https:(不跟随重定向,超时 30 秒,大小上限 32 MiB),可选通过
--net-allow 限制主机(*.example.com 通配符),验证固定的摘要并将 blob 存入
CAS——摘要不匹配时不会存储任何内容(ERR_DIGEST_MISMATCH)。apply 不会获取内容。MCP
axiom_plan_compile 工具没有网络开关。请参阅 docs/reference/plan-format.md
和 docs/concepts/cas.md。
Hook 模式 — axiom gate --stdin
适用于 Claude Code、Copilot CLI 和 VS Code Agent Hook 的 PreToolUse hook。它从标准输入读取一个 harness 负载(支持 {tool_name, tool_input, cwd} 和 {toolName, toolArgs, cwd} 两种大小写形式;toolArgs 可以是 JSON 字符串),提取 Write|Edit|MultiEdit|NotebookEdit、create_file|replace_string_in_file|insert_edit_into_file|apply_patch|multi_replace_string_in_file|edit_notebook_file 和通用 write|edit 的写入目标,并扫描 shell 工具(Bash、run_in_terminal 等)中的写入原语(>、>>、tee、rm、mv、cp、sed -i、git checkout|reset|clean、PowerShell Set-Content/Remove-Item 等——这是一种启发式检测,详见 docs/getting-started/hooks.md),仅运行快速谓词:包含性检查 + RelPath 规则(..、CON、NTFS ADS → ERR_CONTAINMENT / ERR_PATH_*)、path.deny、path.allow、content.noSecrets,以及在负载包含新内容时对其执行的 content.maxBytes 检查。失败时默认拒绝(D-18):无法给出答复即拒绝。
| 结果 | 退出码 | stdout | stderr |
|---|---|---|---|
| 允许 / 非写入、非 shell 工具 | 0 | — | — |
| 拒绝 | 0(使用 --deny-exit 2 时为 2) | 单个对象:hookSpecificOutput{…}(Claude)+ 扁平的 permissionDecision/permissionDecisionReason(Copilot)+ axiom{verdict, code, path, toolClass, standard:"owasp-acs/0.1"} | AXIOM GATE DENY <code>: <reason> (<relpath>) |
| 写入工具没有可识别的路径键 | 与拒绝相同 | 拒绝 JSON | AXIOM GATE DENY ERR_UNSUPPORTED_OP: … |
| 负载格式错误、标准输入超时(2 s)、内部错误 | 与拒绝相同(失败时默认拒绝) | 拒绝 JSON | AXIOM GATE DENY ERR_INTERNAL: … (fail-closed; pass --fail-open to allow) |
同上,使用 --fail-open | 0 | — | AXIOM GATE WARN: … — failing open (--fail-open) |
自 2.4.1 起,拒绝时退出码为 0(D-35):Windows 上的 npm axiom.ps1 shim 会将 2 改写为 1,而 VS Code 会将 1 视为警告。所有能解析 JSON 的 harness 都会遵循退出码为 0 时的文档内容;对于只检查退出码的 harness(Windsurf),请使用 --deny-exit 2。只读工具会在 gate 分块加载前得到响应。若目标位于同一仓库的相邻工作树中(共用相同的 git common dir),则会根据该工作树的根目录和 gate 配置进行判定,而不是返回 ERR_CONTAINMENT。
根目录 = 负载中的 cwd,向上遍历至最近的 .git / 仓库 .axiom/ 祖先目录(绝不会是主目录;--no-root-discovery 可禁用此行为);否则使用 --root,再否则使用进程的 cwd(hook 是唯一允许使用 cwd 的位置:harness 会在项目目录中启动 hook,并负责提供该值)。相对目标路径以 cwd 为基准。
配置 = --profile <file> → <root>/.axiom/gate-profile.json → ~/.axiom/gate-profile.json → 内置配置 { deny: [".git/**", ".axiom/**", "**/*.lock", "pnpm-lock.yaml", ".env", ".env.*", "**/node_modules/**"], noSecrets: true, pii: false }。
Schema:{ deny: string[], allow?: string[], noSecrets: boolean, pii: boolean, maxBytes?: number }(严格)。
pii: true 时还会扫描个人数据(cnp、email、phoneRo、card)——自 S-414 起默认关闭(维护者的电子邮件地址会导致 pyproject.toml 中的真实编辑被拒绝;参见 docs/guides/checks.md)。
gate 是单独的延迟加载分块(dist/gate-lazy.js,不含 MCP SDK):进程内每个负载的 p95 约为 5 ms,端到端耗时约为 150–200 ms(包括 Node 启动时间);check-gate-latency 会将 p95 限制在 ≤ 250 ms。
各 harness 的接入说明见 docs/getting-started/hooks.md。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。