AM

augety121/mcp-state-twin

Developer tools
53 stars 0 forks Quality 65 Trend 43MIT

用于可复现 AI Agent 评测的确定性、可分叉、有状态 MCP 测试世界——不对生产环境产生副作用。Deterministic, forkable, stateful MCP test worlds for reproducible AI agent evaluation—without production side effects.

Overview

用于可复现 AI Agent 评测的确定性、可分叉、有状态 MCP 测试世界 从同一世界快照出发,让不同 Agent 安全地执行不同工具轨迹,再比较最终状态——不写入生产服务。 Fork the tool world, not production. snapshot → fork → act → assert → diff 当前实现究竟可以声明什么,以 Implementation Status、RFC、已接受 ADR、规范文档和可执行测试证据为准。Roadmap 中的能力不会被当作当前功能宣传。 离线项目入口已扩展为 project-check/run/inspect 和 campaign-check/run/inspect:先冻结并审阅全部输入,再执行质量门禁与独立世界绑定。两领域共 24 个任务、103 个质量 case、48 个 trial,附正向与回归 campaign。完整流程见项目指南,本分支验证与主线集成状态见交付台账。旧的独立离线命令仍可使用。 Agent Baseline Kit 候选增加 Task 约束的 MCP stdio、私有会话控制、独立 Inspect adapter、24 family/72 instances、冻结实验分片和四态基线判定。安装、接入及故障恢复见插件指南,测试、性能门槛及外部证据缺口见SPEC-0078 台账。它提供评测基础设施,不提供 AGI 认证。 快速开始 · 工作原理 · 当前状态 · TwinSpec · 安全边界 · 文档地图 Reproducible 从同一不可变 Snapshot 起步 Forkable 每次评测拥有隔离 Branch Stateful 跨工具调用保留真实状态演化 Comparable 用 Assertion 与 Canonical Diff 比较终态 MCP State Twin 是一个面向 AI Agent 评测的实验性开源环境层。它在 Model Context Protocol(MCP)工具背后提供**的测试世界,让多个评测运行从同一个不可变快照出发,各自执行不同但合法的工具调用轨迹,并在最后比较世界状态。

README

[!IMPORTANT] Development Preview · 0.1.0-dev · latest prerelease v0.1.0-alpha.1 · 非 production-ready。 当前实现究竟可以声明什么,以 Implementation Status、RFC、已接受 ADR、规范文档和可执行测试证据为准。Roadmap 中的能力不会被当作当前功能宣传。

离线项目入口已扩展为 project-check/run/inspect 和 campaign-check/run/inspect:先冻结并审阅全部输入,再执行质量门禁与独立世界绑定。两领域共 24 个任务、103 个质量 case、48 个 trial,附正向与回归 campaign。完整流程见项目指南,本分支验证与主线集成状态见交付台账。旧的独立离线命令仍可使用。

Agent Baseline Kit 候选增加 Task 约束的 MCP stdio、私有会话控制、独立 Inspect adapter、24 family/72 instances、冻结实验分片和四态基线判定。安装、接入及故障恢复见插件指南,测试、性能门槛及外部证据缺口见SPEC-0078 台账。它提供评测基础设施,不提供 AGI 认证。

快速开始 · 工作原理 · 当前状态 · TwinSpec · 安全边界 · 文档地图

MCP State Twin 是什么?

MCP State Twin 是一个面向 AI Agent 评测的实验性开源环境层。它在 Model Context Protocol(MCP)工具背后提供确定性、可分叉、有状态的测试世界,让多个评测运行从同一个不可变快照出发,各自执行不同但合法的工具调用轨迹,并在最后比较世界状态。

核心目标不是让模型“变得确定”,而是让模型所操作的外部世界可以被复现、隔离、分叉和比较。

维度 MCP State Twin 的做法
起点可复现 多次运行从同一个不可变 snapshot 开始
状态隔离 每个 fork 拥有独立的状态演化
工具接口 向 Agent 暴露 provider-neutral 的 MCP tool surface
评测方式 比较 terminal state、声明的不变量与 canonical diff,而非强制轨迹完全一致
环境确定性 固定环境身份 + 有序工具调用得到可重放的结构化结果与最终状态摘要
生产副作用 参考 Twin 在隔离模拟状态上执行,不写入生产服务
当前参考 Fidelity L1 · unverified · unbound
当前存储 SQLite + 版本化数据库身份 + 事务化状态转换

它不是什么

MCP State Twin 不是:

  • AGI 系统或模型运行时;
  • Agent framework、planner 或 orchestration framework;
  • memory system 或 RAG service;
  • 对真实上游服务的“完美复制”;
  • 对 ChatGPT、OpenAI API、Claude、Claude Code 或其他 host 兼容性的自动保证;
  • 可以直接暴露到公网的 production service。

“Twin”表示明确声明、可审查、由证据约束的行为模型,而不是无限制地声称与真实服务完全等价。


快速开始

环境要求

  • Go 1.26.x
  • Git

1. 获取代码并验证 TwinSpec

git clone https://github.com/augety121/MCP-State-Twin.git
cd MCP-State-Twin

go mod download

go run ./cmd/statetwin validate \
  --spec examples/issue-tracker/twin.yaml

2. 初始化世界并创建基础 Snapshot

go run ./cmd/statetwin init \
  --spec examples/issue-tracker/twin.yaml \
  --fixture examples/issue-tracker/state.json \
  --db demo.db \
  --branch main \
  --snapshot base

3. 从同一个 Snapshot 创建两个隔离 Fork

go run ./cmd/statetwin fork --db demo.db --snapshot base --branch run-a
go run ./cmd/statetwin fork --db demo.db --snapshot base --branch run-b

4. 让两个 Fork 走不同的合法轨迹

go run ./cmd/statetwin call \
  --spec examples/issue-tracker/twin.yaml \
  --db demo.db \
  --branch run-a \
  --tool create_issue \
  --input '{"owner":"octo","repository":"demo","title":"Fork A","body":"Created only in A"}'

go run ./cmd/statetwin call \
  --spec examples/issue-tracker/twin.yaml \
  --db demo.db \
  --branch run-b \
  --tool close_issue \
  --input '{"owner":"octo","repository":"demo","number":1}'

5. 比较最终世界

go run ./cmd/statetwin diff \
  --db demo.db \
  --before run-a \
  --after run-b

Diff 使用稳定的 JSON Pointer path。对象 key 中的 / 会按 JSON Pointer 规则转义,例如 octo/demo#1 会显示为 octo~1demo#1。

这段 Demo 在验证什么?

它不是在验证两个 Agent 必须走同一条路径,而是在验证:

  • 两个运行拥有相同起点;
  • 两个 branch 的状态修改彼此隔离;
  • 工具调用产生真实的跨调用状态变化;
  • 最终世界可以通过 canonical diff 稳定比较。

30 秒看懂工作原理

flowchart LR
    S0[(不可变 Snapshot S₀)]

    S0 --> A[Branch: run-a]
    S0 --> B[Branch: run-b]

    AA[Agent A] -->|MCP| UA["/mcp/run-a/"]
    AB[Agent B] -->|MCP| UB["/mcp/run-b/"]

    UA --> R[MCP State Twin Runtime]
    UB --> R

    R --> A
    R --> B

    H[Test Harness / Human] -->|Bearer token| C[私有 Control Plane]
    C -->|snapshot / fork / reset / diff| R

    A --> D[Canonical Terminal Diff]
    B --> D

    P[(Production Service)]
    R -. 参考 Twin 不写入 .-> P

一次典型评测可以理解为:

  1. 从固定 fixture 初始化一个世界;
  2. 创建不可变 snapshot;
  3. 从同一 snapshot fork 出多个隔离 branch;
  4. 不同 Agent / prompt / model 在各自 branch 上调用同一组 MCP 工具;
  5. 根据 terminal state、state assertion、invariant 与 canonical diff 评分;
  6. 不要求不同运行采取完全相同的工具调用路径。

[!NOTE] 确定的是环境,不是语言模型。 模型可以做出不同决策;MCP State Twin 的目标是让这些不同决策发生在可复现、可比较的世界里。


为什么需要它?

严肃的工具型 Agent 评测,仅靠“看起来合理的 JSON”通常不够。

例如,一个 issue-tracker Agent 可能先读取 issue、添加 comment、在模糊 timeout 后重试、再次读取 issue,然后只有在预期状态存在时才关闭它。每一次调用都会改变后续调用应该看到的世界。

常见方案解决的是相关但不同的问题:

方案 主要优势 用于 Agent 评测时的边界
Record/replay 重现已经捕获的调用路径 新模型可能采取从未录制过、但仍然合法的路径
静态 MCP mock 隔离客户端并返回可控数据 跨调用状态、约束、幂等和失败语义可能不完整
手工 benchmark sandbox 评估一组精心设计的任务 复用开发者自有 tool surface 并不是其核心抽象
Live 测试/生产服务 运行真实行为 存在副作用、限流、成本、共享状态污染与不可复现起点
MCP State Twin 在可分叉世界状态上执行显式状态转换 Fidelity 只覆盖已经建模并验证的行为

Record/replay 计划作为 L0 fidelity 模式存在;它与 State Twin 是互补关系,而不是必须被替代的方案。


当前状态

Development preview (0.1.0-dev) · 最新公开预览版为 v0.1.0-alpha.1 · 非 production-ready。

能力概览

能力 当前状态 边界
TwinSpec v1alpha1 严格解析与结构校验 ✅ 包含 hermetic JSON Schema 2020-12 编译
Spec / MCP surface / world state canonical digest ✅ SHA-256
Upstream binding admission ✅ surface 不匹配时 fail closed
SQLite 原子状态转换与审计 ✅ 带数据库身份与 schema version
World-store storage compatibility ✅ v1/v2/v3 → v4、tagged alpha v4 reopen、迁移 kill-point 恢复、foreign/future 零写入拒绝;仅限 ADR-0016 local profile
Immutable snapshot / fork / reset / diff ✅ branch 间状态隔离
Stateless Streamable HTTP MCP data plane ✅ 官方 Go SDK
独立 HTTP control plane ✅ bearer token;与数据面分离
Issue-tracker reference Twin ✅ 6 tools;synthetic;L1/unverified/unbound
Package-registry reference Twin ✅ publish/yank/install/advisory flows;synthetic;L1/unverified/unbound
Scenario v1alpha1 runner ✅ 有界 scripted scenario;不是 live model evaluation
Deterministic TwinBundle v1alpha1 ✅ 开发预览 严格清单、payload 语义校验、成员 SHA-256、路径/类型/大小限制、可重现 ZIP;未签名
Local scripted EvaluationEpisode ✅ 开发预览 单进程、单 Scenario、封闭生命周期与可摘要 evidence;不是 provider harness
Durable Episode Journal ✅ 开发预览 独立 SQLite schema v2;v1 fixture 前向迁移、迁移 kill-point 恢复、不可变 request、终态 Evidence 一致性校验
Remote Episode coordinator/workers ✅ 开发预览 bearer + TLS 边界、lease/heartbeat/fencing、并发 claim、bounded retry、cooperative cancellation;仅 synthetic TwinBundle
Exactly-once terminal acceptance ✅ 有界语义 一个 parent Episode 最多接受一个匹配的 Evidence;不承诺 provider/tool/外部副作用 exactly-once
HostCompatibilityReport admission ✅ 严格 schema、bounded evidence、credential/private-key/email pattern rejection;不等于 live provider 通过
OpenAI / Anthropic provider smoke harness 🧪 合同级已实现 OpenAI background/retrieve/cancel 与 Anthropic MCP connector mock contract tests;真实 live 报告尚未生成
Deterministic fault injection / virtual-clock advancement 🧪 部分实现 私有 clock;普通调用与 scheduled TwinSpec action 覆盖两个 fault transaction phases;其余 fault semantics 未实现
Deterministic entropy / world scheduler ✅ 有界语义 sha256-ctr-v1、私有 deterministic-queue-v2、真实 UTC 顺序、同刻准入、摘要绑定分页;支持一次性 runtime-bound 本地 TwinSpec action(每步最多 32、zero cascade),不支持 Agent/provider/外部任务
Versioned semantic resource governance 🧪 部分实现 statetwin limits、environment digest、fail-closed local budgets;OS/remote quotas 未实现
Conservative local execution governor ✅ soft boundary local-v2 默认 quiet:GOMAXPROCS=1、512 MiB Go heap 软目标、每个 listener 4 个 in-flight;不是 OS/RSS 硬配额,不覆盖 native/子进程
HTTP admission/backpressure ✅ local boundary data/control/coordinator 独立非排队 permit pool;过载返回 redacted 503 SERVER_BUSY;不是分布式限流或 DDoS 防护
Operational health/readiness ✅ local control plane 鉴权 /v1/health/live、/v1/health/ready;只检查进程与本地 SQLite ping,不暴露为 MCP tool
External-effect automatic retry / distributed HA ⏳ 外部 commit 不明确时停在 COMMIT_UNKNOWN;无多 coordinator、replication、manual reconciliation 或外部 exactly-once 声明
HostProfile / signed bundle ⏳ 不声明供应链真实性或 host compatibility
Recorder / cassette replay / trace redaction ⏳ 尚未实现
Differential validation / L2 promotion ⏳ 尚未完成
Data-plane auth / TLS / remote multi-tenancy ⏳ 当前仅适合本地 loopback 使用

完整证据与 partial boundaries 请看 Implementation Status。Roadmap 中的能力不会被描述成当前已实现功能。


确定性熵、未来信号与有界 world actions

TwinSpec 可以显式选择模拟专用熵流:

entropy:
  algorithm: sha256-ctr-v1
  seed: sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

effects:
  - op: entropy
    stream: request_id
    bytes: 16
    as: request_id

种子是公开 synthetic fixture,不是 secret。流计数器随 branch state 事务提交,并被 snapshot / fork / reset 捕获;失败 transition 不消耗计数。

测试 harness 还可以在独立 control plane 创建未来信号:

curl -H "Authorization: Bearer $STATETWIN_CONTROL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id":"issue-updated","branch":"main","dueAt":"2026-09-01T00:00:00Z","priority":10,"kind":"signal","payload":{"type":"issue.updated"}}' \
  http://127.0.0.1:8091/v1/scheduler/events

也可以调度一个已由当前 TwinSpec 建模的本地 hermetic tool。客户端不提供 specDigest;runtime 验证 schema 后注入并在执行时再次核对:

curl -H "Authorization: Bearer $STATETWIN_CONTROL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id":"close-later","branch":"main","dueAt":"2026-09-01T01:00:00Z","priority":10,"kind":"tool-call","action":{"tool":"close_issue","input":{"owner":"octo","repository":"demo","number":1}}}' \
  http://127.0.0.1:8091/v1/scheduler/events

普通 /v1/clock/advance 遇到 due action 会整次拒绝;只有 runtime-backed advance-next 能执行。成功、domain failure 与 TIMEOUT_AFTER_EFFECT 都会 留下带 callIndex、effectCommitted 和可选 fault identity 的终态记录。

推进虚拟时钟时,所有有界 due signals 与 clock/head/state digest 原子提交。 普通任意时钟推进保持 all-or-nothing;需要逐个 world instant 推进或恢复旧的 同刻超额队列时,先预览并显式执行 bounded step:

curl -H "Authorization: Bearer $STATETWIN_CONTROL_TOKEN" \
  "http://127.0.0.1:8091/v1/scheduler/next?branch=main"

curl -H "Authorization: Bearer $STATETWIN_CONTROL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"branch":"main","expectedHeadVersion":1}' \
  http://127.0.0.1:8091/v1/clock/advance-next

curl -H "Authorization: Bearer $STATETWIN_CONTROL_TOKEN" \
  "http://127.0.0.1:8091/v1/scheduler/events?branch=main&status=pending&limit=100"

分页 cursor 绑定 branch、filter 与 scheduler digest;队列在两页之间变化时 返回 conflict,客户端必须从第一页重新开始,而不是合并不一致结果。 Signal payload 永远不会自动执行。tool-call 也只执行已加载的本地 TwinSpec transition,不会调用 provider、进程、远程 MCP 或外部系统,更不会唤醒 Agent;control routes 不会出现在 MCP tools/list。完整语义见 SPEC-0026、 SPEC-0027 和 SPEC-0028 至 SPEC-0031,以及 SPEC-0032 至 SPEC-0034。


运行可复现 Scenario

仓库包含一个按状态断言评分的 bounded Scenario:

go run ./cmd/statetwin scenario \
  --spec examples/issue-tracker/twin.yaml \
  --fixture examples/issue-tracker/state.json \
  --scenario examples/issue-tracker/scenario-close-issue.yaml

如果出现非预期 error class 或 assertion failure,命令会以非 0 状态退出。JSON report 包含:

  • environment digest;
  • ordered tool trace;
  • initial / terminal state digest;
  • assertion evidence;
  • canonical state diff。

当前 runner 标识为 scripted-scenario。它不是 live Codex、OpenAI、Claude 或其他模型评测结果。

第二个独立 reference domain 是 package registry:

go run ./cmd/statetwin scenario \
  --spec examples/package-registry/twin.yaml \
  --fixture examples/package-registry/state.json \
  --scenario examples/package-registry/scenario-release-lifecycle.yaml

它覆盖 dependency release、yank、install 和 advisory 查询,并显式断言 yanked release 不能被安装。该环境同样是 synthetic、L1/unverified/unbound, 不是任何真实 package registry 的等价实现。

[!WARNING] Scenario report 会包含工具输入与结果。请只使用 synthetic fixture;不要提交含 credential、production trace 或 personal data 的报告。

构建可移植 TwinBundle 并运行本地 Episode

go run ./cmd/statetwin bundle build \
  --manifest examples/issue-tracker/bundle.yaml \
  --out issue-tracker.stb

go run ./cmd/statetwin bundle verify --bundle issue-tracker.stb

go run ./cmd/statetwin episode run \
  --bundle issue-tracker.stb \
  --id local-episode-001 \
  --out episode-evidence.json

go run ./cmd/statetwin episode run \
  --bundle issue-tracker.stb \
  --id durable-episode-001 \
  --journal episodes.db

go run ./cmd/statetwin episode inspect \
  --journal episodes.db \
  --id durable-episode-001

bundle verify 同时验证 archive 完整性和包内 TwinSpec、fixture、Scenario 的严格语义,但它不证明发布者身份或上游 fidelity。本地 Episode 只执行确定性的 scripted-scenario,不会调用 Codex、OpenAI、Claude 或任何远程模型。Journal 对完全相同的已完成请求返回原 Evidence;同 ID 不同请求会冲突。为避免覆盖证据,已存在的 --out 路径会 fail closed。

运行有 fencing 的远程 Episode worker

先提交一个只允许 hermetic 执行的任务:

go run ./cmd/statetwin episode submit \
  --bundle issue-tracker.stb \
  --id remote-episode-001 \
  --journal remote-episodes.db \
  --effect-profile hermetic \
  --max-attempts 3

设置 STATETWIN_COORDINATOR_TOKEN 后,在独立终端启动 coordinator 与 worker:

go run ./cmd/statetwin episode coordinator \
  --journal remote-episodes.db \
  --addr 127.0.0.1:8092

go run ./cmd/statetwin episode worker \
  --coordinator http://127.0.0.1:8092 \
  --id worker-001 \
  --once

go run ./cmd/statetwin episode task \
  --journal remote-episodes.db \
  --id remote-episode-001

worker 使用 lease、heartbeat 与 fencing token;过期的 hermetic attempt 可在预算内重新入队。external attempt 失联或报告不明确副作用时会进入 COMMIT_UNKNOWN,不会自动重试。Coordinator API 是独立 control plane,不会出现在 Agent 的 MCP tools/list 中。非 loopback listener 必须配置 --tls-cert 与 --tls-key。

运行 OpenAI / Anthropic live smoke(需外部凭据)

go run ./cmd/statetwin provider smoke \
  --provider openai \
  --model YOUR_EXACT_MODEL_ID \
  --runtime-revision YOUR_EXACT_GIT_SHA \
  --mcp-url https://synthetic-mcp.example/mcp/run-a/ \
  --prompt "Use the MCP tools to inspect synthetic issue 1." \
  --out openai-smoke.json \
  --synthetic-only

Provider key 只能通过 OPENAI_API_KEY 或 ANTHROPIC_API_KEY 注入;可选 MCP authorization 通过 STATETWIN_MCP_AUTHORIZATION 注入。报告只保留 digest、能力字段、工具发现/调用计数和终态,不保存 token、prompt、原始 response 或 provider error body。仓库另有手动触发的 provider-smoke workflow;它必须连接公网 HTTPS synthetic MCP endpoint。存在 harness 不等于 live 已通过,也不等于 ChatGPT/Claude 产品兼容。


运行 MCP Server

设置 Control Plane Token

Bash / zsh:

export STATETWIN_CONTROL_TOKEN='replace-with-a-local-secret'

PowerShell:

$env:STATETWIN_CONTROL_TOKEN = 'replace-with-a-local-secret'

启动 Runtime

go run ./cmd/statetwin serve \
  --spec examples/issue-tracker/twin.yaml \
  --fixture examples/issue-tracker/state.json \
  --db demo.db

默认 endpoint:

Plane Endpoint 可见操作
Agent data plane http://127.0.0.1:8090/mcp/main 仅已建模 business tools
Private control plane http://127.0.0.1:8091/v1 branch state、snapshot、fork、reset、diff、forward-only clock、bounded fault plans/events

Branch ID 是 MCP URL 的一部分,不是额外暴露给模型的 tool argument,因此不同 branch 可以保持相同的 tool input schema。

当前 fault preview 仅支持两个经过事务测试的 phase。以下请求必须发送到私有 control plane,并携带 Authorization: Bearer $STATETWIN_CONTROL_TOKEN:

{
  "id": "lose-close-response",
  "branch": "main",
  "tool": "close_issue",
  "phase": "after-commit-before-response",
  "errorClass": "TIMEOUT_AFTER_EFFECT",
  "message": "synthetic response loss",
  "repeatCount": 1,
  "expectedHeadVersion": 0
}

提交到 POST /v1/faults 后,匹配调用会先提交业务状态,再向 Agent 返回确定性错误。另一个受支持组合是 before-validation + RATE_LIMITED/TIMEOUT_BEFORE_EFFECT,它不会执行 transition callback。完整边界见 SPEC-0008。

[!WARNING] 当前 data plane 没有 authentication 或 TLS。 两个服务默认绑定 loopback,并应保持本地使用。Control token 只是开发期保护措施之一,不能让当前构建安全地暴露到 Internet。


Reference Twin

仓库内置 issue-tracker world,向 Agent 暴露 6 个业务工具:

Tool 作用
get_repository 读取 repository 状态
list_issues 列出 issues
get_issue 读取单个 issue
create_issue 创建 issue
add_comment 添加 comment
close_issue 关闭已有 open issue

Snapshot、fork、reset、diff、state inspection 以及未来 fault controls 不是 MCP tools,不会出现在 tools/list 中。测试控制能力属于独立 control plane,而不是暴露给被测 Agent 的隐藏工具。

[!CAUTION] 当前 reference Twin 使用 synthetic data,fidelity 为 L1,状态为 unverified,并且 unbound 于任何 upstream service。不要把它描述成 GitHub-equivalent environment。


TwinSpec

TwinSpec 是一个版本化、可审查、可执行的“工具世界契约”。一个工具不只是 function(args) -> JSON:

tool behavior = input contract
              + reads and preconditions
              + deterministic state effects
              + postconditions and global invariants
              + structured result or typed error
              + time and idempotency semantics

可执行 reference spec 片段:

apiVersion: statetwin.dev/v1alpha1
kind: Twin

metadata:
  name: issue-tracker
  upstream:
    protocol: mcp
    status: unbound
  fidelity:
    level: L1
    status: unverified

clock:
  mode: virtual
  initial: "2026-08-01T00:00:00Z"

state:
  entities:
    repository:
      key: [owner, name]
    issue:
      key: [repository, number]

tools:
  - name: close_issue
    description: Close an existing open issue in the isolated simulated repository.
    preconditions:
      - expr: "state.entities.issue[input.owner + '/' + input.repository + '#' + string(input.number)].state == 'open'"
        code: CONFLICT
        message: issue is already closed
    effects:
      - op: update
        entity: issue
        key: "input.owner + '/' + input.repository + '#' + string(input.number)"
        merge: true
        value: "{'state': 'closed', 'closedAt': clock}"

完整文件见 examples/issue-tracker/twin.yaml。

当前 Effect Operations

Operation Semantics
allocate 对命名 deterministic sequence 自增,并把结果绑定到 vars
insert 插入 keyed entity;已存在时 conflict
update replace 或 merge keyed entity;不存在时失败
delete 删除 keyed entity;不存在时失败

确定性契约

环境身份可以概念化为:

E = (runtime version,
     TwinSpec digest,
     snapshot digest,
     scenario seed,
     ordered tool calls)

execute(E) -> (ordered structured results, final state digest)

当前实现虚拟化 state allocation 以及 expression 可见的 time。确定性 replay test 会在两个 branch 上重放调用语料,并检查每次 transition 后以及最终状态的一致性。

“确定性”意味着什么

  • 相同受控环境 + 相同有序工具调用应得到可重放的环境结果;
  • 多个评测运行可以从同一个 immutable snapshot 起步;
  • branch state、terminal state 与 canonical digest 可以稳定比较。

“确定性”不意味着什么

  • 不意味着 LLM 会选择相同 tool;
  • 不意味着不同 model / prompt 会产生相同 trajectory;
  • 不意味着 L1 Twin 与真实 upstream 行为完全等价;
  • 不意味着未经 smoke test 的 host 已经兼容。

错误与事务语义

普通 tool transition 在单个 SQLite transaction 中完成:

load branch head
  -> validate input
  -> evaluate preconditions
  -> apply effects to an isolated working state
  -> evaluate query, postconditions, and global invariants
  -> commit state and audit record atomically

失败的 domain outcome 会保留之前的 state digest,同时仍追加 tool-call audit record。当前 canonical error classes:

  • INVALID_INPUT
  • PRECONDITION_FAILED
  • NOT_FOUND
  • CONFLICT
  • INVARIANT_VIOLATION
  • UNMODELED_BEHAVIOR
  • INTERNAL_TWIN_ERROR

Timeout-before-effect、timeout-after-effect 与 rate-limit 已作为有界、私有的 deterministic fault preview 实现;latency、partial-effect、crash/cancellation 与 eventual-consistency 仍未实现。

SQLite file 带 State Twin application ID 与显式 schema version。Snapshot 会持久化 storage schema version 并把它绑定到 snapshot ID;foreign database 与高于当前 runtime 的版本会被拒绝。测试覆盖 v1/v2/v3 forward migration、v0.1.0-alpha.1 schema-v4 fixture reopen,以及迁移事务两个 pre-commit 阶段发生进程退出后的 reopen/integrity recovery。该声明只适用于单进程、本地 SQLite;不包含 shared filesystem、multi-process writer、online backup、replication 或 HA。


Fidelity 等级

“Twin”不等于“完美副本”。Fidelity 必须被声明、限定并由证据支持。

Level 含义 预期用途
L0 — Cassette replay 匹配已录制 interaction exact-path smoke / regression tests
L1 — Stateful template 显式 entity + 经审查的基础 transition 开发与探索性 workflow tests
L2 — Contract-backed 人工审查规则、invariant、differential tests、upstream fingerprint 在已声明覆盖范围内做 CI / evaluation
L3 — Native/reference 共享或领域提供的 reference logic 高 fidelity domain simulation

自动生成或推断行为不能自行把 fidelity 晋级到 L2/L3。当前 reference Twin 是 L1 + unverified。


架构与安全边界

项目刻意分离两个 trust domain:

Agent Data Plane Simulation Control Plane
面向谁 被测 Agent test harness / human operator
默认地址 127.0.0.1:8090 127.0.0.1:8091
协议/用途 MCP business tools branch state / snapshot / fork / reset / diff / clock / scheduler / faults
Branch 选择 MCP URL control operation 参数
鉴权 当前没有 independent bearer token
是否向 Agent 暴露测试控制 否 不适用

关键原则:

  • Agent 只能看到 TwinSpec 声明的业务工具;
  • expected state、snapshot、fork、reset、diff 等评测控制不会伪装成 MCP tools;
  • prompt instruction 不是 authorization boundary;
  • privileged control operation 与状态修改在同一 transaction 中写入 control audit;
  • bearer token 与 HTTP header 不记录进该审计数据;
  • 当前构建应保持 loopback、本地、synthetic-fixture 使用方式。

MCP 与模型提供方

MCP State Twin 的核心集成对象是 MCP,不是某一家 model provider SDK。这是有意的:项目希望提供统一的 tool world,而不是声称不同模型一定会选择相同 tool 或遵循相同 trajectory。

当前自动化 integration test 使用官方 Go SDK 作为 server/client,并通过 stateless Streamable HTTP 通信。Linux CI 还运行固定版本的官方 MCP conformance framework v0.1.16,覆盖 initialize、ping、tools-list 与 JSON Schema 2020-12。该 framework 当前覆盖到 2025-11-25 协议版本;这并不证明设计基线 2026-07-28 的所有特性都已验证。

[!NOTE] 当前仓库尚未完成 live ChatGPT、OpenAI API、Claude 或 Claude Code smoke tests。因此 README 不提供“已验证”的 provider-specific 一键接入声明;host 只有在版本化 smoke run 产生 SPEC-0006 要求的证据后,才应被列为 verified。

statetwin compatibility validate --report 已实现严格 evidence admission;详见 Host Compatibility Evidence Procedure。验证报告格式不等于验证 provider。

报告须显式声明布尔值 redaction.secretsDetected: false,遗漏、null、no/off 均不能代替检查结果。报告和目标文件均限制为不超过 1 MiB 的普通文件,拒绝观察到的 symlink 和特殊文件;读取错误不回显本地路径。输入应来自可信、静止的本地目录。 报告时间与 --at 使用固定宽度 UTC 时间,点号后可有 1–9 位小数秒;超出纳秒精度 或非标准拼写直接拒绝,避免截断时间后误判有效期。

新增只读 compatibility assess --report --at :按明确时间判断声明是否 处于有效窗口,--require-fresh 可阻断过期、未来日期或非 verified 声明。工具面标识矛盾、 零成功断言和 YAML 转义的已知密钥模式会被拒绝。结果始终保留 publicationAllowed: false:时效合格不证明真实运行、当前配置匹配或产品兼容。 具体边界见 SPEC-0051 / SPEC-0052。

继续核对目标配置时,加 --target target.yaml --require-current:即使没过期,runtime、 host/model、协议、工具面、部署或预算不符也会阻断,并列出不一致字段。报告计数和预算 现在拒绝小数被截成整数或遗漏默认为零;有效期和来源验证仍分开。 见 目标核对指南。这是声明比对,不是实时部署认证。

设计参考:


CLI

statetwin --execution-mode quiet COMMAND
statetwin --execution-mode balanced --max-procs 2 --memory-limit-mib 768 --max-inflight 6 COMMAND
statetwin validate   validate structure, CEL, and print the spec digest
statetwin init       initialize a branch and optional immutable snapshot
statetwin call       execute one tool directly against a branch
statetwin state      inspect canonical branch state
statetwin snapshot   create an immutable logical snapshot
statetwin fork       create an isolated branch from a snapshot
statetwin diff       compare two branch states
statetwin scenario   execute a bounded scripted scenario and assertions
statetwin protocols   print pinned MCP wire-evidence profiles
statetwin limits      print the versioned resource profile and digest
statetwin execution-profile  print the applied operational execution policy
statetwin compatibility validate --report report.yaml
statetwin compatibility assess --report report.yaml --at  [--require-fresh]
statetwin compatibility assess --report report.yaml --target target.yaml --at  [--require-current]
statetwin bundle build --manifest bundle.yaml --out twin.stb
statetwin bundle verify --bundle twin.stb
statetwin episode run --bundle twin.stb --id episode-001 --out evidence.json
statetwin episode run --bundle twin.stb --id episode-001 --journal episodes.db
statetwin episode inspect --journal episodes.db --id episode-001
statetwin serve      run separate MCP data and HTTP control planes
statetwin version    print the development version

除 server log 与 fatal diagnostic 外,CLI output 为 structured JSON。

默认执行模式是 quiet,使用一个 Go 逻辑执行槽、512 MiB Go heap 软目标,并把每个 HTTP listener 的同时处理请求限制为 4。优先级为 root CLI 参数 > 对应 STATETWIN_* 环境变量 > mode 默认值。例如:

statetwin --execution-mode balanced --max-procs 2 --memory-limit-mib 768 --max-inflight 6 scenario --spec twin.yaml --fixture state.json --scenario scenario.yaml
statetwin execution-profile

环境变量为 STATETWIN_EXECUTION_MODE、STATETWIN_MAX_PROCS、STATETWIN_MEMORY_LIMIT_MIB 和 STATETWIN_MAX_INFLIGHT。

这是可移植的软治理,不是精确 CPU、RSS、温度、功耗、分布式公平性或 DDoS 保证;子进程和 future native threads 不在覆盖范围。完整边界见 SPEC-0022、SPEC-0023 和 SPEC-0024。

启动 serve 后,可在携带 control-plane bearer token 时访问:

GET /v1/health/live
GET /v1/health/ready

它们只存在于 private control plane,不进入 Agent MCP surface。ready 只表示本地 SQLite 在该时刻可 ping,不代表 provider、upstream 或整个场景可用;见 SPEC-0025。


测试与构建

gofmt -w .
go vet ./...
GOMAXPROCS=1 go test -p 1 ./...
GOMAXPROCS=1 go test -p 1 -race ./...
go build ./cmd/statetwin

PowerShell 安静验证可使用 $env:GOMAXPROCS='1'; go test -p 1 ./...。go test 是外部 Go 工具链,不受 statetwin 进程内 governor 控制,所以本地验证需要显式设置。

README 中的环境/CI 状态可能随开发变化。可复现证据应优先查看 CI、Implementation Status 与对应 executable tests,而不是依赖一段可能过期的宣传性文字。


文档地图

如果你是第一次阅读项目,建议按这个顺序:

  1. Project Map — 项目思路、边界、架构和 AGI-facing 定位;
  2. Implementation Status — 现在真正实现了什么;
  3. Documentation Governance — 哪些文档有权威、怎样把提案变成实现;
  4. RFC-0001 — 产品边界、核心不变量与整体架构;
  5. TwinSpec Core — TwinSpec v1alpha1 数据模型;
  6. Runtime Semantics — 确定性、事务、snapshot 与错误;
  7. Release Management — 版本、CI、tag、release evidence 与维护节奏;
  8. Roadmap — 下一阶段工作与退出条件。
  9. RFC-0003 — v0.2 本地评测平台提案与已接受子集;
  10. v0.2 Requirement Ledger — requirement、decision、实现状态与证据。

Specifications

RFC 和 accepted ADR 定义设计意图;Implementation Status 与 executable tests 定义当前 development build 实际上可以诚实声明什么。


首个稳定 Tagged Release 路线图

按照 RFC-0002 revision 2,v0.1 是 local hermetic core release。OpenAI-family、Anthropic-family 和产品级 live smoke 已移动到需要独立 remote-staging security profile 的 Phase 4 / v0.3,不再形成 v0.1 的循环依赖,也不会因为存在 mock harness 就被视为已验证。

Storage compatibility、P0 traceability、MCP wire tests 与 hermetic CI 已有可执行证据;正式 tag 仍要求这些 gate 在同一个待发布 commit上重新通过并完成文档/claim 审计。scheduled faults、upstream inspector、recorder、L2 differential validation、cloud hosting 与扩大 scenario corpus 仍是后续工作,不能偷换成当前能力。

Cloud hosting、registry、marketplace 与 automatic production mirroring 不是首个正式 release 的优先事项。


常见问题


贡献与安全

在修改 protocol、TwinSpec、canonicalization 或 trust-boundary semantics 前,请先阅读 CONTRIBUTING.md。

在使用 synthetic local fixture 以外的任何数据前,请阅读 SECURITY.md。不要提交:

  • credential / secret;
  • production trace;
  • personal data;
  • 无权重新分发的第三方 recording。

项目定位与研究声明

本项目不声称自己是第一个 mock server、stateful sandbox、service virtualization system 或 digital twin。

它提出的更窄假设是:Agent engineering 需要一种可复用组合,将以下能力放在一起:

  • MCP-compatible agent-facing surface;
  • explicit state-transition contracts;
  • forkable deterministic world state;
  • strict control-plane isolation;
  • declared fidelity 与 differential validation。

Prior-art 调研记录在 Competitive Landscape。一次带日期的 public search 无法证明不存在类似的 public、private 或 unindexed project;如果出现更强 prior art,项目定位应随证据调整。


开发预览兼容性提示

2026-09-02 的维护修复将 CEL 迁移到官方 cel.dev/cel-go 模块,并修正了 CEL null 被错误输出为数字 0 的问题。受影响的结果/状态摘要会改变; 旧快照和证据不会被改写。比较评测时必须固定 runtime revision。 详见 维护 SPEC 索引 与 空值兼容边界。

License

MCP State Twin 使用 MIT License。完整、具有约束力的许可证文本见 LICENSE。

README 中对许可证的任何说明仅用于帮助阅读;若存在差异,以 LICENSE 文件中的标准 MIT 文本为准。

AgentTask 离线验证(实验性)

现在可通过 eval suite-preflight 全量预检,再用 eval suite 一次运行六任务、 两组 mock 配置并保存比较报告。支持独立世界、累计预算、取消和失败证据保留。 命令与回归演示见 批量离线指南。

运行后可用 eval suite-inspect --root DIR --out SUITE --format markdown 查看整套 证据;eval suite-verify 会重放核对保存报告,并要求无残留、报告一致且未观察到回归。 缺失、篡改或中断证据不会因汇总报告写着成功而通过。

需要判断候选是否真正达标时,使用 eval suite-assess,显式提供独立的 --expect 和 --policy candidate-pass-v1 或 both-pass-v1。它还会核对跨重复的定义一致性, 拒绝“两边同样失败但无回归”的假达标。见 候选达标指南。

新增独立任务准入、只读目标/策略评分和六个合成 witness。task validate 仅检查结构与工具面;task witness 经过 MCP 执行已知轨迹,再独立评分,明确标为 scripted-witness。它不是自主模型运行、provider live 或完整证据 replay。命令与限制见 SPEC-0038。

进一步的 eval mock 已支持合成 Responses 循环、独立世界、预算停止、证据保存与 eval verify 离线重放。eval compare 保留计划分母并输出回归/不可比/证据不足报告。 先跑 离线回归教程:故意遗漏动作的候选 应被判为回归,而不是得到假成功。此路线仍是 mock 测试,不是实际模型能力或 live 兼容证据; 完整边界见 SPEC-0039。

比较器使用 offline-regression-v2:评分器出错不计作有效评分;新策略违规即使总次数 不变也会阻断门禁。JSON/Markdown 列出双方分母、trial ID 和回归原因,读取有累计预算, 取消不会变成完成报告。两边同样失败可以“未观察到回归”,但不是任务成功或升级许可。 详细规范见 Spec 索引。旧 JSON 严格消费者需接受新增报告字段。

按任务汇总 taskSummaries 进一步列出各任务的回归/不可比/证据不足次数,以及双方 成功、预期不操作、任务失败、策略违规、未评分数量。缺失和损坏的证据仍计入计划总数, 不会被当成成功或从分母移除。JSON 和 Markdown 都保留逐次详情;相同 Task ID 仅用于 分组,不证明不同重复使用了相同 oracle。规则见 SPEC-0055。

可选本地 API bridge(实验性,live 未验证)

新增独立的 eval live-plan / live-preflight / live / live-verify:先审阅完整 合成任务、明确模型、请求上限和有效期;只有批准计划并传入 --allow-live 才访问固定 OpenAI API endpoint。无默认模型、重试、重定向或 production tool passthrough。 超时保留未知接受状态,费用 unknown;证据重放不调用模型,也不证明 Provider 来源。

目前验证来自本地六任务 contract tests,尚无这个新 profile 的真实 API 验收报告, 不代表 ChatGPT/Codex/Claude 产品兼容。使用前请读 分步指南、 授权 Spec 和 传输/证据 Spec。

证据故障诊断(实验性)

eval inspect --root DIR --out RELATIVE_DIRECTORY 可只读检查 offline/local-API 产物:区分未开始、未完成、已发布、有残留和无效目录,核对 claim、分阶段工件与世界 replay。 不调用模型、不修改文件、不自动恢复;诊断退出码 0 不是任务成功或 Provider 来源证明。 先读 故障诊断指南。

保存链路已覆盖 22 个注入故障和五个测试子进程退出点,并修复短写漏检、取消影响终态 检查、后续清理错误覆盖首因,以及 JSON credential 字段漏检。完整契约: 存储/终态、 只读检查、 结构化隐私。 这些测试不等于硬件断电安全、全部 storage compatibility 或完整 DLP;SQLite schema 不变。

发布维护边界

发布前必须有版本绑定的 reviewed plan 和说明,完整 CI 在同一候选提交上通过后才可 创建 draft。预发布会明确标记为 prerelease,不自动发布或设为 Latest。打包拒绝已有 dist,不再删除旧产物;默认单槽 Go、串行构建。入口与未批准模板见 发布声明指南,详细契约见 Spec 索引。 当前验证是代码/工作流合同测试,不代表已执行新的 tag 发布或获得 stable 资格。

View this README on GitHub

Install

This server does not publish a one-line install command.

Open the repository installation guide