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 整合