mcpField
P
Postgres and REST twins

Postgres and REST twins

本地服务
cmdrvl.com开发工具06 天前更新

关于 Postgres and REST twins

twinning 为数据库和 API 提供遵循已声明契约的本地协议替身,供开发者和 Agent 在接入真实系统前测试客户端、提取器及迁移。请求超出契约时会给出拒绝原因,并记录报告;其 MCP 管理器仅提供 Postgres 和 REST 替身。

主要功能

  1. 01按声明子集模拟 Postgres
  2. 02依据 OpenAPI 规范模拟 REST
  3. 03返回约束拒绝原因和 SQLSTATE
  4. 04重放查询比较迁移快照
  5. 05MCP 工具管理替身生命周期

适用场景

  1. 01在真实数据库前演练数据管道
  2. 02比较迁移前后的查询结果
  3. 03按 OpenAPI 契约测试 API 客户端

MCP 相关

stdio MCP 服务提供七种工具,用于检查环境、创建和停止 Postgres 或 REST 替身、列出实例及读取报告。MCP 管理器不提供 MCP 协议替身。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"com-cmdrvl-twinning": {
"command": "npx",
"args": [
"-y",
"@cmdrvl/twinning-mcp"
]
}
}
}
启动命令npx -y @cmdrvl/twinning-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@cmdrvl/twinning-mcp0.7.1

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

twinning

Twinning 为你的代码和 Agent 提供数据库或 API 的替身,并告知请求被拒绝的原因。将它指向 Postgres 架构或 OpenAPI 规范,即可启动本地孪生服务。客户端使用常规驱动连接;违反约束的写入会返回真实的 SQLSTATE 和原因,并由报告记录发生的情况。你可以用它在代码和管道接触真实数据库前进行演练,通过针对新旧快照重放查询来检查迁移,并根据规范定义的契约测试 API 客户端。任何超出所声明契约的请求都会被拒绝并说明原因,而不是靠猜测处理。

与 Agent 一起设置

将此提示词粘贴到你的编码 Agent(Claude Code、Cursor、Codex,或任何能够运行 shell 命令的 Agent)中,即可在你的机器上安装 twinning MCP 服务。它会下载预构建版本、验证校验和,并配置你的 MCP 客户端。它适用于 macOS 和 Linux。Windows 压缩包目前尚不包含 MCP 服务。

Set up the twinning MCP server on this machine. Work through the steps in order,
run each command yourself, and tell me what you did and what you saw. Do not use
sudo, and do not change any MCP server entry other than "twins".

1. Detect my OS and CPU. Supported targets are aarch64-apple-darwin,
   x86_64-apple-darwin, x86_64-unknown-linux-gnu and aarch64-unknown-linux-gnu.
   If this is Windows, stop and tell me the MCP server is not available there yet.

2. Find the latest release tag of https://github.com/cmdrvl/twinning (for example
   by following the redirect from https://github.com/cmdrvl/twinning/releases/latest).
   The archive is named twinning-<tag>-<target>.tar.gz and the checksums file is
   named SHA256SUMS, both under https://github.com/cmdrvl/twinning/releases/download/<tag>/.

3. Create a new, empty directory ~/.local/share/twinning/<tag> and download the
   archive and SHA256SUMS into it with curl -fL (not a browser). Verify the archive
   against its line in SHA256SUMS (shasum -a 256 -c, or sha256sum -c on Linux).
   If the checksum does not match, stop and tell me. Do not extract it.

4. Extract the archive into that directory. It must contain two executables,
   twinning and twinning-mcp. Remember their absolute paths.

5. Run "<dir>/twinning-mcp doctor". It must print "health: ok (healthy (READY))".
   If macOS refuses to run the binaries, run
   "xattr -d com.apple.quarantine <dir>/twinning <dir>/twinning-mcp" and retry.

6. Ask me which project directory twins should work in (default: the current
   directory) and which MCP client I use. Then configure it:
   - Claude Desktop: "<dir>/twinning-mcp --workdir <project> setup --client claude-desktop"
   - Cursor: "<dir>/twinning-mcp --workdir <project> setup --client cursor"
   - Claude Code: "claude mcp add twins -- <dir>/twinning-mcp --workdir <project>"
   - Anything else: run "<dir>/twinning-mcp --workdir <project> setup --client claude-desktop --print"
     and add that "twins" entry to my client's MCP configuration by hand.
   Tell me if I need to restart or reload the client.

7. Check it works without the client: write a file schema.sql in the project
   directory containing
       CREATE TABLE deals (deal_id TEXT PRIMARY KEY, deal_name TEXT NOT NULL);
   then start the server with "<dir>/twinning-mcp --workdir <project>" and, over
   MCP stdio, call twin_doctor, then twin_start with kind "postgres" and
   schema_path "schema.sql", then twin_stop with the returned twin_id. Report the
   result of each call. Stop the server when done.

If any step fails, stop and show me the exact command and its full output.

Twinning 由 CMD+RVL 开发。如果你从事申报文件或结构化金融数据相关工作,并希望获得有来源依据的答案,可以通过文字与我们的研究助手 Cairn 聊天:textcairn.com。

与 Agent 一起使用(MCP)

Twinning 不是通用数据库。MCP 管理器仅提供 postgres 和 rest 两种孪生类型,不提供 MCP 孪生类型。MCP stdio 是管理器的控制接口。Postgres 接受所声明的 SQL 子集,REST 提供规范定义的路由,而超出这些契约的请求会收到拒绝原因。

使用场景
使用场景录制演示
提取器和管道开发:根据架构契约演练写入,并查看违反了哪些约束。psycopg2 演示步骤、运行脚本、客户端兼容性结果
迁移验证:针对旧版和候选 Postgres 快照重放一组查询,并检查哪些结果存在差异。已记录的验证结果、迁移演示
API 契约测试:使用身份验证和架构拒绝机制测试 OpenAPI REST 孪生服务。REST 兼容性结果、REST 演示
构建和配置

从源代码构建两个可执行文件:

cargo build --locked --release -p twinning -p twinning-mcp

首次运行且缓存为空时,Cargo 需要联网下载锁定的 Rust 依赖项。该演示也需要联网,以便通过 uv 下载 psycopg2-binary。

将 twinning 放在 twinning-mcp 旁边,然后为项目目录配置 Claude Desktop 或 Cursor。需要更新配置时,setup 会合并 twins 条目、保留其他服务条目,并在替换现有文件前备份该文件。--print 会显示配置片段,但不会写入文件。

./target/release/twinning-mcp --workdir "$PWD" setup --client claude-desktop
./target/release/twinning-mcp --workdir "$PWD" setup --client cursor
./target/release/twinning-mcp --workdir "$PWD" setup --client claude-desktop --print

生成的客户端条目格式如下。setup 会填入可执行文件和工作目录的绝对路径。

Claude Desktop:

{
  "mcpServers": {
    "twins": {
      "command": "/absolute/path/to/twinning-mcp",
      "args": ["--workdir", "/absolute/path/to/project"]
    }
  }
}

Cursor:

{
  "mcpServers": {
    "twins": {
      "command": "/absolute/path/to/twinning-mcp",
      "args": ["--workdir", "/absolute/path/to/project"]
    }
  }
}

预构建二进制文件安装:从发布页面下载适用于你平台的压缩包,并根据 SHA256SUMS 验证。每个 macOS 和 Linux 压缩包都包含匹配的 twinning 和 twinning-mcp 文件;Windows 压缩包仅包含 twinning。

MCP 服务也发布在 npm 上。npx @cmdrvl/twinning-mcp 会下载匹配的发布压缩包、通过其 SHA-256 校验,并运行它。Homebrew 也会安装这两个二进制文件:brew install cmdrvl/tap/twinning。

工具

stdio MCP 服务公开了七个工具:

工具参数
twin_doctor无。检查可执行文件和工作目录。
twin_list无。列出保留的 twin。
twin_pair_proof必需:left_snapshot_path、right_snapshot_path、queries_path。可选:report_path。
twin_reporttwin_id;仅在停止后可用。
twin_seed_contractkind: "postgres"、schema_path。
twin_start必需:kind 及对应类型的输入路径。Postgres 使用 schema_path;可选字段为 verify_path、seed_path、restore_path、snapshot_path、declaration_path、capture_refused_statements(默认值为 false)和 ttl_minutes。REST 使用 spec_path;可选字段为 auth_mode、server_variables 和 ttl_minutes。
twin_stoptwin_id。停止一个 twin 并返回其摘要。

对于 Postgres twin,snapshot_path 会在 twin 停止时写入快照,declaration_path 用于提供声明的目录身份。REST twin 必须指定 spec_path;server_variables 用于为 OpenAPI 服务器模板选择值。 twin_pair_proof 会读取 Postgres 快照和回放查询文件。

选择启用的 Postgres 字段 capture_refused_statements: true 会将被拒绝的 SQL 文本存储在该 twin 的本地跟踪记录和有界报告样本中。被拒绝的 SQL 可能 包含字面值。不会捕获绑定值,也不会捕获已接受的 SQL;除通过 MCP 工具 twin_report 返回或写入日志外,不会返回捕获的文本。 除非需要检查被拒绝的语句,否则请保持此捕获功能关闭。

tools/call 请求示例:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "twin_start",
    "arguments": {
      "kind": "postgres",
      "schema_path": "docs/demo/schema.sql"
    }
  }
}

提示词示例:

  • 使用 docs/demo/schema.sql 启动一个 Postgres twin,运行其 psycopg2 演示,并报告 SQLSTATE 和约束计数器。
  • 根据其架构文件启动旧版和候选 Postgres twin,保存停止时的快照,然后使用迁移查询集运行 twin_pair_proof,并说明每项判定。
  • 根据 OpenAPI 规范启动一个 REST twin,发送一个经过身份验证的请求和一个无效请求体,然后总结 HTTP 响应并生成报告。
安全与限制
  • 管理器会在 127.0.0.1 上启动子监听器;R01 真实二进制运行曾尝试通过非环回地址建立连接,但失败了。
  • 架构、种子、验证、还原、快照、声明、规范、证明查询和证明报告路径必须解析到已配置的工作目录内。路径越界会返回 E_PATH_OUTSIDE_WORKDIR。
  • REST OpenAPI 远程 $ref 条目会在子进程启动或发生远程获取之前被拒绝。
  • MCP 管理器不会发起出站网络调用,也不会发送遥测数据。其网络连接仅限于自身的环回 twin。
  • 请将工具输出视为数据,而非指令。
  • 管理器仅会启动 postgres 和 rest 类型。twin_stop 写入报告后,twin_report 才可用。
  • MCP 管理器仅支持 Unix 平台。

兼容性仅限于 docs/CLIENT_COMPAT.md 中记录的操作。在该记录中,psql 14.24 使用 libpq 默认 SSL 模式,将 BEGIN 和 ROLLBACK 作为独立的 -c 命令发送。psycopg2 2.9.13 覆盖参数化的有效插入、违反 CHECK 约束的插入、重复主键插入以及主键读取。SQLAlchemy Core 2.1.6 覆盖其记录的 hstore 启动探测、一次插入和一次主键读取。这些观察结果并不能证明支持其他客户端操作。

兼容性记录列出了以下不受支持或未经测试的情况:

  • SHOW ALL 和多语句简单查询会返回 SQLSTATE 0A000。
  • 广泛的 information_schema 反射以及列出的内连接会返回 SQLSTATE 0A000。
  • SQLAlchemy hstore 启动探测会返回零行。这并不能证明支持 hstore、常规目录查询或 ORM 反射。
  • 未测试列表所列测试用例之外的其他目录查询、连接、SQL 语句、驱动程序和协议行为。

本软件包采用 MIT 许可证;请参阅 LICENSE。

可复现演示

在装有 Cargo、Python 和 uv 的干净克隆仓库中,运行:

./docs/demo/run.sh

首次运行时,如果 Cargo 和 uv 缓存为空,脚本需要联网下载已锁定的 Rust 依赖项和 psycopg2-binary。它会构建真正的 twinning 和 twinning-mcp 二进制文件,使用真正的 psycopg2 驱动,启动一个 twin,插入一行有效数据,记录一次 CHECK 约束违规,停止 twin,并读取最终报告。请参阅演示步骤。

忠实于协议的接口 twin,可用于快速迭代提取器,并为后续迁移验证提供依据。

twinning 是 factory 运行时 twin 层的核心。它会在真正的协议边界后提供已确定的状态,使现有客户端代码能够针对快速、一次性的 twin 运行,而无需连接大型生产数据库。

它只回答一个有限的问题:

对于声明的子集,这个客户端或提取器能否在忠实于协议的 twin 上运行?该 twin 会生成哪些已提交状态制品?

当前状态:

  • 仓库状态:Phase 0 引导阶段,以及针对已验证 Postgres 子集的实时 run_once 和 --serve 外壳;另有 REST、MCP 和 Snowflake 协议 twin
  • 事实来源:docs/PLAN_TWINNING.md
  • 工作区:crates/twinning-kernel、crates/twinning-postgres、crates/twinning-rest、crates/twinning-snowflake
  • v0 核心之后的首个延期方向:twin 配对迁移验证

可用的协议 twin:

子命令功能标志协议
twinning postgres(默认)pgwire — 由 canary 定义的 SQL 子集
twinning restrest由 OpenAPI 规范驱动的 HTTP REST
twinning mcpmcpModel Context Protocol(通过 HTTP + stdio 传输的 JSON-RPC 2.0)
twinning snowflakesnowflakeSnowflake HTTP 线协议(Arrow IPC 结果)
twinning portrest用于客户端迁移验证的双 REST twin

构建所有 twin:cargo build --features all


当前快速入门

# Build with all protocol twins enabled
cargo build --features all

# Validate a schema and inspect the bootstrap state
cargo run -- postgres --schema schema.sql --json

# Write the bootstrap report and deterministic bootstrap snapshot
cargo run -- postgres --schema schema.sql --verify schema.verify.json \
  --report out/bootstrap.json \
  --snapshot out/bootstrap.twin \
  --json

# Capture declared rows from a disposable/source Postgres database into a snapshot
cargo run -- postgres --schema schema.sql \
  --materialize-source-url "$SOURCE_DATABASE_URL" \
  --report out/materialized.json \
  --snapshot out/materialized.twin \
  --json

# Export a seed contract for an external agent to fill, then import seed rows
cargo run -- postgres --schema schema.sql \
  --export-seed-contract out/seed-contract.jsonl \
  --json
cargo run -- postgres --schema schema.sql \
  --seed out/seed-data.jsonl \
  --snapshot out/seeded.twin \
  --json

# Restore a prior snapshot and re-emit bootstrap status
cargo run -- postgres --restore out/bootstrap.twin --json

# Compare two committed-state snapshots over one proof query fixture
cargo run -- --json proof twin-pair \
  --left snapshots/legacy.twin \
  --right snapshots/candidate.twin \
  --queries tests/fixtures/differential/twin_pair_migration_proof/cases.json \
  --report out/twin-pair-proof.json

# Run manifest-first twin-pair proof orchestration over restore-backed or schema-load endpoints
cargo run -- --json proof twin-pair orchestrate \
  --manifest proof-run.json \
  --report out/twin-pair-proof.json \
  --bundle-dir out/twin-pair-proof/

# Run one child command against the live run_once shell
# The child must connect to the configured --host/--port.
cargo run -- postgres --schema schema.sql --run 'your-client-command' --json

# REST twin — serve OpenAPI-spec-driven HTTP endpoints
cargo run --features rest -- rest --spec openapi.yaml --serve --report out/rest.json

# REST response stubs — deterministic contract responses declared in x-twinning
cargo run --features rest -- rest \
  --spec tests/fixtures/rest/openfigi_v2_v3/response-stub-schema.yaml \
  --server-variable basePath=v3 \
  --auth-mode shape \
  --serve

# MCP twin — serve Model Context Protocol over HTTP (or stdio)
cargo run --features mcp -- mcp --server 'npx @scope/mcp-server' --report out/mcp.json
cargo run --features mcp -- mcp --manifest manifest.json --serve

# Snowflake wire twin — serve Snowflake HTTP protocol with Arrow IPC results
cargo run --features snowflake -- snowflake --schema schema.sql --serve --report out/sf.json

# Run a standalone interactive twin until SIGINT/SIGTERM
cargo run -- postgres --schema schema.sql \
  --serve \
  --report out/interactive.json \
  --snapshot out/interactive.twin \
  --json

# Opt in to a redacted-by-default query trace artifact for a live run_once session
cargo run -- postgres --schema schema.sql \
  --run 'your-client-command' \
  --query-trace out/query-trace.json \
  --json

# Also capture SQL text for refused statements only; the local trace can contain SQL literals.
cargo run -- postgres --schema schema.sql \
  --serve \
  --query-trace out/query-trace.json \
  --capture-refused-statements \
  --json

# Print the operator manifest
cargo run -- --describe

# Inspect the read-only doctor surface
cargo run -- doctor health --json
cargo run -- doctor capabilities --json
cargo run -- doctor --robot-triage

第一个物化示例会调用 psql,并且只捕获架构中声明的表。请针对适合确定性读取的源账号/数据库使用此示例;在测试框架中,TWINNING_PSQL_BIN 可指向特定的 psql 二进制文件。--run 和 --serve 示例使用当前的实时 pgwire 外壳和最终制品路径。

Seed JSONL 是契约/数据对,并非生成器。--export-seed-contract 会写入一个确定性的、符合架构形状的模板,供其他 Agent 填写。--seed 会在引导最终化或实时启动之前,通过 Postgres 内核和约束执行器导入已填写的行,因此这些行会成为报告、快照和第一个 run_once 客户端会话中的已提交状态。V1 仅由架构提供支持:seed 导入/导出不能与 --restore 组合使用,且 --seed 不能与 --materialize-source-url 组合使用。

示例输出

人类可读模式(默认):

twinning postgres bootstrap ready
endpoint: 127.0.0.1:5432
schema: schema.sql (4 tables, 28 columns, 3 indexes, hash sha256:a1b2c3...)
storage: tournament=bounded-memory hot working set with per-twin overlay | replay=disk-backed, snapshot-backed, or delegated real-database backend
verify: constraints.verify.json (12 loaded, hash sha256:d4e5f6...)
snapshot: out/bootstrap.twin (sha256:7a8b9c...)
next: Bootstrap mode validated the schema assets and deterministic artifact path. Use --run or --serve to exercise the declared live Postgres subset, or stay in bootstrap mode while broader protocol and SQL coverage lands.

JSON 模式(--json):

{
  "version": "twinning.v0",
  "outcome": "READY",
  "mode": "bootstrap",
  "engine": "postgres",
  "host": "127.0.0.1",
  "port": 5432,
  "wire_protocol": "pgwire",
  "schema": {
    "source": "schema.sql",
    "hash": "sha256:a1b2c3...",
    "table_count": 4,
    "column_count": 28,
    "index_count": 3,
    "constraint_count": 9
  },
  "verify_artifact": {
    "source": "constraints.verify.json",
    "hash": "sha256:d4e5f6...",
    "loaded": 12
  },
  "catalog": {
    "dialect": "postgres",
    "table_count": 4,
    "column_count": 28,
    "index_count": 3,
    "constraint_count": 9
  },
  "storage": {
    "tournament_mode": "bounded-memory hot working set with per-twin overlay",
    "replay_mode": "disk-backed, snapshot-backed, or delegated real-database backend",
    "hot_working_set": "memory",
    "cold_state": "shared snapshot or pluggable backing store"
  },
  "tables": {
    "public.deals": { "rows": 0, "columns": 10, "indexes": 2, "constraints": 4 },
    "public.tenants": { "rows": 0, "columns": 6, "indexes": 1, "constraints": 3 }
  },
  "constraints": {
    "not_null_violations": 0,
    "fk_violations": 0,
    "check_violations": 0,
    "unique_violations": 0
  },
  "snapshot": {
    "written_to": "out/bootstrap.twin",
    "snapshot_hash": "sha256:7a8b9c..."
  },
  "next_step": "Bootstrap mode validated the schema assets and deterministic artifact path. Use --run or --serve to exercise the declared live Postgres subset, or stay in bootstrap mode while broader protocol and SQL coverage lands."
}

引导报告会显示上方用于验证的 next_step 字符串。使用 --run 时,报告会切换为 mode: "run_once",并将操作人员指向最终的 run 元数据。

单次运行模式(--run <COMMAND>):

{
  "version": "twinning.v0",
  "outcome": "FAIL",
  "mode": "run_once",
  "engine": "postgres",
  "host": "127.0.0.1",
  "port": 5432,
  "run": {
    "command": "exit 7",
    "exit_code": 7,
    "timed_out": false
  },
  "next_step": "Inspect the run metadata, fix the child failure or drift, and rerun the candidate against the twin."
}

交互模式(--serve):

{
  "version": "twinning.v0",
  "outcome": "READY",
  "mode": "interactive",
  "engine": "postgres",
  "host": "127.0.0.1",
  "port": 5432,
  "next_step": "Interactive mode finalized committed-state artifacts after shutdown. Inspect the snapshot and embedded verify payload before reusing this twin state."
}

拒绝模式(引导/配置失败):

{
  "version": "twinning.v0",
  "outcome": "REFUSAL",
  "refusal": {
    "code": "E_AMBIGUOUS_BOOTSTRAP_SOURCE",
    "message": "Use exactly one bootstrap source: --schema or --restore, not both.",
    "detail": { "engine": "postgres" },
    "next_command": "twinning postgres --schema schema.sql --json"
  }
}

为什么需要 twinning

两个循环需要同一种基础能力:

  • 提取器迭代。 由 Agent 编写的提取器需要一个快速且表现类似 Postgres 的目标,用于快速暴露类型强制转换、约束违规和不支持的 SQL 形态。
  • 迁移验证。 后续,同一内核和快照契约应能支持历史查询重放和双实例迁移验证,而无需将旧版工作负载指向生产环境。

你需要提供:

  • 一个架构 DDL 文件或先前的快照
  • 可选的已编译 verify.constraint.v1 工件
  • 后续可将真实客户端或提取器指向 twin

twinning 会返回:

  • 一份关于声明的已提交状态的确定性 twinning.v0 报告
  • 一份内容寻址的 twinning.snapshot.v0 快照,其中包含规范化的已提交状态字节;创建时间和恢复沿袭等封套元数据仍会明确保留,但不作为相等性判断依据
  • 明确的拒绝行为,而非静默地提供不完整语义
  • 后续针对 canary 定义的 Postgres 子集提供协议可见的运行时行为

当前已有功能

目前已实现:

Postgres twin(默认):

  • 使用 sqlparser-rs 解析 DDL,确定性地构建规范化目录
  • 加载 verify 工件,生成引导报告和快照
  • pgwire 监听器 + 针对声明的实时子集的启动/会话外壳
  • 规范化的读取/变更 IR,以及针对 canary 定义的 SQL 形态执行行存储操作
  • 支持实时 --run 和 --serve 模式,并通过 SIGINT/SIGTERM 完成最终处理
  • 内嵌 verify 执行、双实例迁移验证编排

REST twin(--features rest):

  • 由 OpenAPI 规范驱动的 HTTP 端点生成
  • 身份验证形态强制执行(bearer/apiKey)、混沌注入、路由模式
  • 用于基于 fixture 的契约响应的确定性 x-twinning.response-stubs
  • canary 清单验证、启动报告、port 双实例迁移验证

MCP twin(--features mcp):

  • 通过 HTTP 和 stdio 传输的 JSON-RPC 2.0 分发器
  • 目录来自实时 MCP 服务内省或静态清单
  • 全部 7 种 MCP 方法:initialize、tools/list、tools/call、resources/list、resources/read、prompts/list、prompts/get
  • 为带有输出架构的工具提供类型化 stub 响应;对有状态/无架构的工具返回 unsupported_shape
  • 身份验证强制执行、会话日志、启动报告

Snowflake wire twin(--features snowflake):

  • Snowflake HTTP REST 协议(5 个核心端点)
  • 使用 Arrow IPC rowsetBase64 编码结果,并完整保留 Snowflake 类型
  • 提供 SHOW 和 DESCRIBE 响应,兼容 JDBC/DBeaver/dbt
  • DDL 目录摄取、通过 SqlRoute 分类进行查询分发
  • 会话生命周期、启动报告、物化路径

尚未实现:

  • 已检入的 canary 清单之外的 SQL/会话形态
  • 联接读取(当前清单中明确拒绝,并通过协议可见)
  • 并发写入者或多写入者语义
  • 内存中基于快照的验证路径之外,更复杂的重放/验证后端

这意味着该仓库可以验证引导资产、运行一条子命令,或为已验证子集提供交互式客户端服务,但对于更广泛的实时流量,它仍会予以拒绝,而不会假装自己是一个完整的数据库。


运行时契约

命令接口:

twinning postgres [OPTIONS]           # pgwire twin (default)
twinning rest [OPTIONS]               # REST twin (--features rest)
twinning mcp [OPTIONS]                # MCP twin (--features mcp)
twinning snowflake [OPTIONS]          # Snowflake wire twin (--features snowflake)
twinning port [OPTIONS]               # dual REST twins (--features rest)
twinning proof twin-pair [OPTIONS]    # twin-pair migration proof
twinning doctor [SUBCOMMAND]          # read-only health/capabilities

当前选项:

  • --schema <FILE>:定义表、约束和索引的 SQL DDL 文件
  • --verify <FILE>:已编译的 verify.constraint.v1 产物
  • --declaration <FILE>:可选的 twinning.catalog-declaration.v0 父目录子集标识
  • --host <HOST>:绑定主机(默认 127.0.0.1)
  • --port <PORT>:绑定端口(默认 5432)
  • --run <COMMAND>:通过运行中的 pgwire shell 执行一条子命令,然后冻结最终产物
  • --serve:运行独立的交互式 pgwire shell,直到收到 SIGINT/SIGTERM,然后冻结最终产物
  • --report <FILE>:写入 twinning.v0
  • --snapshot <FILE>:写入 twinning.snapshot.v0
  • --query-trace <FILE>:在 --run 或 --serve 中写入实时查询跟踪产物,默认会进行脱敏
  • --capture-refused-statements:与 --query-trace 配合时,仅捕获被拒绝的 Postgres SQL 文本;本地跟踪可能包含 SQL 字面值,但绝不包含绑定值
  • --restore <FILE>:恢复先前的 twinning.snapshot.v0
  • --export-seed-contract <FILE>:为已加载架构的 Postgres 目录写入 twinning.seed-contract.v0 JSONL
  • --seed <FILE>:将已填充的 twinning.seed-data.v0 JSONL 导入为已提交的 Postgres 状态
  • --materialize-source-url <URL>:将声明的源行捕获到最终报告/快照中
  • --json:输出机器可读状态
  • --describe:打印 operator.json

REST 响应桩在 OpenAPI 文档中的 x-twinning.response-stubs 下声明,并通过现有的 twinning rest --spec <FILE> 路径使用。它们是确定性的契约夹具: 运行时会匹配方法、挂载路径和可选的规范化 JSON 请求体是否相等,然后在 完成身份验证、故障注入和匹配请求体验证检查后,返回声明的状态、标头以及 JSON、文本或基于文件的响应体。基于文件的响应体使用 body-file,并在启动时进行验证。它们不是生成的虚假数据,不是实时服务提供方模拟器,也不是单独的 REST --seed 模式。

对于匹配的 JSON 路由,REST twin 会在响应桩、 物化或 unsupported_shape 路由拒绝之前,验证声明的 OpenAPI requestBody.content.application/json.schema。架构验证失败会返回确定性的请求路径,例如 $.edges[0].downstream_key;格式错误的 JSON 和不受支持的内容类型保留现有的拒绝映射。如果有效请求到达非物化路由,request_valid: true 仅表示请求符合声明的请求架构。这不表示副作用已建模或持久化。

使用不同规格或精简的规格覆盖,为同一上游服务建模不同的 API 场景,例如成功路径、无匹配、格式错误/错误以及歧义 twin。 tests/fixtures/rest/openfigi_v2_v3/response-stub-schema.yaml 中的 OpenFIGI 夹具展示了本地 /v3/mapping 响应如何返回 OpenFIGI 顶层批次数组,而不是通用的 {"data":null,"warning":null} 回退响应。

受管理的路径:

  • 规范配置位置:~/.cmdrvl/config/twinning/config.toml
  • 规范的工具管理状态目录:~/.cmdrvl/state/twinning/
  • 规范的可重建缓存目录:~/.cmdrvl/cache/twinning/
  • 迁移记录和弃用通知:~/.cmdrvl/migrations/applied.jsonl 和 ~/.cmdrvl/notices/deprecated-paths.jsonl
  • 当前清单中没有需要复制的旧版 twinning 管理的主目录或仓库配置路径。只有在操作员提供明确的输出路径时,才会写入报告、快照、查询跟踪、种子契约、证明包和协议会话报告。

只读 doctor 界面:

  • doctor health --json:输出 twinning.v0 健康诊断信息,不读取架构、快照或 verify 文件
  • doctor capabilities --json:列出机器可读的命令、输出契约、检测器夹具和安全边界
  • doctor robot-docs:打印简洁的、面向 Agent 的命令说明
  • doctor --robot-triage:输出结构化的后续处理发现 doctor --fix 有意不提供。只读 doctor 检测器目录由 fixture 提供支持,任何未来的修复模式在开放使用前,都需要逐字备份、明确的逆向操作和撤销测试。

退出代码:

退出码含义
0bootstrap、run_once 或 --serve 完成,且未出现内嵌 verify 失败
1实时定稿已完成,但内嵌 verify 报告了 FAIL
2拒绝 / bootstrap 失败 / CLI 错误

实时形态规范:

  • bootstrap / 配置失败保持为进程级拒绝
  • 不受支持的实时协议或 SQL 形态会成为客户端可见错误
  • 收到不受支持的实时流量后,双生体仍会保持运行
  • 报告和快照只能查看已提交状态

核心边界

twinning 负责:

  • 运行时 / 会话行为
  • 物化后的双生体状态
  • 快照
  • 双生体原生原始指标

twinning 不负责:

  • 声明解析或规范化(decoding、canon)
  • 约束语义(verify)
  • 黄金集评分(benchmark)
  • 继续 / 升级处理 / 阻止决策(assess)
  • 证据封存(pack)

关键边界:

  • 实时双生体必须执行内嵌 verify
  • 必须附加原始 verify.report.v1 载荷
  • 不得导出状态并通过 shell 调用批处理 verify
  • 双生体对证明报告可以引用原始 verify / benchmark / assess 工件标识,但不得对其评分或重新解释
  • 双生体对证明案例包含带快照来源信息、结果哈希和 SQLSTATE 奇偶性 的重放结果差异输入,而不包含基于时序推导的字段

twinning 的定位

工厂角色:

decoding / materialize -> twinning -> embedded verify -> assess / pack

当前开发顺序:

real Postgres proof loop first -> twinning tournament wedge -> later replay/proof modes

相关工具:

如果你需要……使用
声明解析和规范变更选择decoding
约束语义和报告verify
黄金集评分benchmark
策略决策assess
证据封存pack

twinning 只回答:

我们能否在符合协议规范的双生体边界后,为声明的子集物化并运行候选状态?


工件

当前工件契约:

  • twinning.v0 — 引导或后续运行时报告
  • twinning.snapshot.v0 — 内容寻址快照
  • twinning.query-trace.v0:可选择启用的实时查询血缘工件,SQL 文本已脱敏
  • twinning.query-trace.v1:可选择启用的拒绝语句捕获;拒绝的 SQL 文本可能包含 SQL 字面值,绑定值仍会脱敏
  • twinning.twin-pair-proof.v0 — 两个 Postgres 双生实例的接口等效性回执
  • twinning.twin-pair-replay-result.v0 — 双生实例配对证明报告中嵌套的逐用例重放差异输入
  • twinning.twin-pair-replay-manifest.v0 — 用于双生实例配对证明查询的已声明 Postgres 子集重放清单
  • twinning.twin-pair-orchestration-manifest.v0 — 清单优先的双生实例配对证明编排契约
  • twinning.canary-manifest.v0 — 受支持子集的规范兼容性清单

已检入的清单:

架构:

快照契约要点:

  • 哈希包含已提交状态标识和规范关系排序
  • 哈希不包含时间戳、实时会话、警告和调试字符串
  • 引导快照仅包含目录;run_once 快照会冻结已执行子集中的已提交关系内容

拒绝代码

拒绝以结构化错误形式返回,退出代码为 2。每个错误都包含代码、消息、详情,以及(如适用)建议替代操作的 next_command。

代码触发条件后续步骤
E_BOOTSTRAP_SOURCE_REQUIRED未提供 --schema 或 --restore添加 --schema schema.sql
E_AMBIGUOUS_BOOTSTRAP_SOURCE同时提供了 --schema 和 --restore只使用其中一个
E_ENGINE_UNIMPLEMENTED请求了非 Postgres 引擎使用 twinning postgres ...
E_IO_READ无法读取输入文件检查路径和权限
E_IO_WRITE无法写入输出文件检查路径和权限
E_SCHEMA_PARSEDDL 解析失败修正架构文件中的 SQL 语法
E_DECLARATION_PARSE目录声明格式错误或不匹配针对所选架构重新生成声明
E_VERIFY_ARTIFACT_PARSE验证工件格式错误使用 verify 重新生成
E_SNAPSHOT_VERIFY快照哈希不匹配或版本错误从架构源重新输出
E_SEED_BOOTSTRAP_SOURCE使用 --restore 请求了种子导入/导出使用 --schema
E_SEED_SOURCE_COMPOSITION将 --seed 与 --materialize-source-url 结合使用v1 请选择一个来源
E_SEED_JSONL种子 JSONL 格式错误,或违反目录/约束规则重新生成或修正种子行
E_REST_INVALID_X_TWINNINGREST x-twinning 响应桩格式错误,或未指向已挂载路由修正 OpenAPI x-twinning 扩展
E_TWIN_PAIR_PROOF双生实例配对证明输入或查询测试夹具不兼容使用架构/目录/声明相同的快照,并搭配受支持的查询测试夹具
E_SERIALIZATION内部 JSON 渲染失败报告错误

拒绝绝不会悄无声息。如果 twinning 无法执行你的请求,它会说明原因以及你可以尝试的替代操作。


twinning 不是什么

如果你需要……使用twinning 不会做什么
认领解析、规范变更选择decodingtwinning 不判断事实真伪
约束语义和验证规则verifytwinning 会执行 verify,但不会定义约束
黄金集评分benchmarktwinning 会物化状态,但不会为状态评分
策略放行/阻止决策assesstwinning 会报告,但不会裁决
证据封存packtwinning 是运行时工具,不是归档工具
真正的 Postgres 实例docker run postgrestwinning 针对有限子集实现协议支持,它不是数据库
通用 SQL 引擎DuckDB、SQLitetwinning 仅支持由 canary 定义的形态

twinning 只回答:客户端能否针对声明的子集使用符合协议的孪生体运行,以及该孪生体会生成哪些已提交状态产物?


安装

Homebrew(标记版本)

标记版本会将 twinning 发布到 cmdrvl/tap:

brew install cmdrvl/tap/twinning

在发布首个标记版本之前,请使用下方的源码构建方式。

从源码构建(当前方式)
git clone https://github.com/cmdrvl/twinning.git
cd twinning
cargo build --release
# Binary at target/release/twinning

Cargo 会获取固定的 cmdrvl/verify Git 修订版本,用于 verify-core 和 verify-engine;无需检出同级仓库。


Agent/CI 集成

twinning 专为 Agent 驱动的流水线设计。以编程方式解析 JSON 输出:

# Check bootstrap readiness
result=$(cargo run -- postgres --schema schema.sql --json 2>/dev/null)
outcome=$(echo "$result" | jq -r '.outcome')

case $outcome in
  READY)    echo "Twin ready for bootstrap or live mode" ;;
  REFUSAL)  echo "Refused: $(echo "$result" | jq -r '.refusal.code')" ;;
esac

# Exit code routing
cargo run -- postgres --schema schema.sql --json
case $? in
  0) echo "clean bootstrap" ;;
  1) echo "verify violations (future)" ;;
  2) echo "refusal or error" ;;
esac

故障排除

run_once 模式下出现 FAIL 结果

子命令执行完成,但返回了非成功退出状态、超时、收到信号,或出现了内嵌的 verify 失败。检查 twinning.v0 中的 run 元数据和任何附带的 verify 负载,修正候选内容或受支持形态的偏差,然后重新运行。

看似有效的 SQL 出现 E_SCHEMA_PARSE

twinning 使用 sqlparser-rs 解析 DDL。请确保架构采用标准的 Postgres CREATE TABLE 语法。v0 不支持扩展、自定义类型和过程式 SQL。

E_SNAPSHOT_VERIFY 哈希不匹配

快照在创建后被修改,或由不同版本的 twinning 生成。请使用 --schema 和 --snapshot 从原始架构源重新生成。

mysql 或 oracle 出现 E_ENGINE_UNIMPLEMENTED

目前仅实现了 Postgres 引擎。CLI 中声明了 MySQL 和 Oracle,以便向前兼容,但目前会拒绝它们。路线图请参见 docs/PLAN_TWINNING_FUTURES.md。


限制(v0)

  • 仅支持 Postgres。 MySQL、Oracle、VSAM、IMS 暂不支持。
  • 仅支持由 Canary 定义的实时 Shell。 --run 和 --serve 会为清单所涵盖的子集绑定 pgwire;不支持的 SQL 和协议形态仍会明确报错。
  • 仅支持 Canary 定义的子集。 仅支持 canary 清单中列出的 SQL 形态。
  • 不支持并发写入方。 预期的实时模型是单写入方准入,并在发生争用时明确拒绝。
  • 仅支持基于内存快照的证明编排。 当已提交状态符合当前内存预算时,支持基于恢复和基于架构加数据加载的证明端点;更重型的重放/证明后端仍暂缓实现,具体见后端策略。

仓库计划


质量门槛

cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test
./scripts/ubs_gate.sh

由 CMD+RVL 构建。支持:[email protected] 或 GitHub 问题。对申报文件或结构化金融数据有疑问? 通过文字聊天联系 Cairn:textcairn.com。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。