AXIOM

io.github.dragoscv由 GitHub 账号 dragoscv 发布v3.0.0更新于 Oct 24, 2026

Transactional write gate for coding agents: plan, canonical manifest, checks, two-phase apply.

发布方自己的服务:Axiom

概览

AI 生成的概览

AXIOM 是面向编码代理的事务性写入闸门:在允许的仓库根目录内规划、检查、预览并原子应用文件改动,并保留可回滚日志。

可以做什么
  • 规划与编译:校验计划、编译为规范化清单包、解析 .axm 源文件、比较清单差异、生成仓库快照。
  • 写入前检查:运行集合级检查与预应用配置,把耗时检查作为可轮询任务启动,并试运行查看差异。
  • 经闸门写入:先预览,确认清单摘要后再原子地批量写入或删除文件,带锁与备份。
  • 回滚与查看:回滚已应用的清单,读取状态、锁持有者与日志链,列出允许的根目录。
  • 校验信任:对照根目录信任文件中固定的 Ed25519 公钥验证清单包与签名。
适用场景
当代理需要修改真实仓库,而你希望每次写入都先预览、检查、再原子应用并保留回滚路径时使用。也适合需要签名清单、防回滚计数器或代理改动审计日志的团队。
运行要求
通过 npx 以 stdio 在本地运行(需 Node.js),启动时须给出一个或多个绝对 --root 目录,没有 cwd 或环境变量回退。另有可选的 Streamable HTTP 模式,非回环地址必须提供 bearer 令牌。签名由 CLI 使用 AXIOM_SIGNING_KEY 或密钥文件完成,不由服务器执行。外部 guard 需同时通过命令行开关和配置启用。
安装前请注意
核心工具会在配置的根目录内写入、删除和回滚文件,应尽量缩小根目录范围;应用时需回显清单摘要,目标已变动会被拒绝。启用后外部 guard 会执行本地进程。AXIOM_SIGNING_KEY 是 Ed25519 私钥,应避免交给服务器或提交进仓库。非回环 HTTP 暴露必须配置 bearer 令牌。

安装

在 SourceWeft 中

  1. 打开 控制台中的 AXIOM,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

@codai/axiom-mcp

MCP server (stdio or Streamable HTTP) and CLI for AXIOM v2 — the transactional write gate for coding agents: Plan → canonical ManifestBundle → set-level checks → hash-gated two-phase apply → journal. dist/cli.js (thin entry) + dist/cli-main.js (lazy-loaded engines; the MCP SDK v2 and zod are bundled into the mcp-lazy / http-lazy chunks); no runtime dependencies.

Install & run

sh
npx @codai/axiom-mcp mcp --root /abs/path/to/repo          # stdio MCP servernpx @codai/axiom-mcp mcp --root /abs/path/to/repo --http 127.0.0.1:3411   # Streamable HTTP at /mcpnpx @codai/axiom-mcp --help                                # CLI verbs

--root may repeat. Every tool root argument must equal or lie inside one of them; with exactly one root it is the default. There is no env-var or cwd fallback (ERR_ROOT_REQUIRED / ERR_ROOT_NOT_ALLOWED).

Protocol revisions — --wire 2026|2025|2026-only

Built on MCP TypeScript SDK v2 (@modelcontextprotocol/server 2.0.0). The server speaks the 2026-07-28 revision (no initialize, per-request _meta envelope, server/discover, ttlMs/cacheScope on list results) and the 2025-era revisions (initialize handshake, HTTP sessions) from the same entry — the SDK pins each stdio connection, or routes each HTTP request, to the era the client opened with. --wire 2026 (default) and --wire 2025 both serve both; --wire 2026-only refuses 2025 openings with the unsupported-protocol-version error. Clients on SDK v1 need no change. Details: docs/reference/mcp-tools.md.

VS Code — .vscode/mcp.json

json
{  "servers": {    "axiom": {      "type": "stdio",      "command": "npx",      "args": ["-y", "@codai/axiom-mcp", "mcp", "--root", "${workspaceFolder}"]    }  }}

Streamable HTTP — --http <host:port>

sh
axiom mcp --root /abs/repo --http 127.0.0.1:3411            # loopback, no token neededaxiom mcp --root /abs/repo --http 0                          # random port; URL logged at info levelAXIOM_HTTP_TOKEN=$(openssl rand -hex 32) axiom mcp --root /abs/repo --http 0.0.0.0:3411 --log-level info
  • Endpoints: POST /mcp (2026-07-28 requests are served statelessly; a 2025 initialize opens a session and returns Mcp-Session-Id, which every later 2025 request must send), GET /mcp (standalone SSE stream, one per 2025 session), DELETE /mcp (close the session), GET /health → { ok, name, version } (unauthenticated). Anything else is 404 JSON.
  • Loopback by default. A non-loopback host refuses to start unless a bearer token is present in the env var named by --http-token-env <NAME> (default AXIOM_HTTP_TOKEN, ≥ 16 chars). Clients send Authorization: Bearer <token>; the compare is constant-time. A token is optional on loopback.
  • DNS-rebinding protection is on for loopback binds (Host must be <host>:<port>, localhost:<port> or 127.0.0.1:<port>; otherwise 403). Request bodies over 4 MiB are 413.
  • 2025 sessions idle for 30 minutes are evicted; each session (and each 2026 request) has its own server instance from one factory (roots, discovered sub-roots and guard settings are shared). The transport lives in dist/http-lazy.js, loaded only with --http, and is plain node:http — no express/hono at runtime.
  • VS Code: { "type": "http", "url": "http://127.0.0.1:3411/mcp" }; add "headers": { "Authorization": "Bearer ${input:axiom-token}" } when a token is set.

Conformance: packages/conformance runs @modelcontextprotocol/conformance server against this transport in CI with an expected-failures baseline (packages/conformance/baseline.yml).

Claude Desktop — claude_desktop_config.json

json
{  "mcpServers": {    "axiom": { "command": "npx", "args": ["-y", "@codai/axiom-mcp", "mcp", "--root", "/abs/path/to/repo"] }  }}

Tools

Toolsets (3.0, D-43)

axiom mcp serves the core toolset by default — the six tools an agent needs to write through the gate: axiom_write, axiom_status, axiom_rollback, axiom_check, axiom_apply, axiom_apply_dry_run. Start the server with --tools full to also expose the plan / manifest / task plumbing below (every row not marked core). spec/tools.json and spec/codai-tools.json list every tool with "toolset": "core" | "full". Library users pass createServer(policy, { toolset: "full" }) / serverFactory(policy, { toolset }); parseToolset(value) maps the flag value (ERR_USAGE otherwise).

toolriskinputoutput
axiom_plan_validateREAD{ plan }{ ok, planDigest?, errors[] }
axiom_plan_compileACT{ plan, store?: inline|cas, root? }ManifestBundle (writes only under <root>/.axiom/ — CAS blobs and the stored manifest — when a root is given)
axiom_manifest_verifyREAD{ bundle, root? }{ ok, manifestDigest, canonical, signed, missing[], errors[], signatures?: { trustFile, keyids[], findings[], ok, code? } } — signatures only when root has .axiom/trust/keys.json; code is ERR_SIGNATURE_MISSING | ERR_SIGNATURE_INVALID when not ok
axiom_check coreREAD{ bundle, profile?, root? }CheckReport (verdict: pass|fail|error, preImage: verified|drifted|unverified)
axiom_check_startREAD{ bundle, profile?, root? }{ taskId, tool, status: "working", pollIntervalMs, ttlMs, elapsedMs } — same evaluation as axiom_check, returned immediately as a task so long guard.external suites (up to 15 min per guard) outlive the client's per-call timeout (S-406 / D-24)
axiom_task_getREAD{ taskId }descriptor + result: CheckReport once completed, or error: { code, message } once failed/cancelled; unknown/expired id → ERR_TASK_NOT_FOUND
axiom_task_cancelACT{ taskId }descriptor; kills every running guard tree, task ends cancelled with ERR_TASK_CANCELLED (idempotent on terminal tasks)
axiom_plan_beginACTPlan header: { name, intent, profile?, capabilities?, checks?, counter?, metadata? }{ sessionId, artifacts: 0, bytes: 0, limits: { maxArtifacts, maxBytes }, ttlMs } — opens a chunked plan session for Plans whose JSON would exceed the 4 MiB call cap
axiom_plan_addACT{ sessionId, artifacts[] } (each call ≤ 4 MiB)session descriptor; duplicate path across chunks → ERR_INVALID_PLAN, over budget (2000 artifacts / 64 MiB) or sealed → ERR_PLAN_SESSION_STATE
axiom_plan_sealACT{ sessionId, store?: inline|cas, root? }ManifestBundle — compiled by the same code path as axiom_plan_compile, so the digest equals a one-shot compile of the assembled Plan (property-tested); the session is consumed
axiom_apply_dry_run coreREAD{ bundle, root, profile? }ApplyResult{mode:"dry-run", diff}
axiom_apply coreSENSITIVE{ bundle, root, profile?, confirmDigest, mode?, branch?, commitMessage?, lockTimeoutMs? (0..600000), keepBackups? (0..1000) }ApplyResult — error.details carries { otherDigest, paths } for ERR_CONFLICT and { holder, waitedMs, queuePosition } for ERR_LOCKED
axiom_write coreSENSITIVE{ root, files[]: { path, content?, encoding?: utf8|base64, op?: write|delete, mode? }, intent?, profile?, confirmDigest?, lockTimeoutMs?, keepBackups? }One-tool write (2.5.0): without confirmDigest → status: "preview" (dry-run + checks, diff, manifestDigest, next; nothing outside .axiom/ touched); the same files + confirmDigest → atomic apply like axiom_apply (journal, one-step axiom_rollback). A target changed since the preview → ERR_CONFIRM_DIGEST_MISMATCH. Prefer it for multi-file or sensitive changes
axiom_rollback coreSENSITIVE{ root, manifestDigest }{ status:"rolled-back", phase, steps }
axiom_manifest_diffREAD{ a: bundle|"sha256:…", b }{ added[], removed[], changed[] }
axiom_axm_parseREAD{ source } (.axm text){ plan?, diagnostics: [{ severity, code, message, range: { start: {line, column}, end } }] }
axiom_roots_listREAD{}{ roots: [{ path, writable, hasGit }] }
axiom_status coreREAD{ root? }{ root, lock: { held, holder?: { pid, host?, digest?, since?, stale }, queue[], intents[] }, interrupted[], corrupt[], lastApplied?, chain: { ok, entries, head, firstBad?, missingJournals } } — same as axiom status --json; never takes the lock
axiom_repo_snapshotREAD{ 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 } } — sorted, no timestamps/absolute paths; .git/, .axiom/ always skipped; symlinks recorded, never followed (docs/guides/snapshot.md)

Every tool carries MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) and an outputSchema; structuredContent is the full result, content[0].text a small summary (digest, verdict, counts, first 20 findings). Errors come back as isError: true with { code, message, path? } from the closed ERROR_CODES enum — a handler never throws. spec/tools.json is generated from the same registry (pnpm build:spec) and guarded by a parity test. spec/codai-tools.json is the same registry in codai's packages/agent-core/spec/tools-v2.json entry shape ({ name, risk, toolset, description, parameters }) — see docs/integration/codai.md.

Resources: axiom://manifest/{sha}, axiom://report/{sha}, axiom://applied/{sha}, axiom://profile/{name}, axiom://schema/{Plan|Manifest|ManifestBundle|CheckReport|ApplyResult|Profile|Journal|RepoSnapshot}, axiom://emitters (template emitters loaded with --emitter <pkg> — empty by default since 3.0; install @codai/axiom-emitters-web next to the repo and pass --emitter @codai/axiom-emitters-web, see docs/guides/emitters.md), axiom://lock ({ roots: [{ root, held, holder?, queue[], intents[] }] } for every allowlisted root; read-only).

Trust model

  • Roots are realpath'd at startup, must be directories, and the set is frozen. Requested roots are realpath'd too (case-insensitive containment on Windows); anything outside is a hard error.
  • axiom_apply requires confirmDigest === bundle.manifestDigest — echo the digest you saw in dry-run. Pre-apply checks run against the profile (default default, or <root>/.axiom/profiles/<name>.json); a non-pass verdict aborts with ERR_CHECKS_FAILED before any write.
  • Payloads over 4 MiB are rejected up front (ERR_BUNDLE_TOO_LARGE).
  • Tasks and plan sessions live in the server process (shared by every connection/request the process serves; never on disk). A restart forgets them; finished tasks stay pollable for 10 min, idle sessions expire after 30 min; at most 8 tasks run concurrently (ERR_EBUSY beyond that). Stopping the server aborts every running task and kills its guard trees.
  • .axiom/lock makes apply single-writer per root; the journal makes it crash-safe and reversible.
  • stdout carries only JSON-RPC. Logs are JSON lines on stderr (--log-level error|warn|info|debug, default warn).
  • External guards (guard.external) are off unless the process is started with --allow-guards and the profile sets facts.allowGuards: true. Relative commands must live under <root>/scripts/; absolute ones must be listed exactly via --guard-allowlist <abs> (repeatable). Guards are spawned with an args array (never a shell), a scrubbed environment, a wall-clock timeout, and must print GuardOutput JSON — see docs/guides/checks.md.
  • Signed manifests (docs/guides/signing.md): a root can pin Ed25519 public keys in .axiom/trust/keys.json; a profile with manifest.requireSigned then refuses unsigned, tampered or untrusted bundles, and with antiRollback: true refuses any counter ≤ .axiom/trust/state.json#lastCounter. axiom_apply advances that state only on status: "applied". Private keys never enter the server: signing is axiom sign with AXIOM_SIGNING_KEY or --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 })

Exit codes: 0 ok · 1 verdict fail / apply failed / journal chain broken / keyless unavailable · 2 usage or error (doctor: 2 = a check failed). Non-mcp verbs print JSON to stdout (init, doctor, status, log, check, emitters: human lines unless --json).

ref sources ({ type: "ref", uri, digest }) are offline by default: a digest already in <root>/.axiom/cas resolves without network, anything else is ERR_NET_DISABLED. --allow-net fetches https: only (no redirects, 30 s timeout, 32 MiB cap), optionally restricted to --net-allow hosts (*.example.com wildcards), verifies the pinned digest and stores the blob in the CAS — a mismatch stores nothing (ERR_DIGEST_MISMATCH). apply never fetches. The MCP axiom_plan_compile tool has no network switch. See docs/reference/plan-format.md and docs/concepts/cas.md.

Hook mode — axiom gate --stdin

A PreToolUse hook for Claude Code, Copilot CLI and VS Code agent hooks. It reads one harness payload from stdin (both {tool_name, tool_input, cwd} and {toolName, toolArgs, cwd} casings; toolArgs may be a JSON string), extracts the write target(s) of Write|Edit|MultiEdit|NotebookEdit, create_file|replace_string_in_file|insert_edit_into_file|apply_patch|multi_replace_string_in_file|edit_notebook_file and generic write|edit, scans shell tools (Bash, run_in_terminal, …) for write primitives (>, >>, tee, rm, mv, cp, sed -i, git checkout|reset|clean, PowerShell Set-Content/Remove-Item, … — a heuristic, documented in docs/getting-started/hooks.md), and runs only the fast predicates: containment + RelPath rules (.., CON, NTFS ADS → ERR_CONTAINMENT / ERR_PATH_*), path.deny, path.allow, content.noSecrets and content.maxBytes on the new content when the payload carries it. Fail-closed (D-18): a non-answer is a deny.

outcomeexitstdoutstderr
allow / non-write, non-shell tool0——
deny0 (2 with --deny-exit 2)one object: hookSpecificOutput{…} (Claude) + flat permissionDecision/permissionDecisionReason (Copilot) + axiom{verdict, code, path, toolClass, standard:"owasp-acs/0.1"}AXIOM GATE DENY <code>: <reason> (<relpath>)
write tool with no recognised path keyas denydeny JSONAXIOM GATE DENY ERR_UNSUPPORTED_OP: …
malformed payload, stdin timeout (2 s), internal erroras deny (fail closed)deny JSONAXIOM GATE DENY ERR_INTERNAL: … (fail-closed; pass --fail-open to allow)
same, with --fail-open0—AXIOM GATE WARN: … — failing open (--fail-open)

A deny exits 0 since 2.4.1 (D-35): the npm axiom.ps1 shim on Windows rewrites 2 to 1, and VS Code treats 1 as a warning. Every JSON-aware harness honours the document on exit 0; use --deny-exit 2 for exit-code-only harnesses (Windsurf). Read-only tools are answered before the gate chunk loads. A target in a sibling worktree of the same repository (same git common dir) is judged against that worktree's root and gate profile instead of ERR_CONTAINMENT.

Root = payload cwd, walked up to the nearest .git / repository .axiom/ ancestor (never the home dir; --no-root-discovery disables), else --root, else the process cwd (the hook is the one place where cwd is acceptable: the harness spawns the hook in the project directory and owns that value). Relative targets stay relative to cwd. Profile = --profile <file> → <root>/.axiom/gate-profile.json → ~/.axiom/gate-profile.json → built-in { 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 } (strict). pii: true additionally scans for personal data (cnp, email, phoneRo, card) — off by default since S-414 (maintainer e-mails in pyproject.toml denied real edits; see docs/guides/checks.md).

gate is a separate lazy chunk (dist/gate-lazy.js, no MCP SDK): in-process p95 ≈ 5 ms per payload, end-to-end ≈ 150–200 ms including node startup; check-gate-latency guards p95 ≤ 250 ms. Wiring for each harness is in docs/getting-started/hooks.md.

来源:packages/mcp/README.md,提交 8ddce4c

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

10
  1. v3.0.0最新Oct 19, 2026
  2. v2.7.0Oct 19, 2026
  3. v2.6.1Oct 14, 2026
  4. v2.5.2Oct 14, 2026
  5. v2.5.0Oct 14, 2026
  6. v2.4.1Oct 14, 2026
  7. v2.4.0Sep 27, 2026
  8. v2.3.1Sep 27, 2026
  9. v2.3.0Sep 23, 2026
  10. v2.2.1Sep 21, 2026

评分

已满足适用检查项的 50%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分

其他 Axiom 集成