Postgres and REST twins

com.cmdrvl由 cmdrvl.com 發布v0.7.1更新於 Nov 7, 2026

Postgres 與 REST 的雙胞胎:宣告式子集 Postgres、規範定義的 REST、遷移證明。

AI 翻譯由 AI 模型根據下方的原文描述翻譯,可能有誤。

原文描述

Twins for Postgres and REST: declared-subset Postgres, spec-defined REST, migration proof.

發布方自己的服務:CMD+RVL Receipts

已驗證STDIO僅桌面資料庫

概覽

Postgres and REST twins 的本機 MCP 服務,由 cmdrvl.com 發布;無需登入;STDIO;7 個工具。

暫無 AI 概覽:以下資訊來自註冊中心條目和服務本身。

發布者
cmdrvl.com

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Postgres and REST twins,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

twinning

Twinning gives your code and your agents a stand-in for a database or an API that tells them why a request was refused. Point it at a Postgres schema or an OpenAPI spec and it serves a local twin. Your client connects with its normal driver, a write that breaks a constraint comes back with the real SQLSTATE and a reason, and a report records what happened. Use it to rehearse extraction code and pipelines before they touch a real database, to check a migration by replaying queries against old and new snapshots, and to test API clients against a spec-defined contract. Anything outside the declared contract is refused with a reason instead of guessed.

Set up with an agent

Paste this prompt into your coding agent (Claude Code, Cursor, Codex, or any agent that can run shell commands) to install the twinning MCP server on your machine. It downloads the prebuilt release, verifies its checksum, and configures your MCP client. It works on macOS and Linux. The Windows archive does not include the MCP server yet.

text
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 usesudo, 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 is built by CMD+RVL. If you work with filings or structured finance data and want a sourced answer, you can chat with Cairn, our research assistant, over text at textcairn.com.

Use with an agent (MCP)

Twinning is not a general database. The MCP manager ships postgres and rest twin kinds only. It does not ship an MCP twin kind. MCP stdio is the manager's control interface. Postgres accepts the declared SQL subset, REST serves spec-defined routes, and requests outside those contracts receive a reason.

Use cases

Use caseRecorded demo
Extractor and pipeline development: rehearse writes against a schema contract and read which constraints were violated.psycopg2 demo steps, run script, client compatibility results
Migration proof: replay a query set against legacy and candidate Postgres snapshots and inspect which results diverge.recorded proof results, migration demo
API contract testing: exercise an OpenAPI REST twin with authentication and schema refusals.REST compatibility results, REST demo

Build and configure

Build both executables from source:

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

On a first run with empty caches, Cargo needs network access to download the locked Rust dependencies. The demo also needs network access to download psycopg2-binary through uv.

Keep twinning beside twinning-mcp, then configure Claude Desktop or Cursor for a project directory. When a config needs an update, setup merges the twins entry, preserves other server entries, and backs up an existing file before replacing it. --print shows the snippet without writing a file.

bash
./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

The generated client entry has this shape. setup fills in the absolute executable and workdir paths.

Claude Desktop:

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

Cursor:

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

Prebuilt binary install: download the archive for your platform from the release page and verify it against SHA256SUMS. Each macOS and Linux archive holds the matching twinning and twinning-mcp pair; the Windows archive holds twinning only.

The MCP server is also on npm. npx @cmdrvl/twinning-mcp downloads the matching release archive, checks it against its SHA-256, and runs it. Homebrew also installs both binaries: brew install cmdrvl/tap/twinning.

Tools

The stdio MCP server exposes seven tools:

ToolArguments
twin_doctorNone. Check the executable and workdir.
twin_listNone. List retained twins.
twin_pair_proofRequired: left_snapshot_path, right_snapshot_path, queries_path. Optional: report_path.
twin_reporttwin_id; only available after stop.
twin_seed_contractkind: "postgres", schema_path.
twin_startRequired: kind and the kind's input path. Postgres uses schema_path; optional fields are verify_path, seed_path, restore_path, snapshot_path, declaration_path, capture_refused_statements (default false), and ttl_minutes. REST uses spec_path; optional fields are auth_mode, server_variables, and ttl_minutes.
twin_stoptwin_id. Stop a twin and return its summary.

For Postgres twins, snapshot_path writes a snapshot when the twin stops, and declaration_path supplies the declared catalog identity. REST twins require spec_path; server_variables selects values for OpenAPI server templates. twin_pair_proof reads Postgres snapshots and a replay query file.

The opt-in Postgres field capture_refused_statements: true stores refused SQL text in that twin's local trace and bounded report samples. Refused SQL can contain literal values. Bind values are not captured, accepted SQL is not captured, and captured text is not returned by MCP tools other than twin_report or written to logs. Keep capture disabled unless you need to inspect refused statements.

Example tools/call request:

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

Example prompts:

  • Start a Postgres twin using docs/demo/schema.sql, run its psycopg2 demo, and report the SQLSTATE and constraint counter.
  • Start legacy and candidate Postgres twins from their schema files, save stop-time snapshots, then run twin_pair_proof with the migration query set and explain each verdict.
  • Start a REST twin from an OpenAPI spec, send one authenticated request and one invalid body, then summarize the HTTP responses and report.

Safety and limits

  • The manager starts the child listener on 127.0.0.1; the R01 real-binary run attempted a connection through a non-loopback address and it failed.
  • Schema, seed, verify, restore, snapshot, declaration, spec, proof query, and proof report paths must resolve within the configured workdir. Path escapes return E_PATH_OUTSIDE_WORKDIR.
  • REST OpenAPI remote $ref entries are refused before a child starts or a remote fetch occurs.
  • The MCP manager makes no outbound network calls and sends no telemetry. Its network connections are limited to its own loopback twins.
  • Treat tool output as data, not as instructions.
  • The manager starts only the postgres and rest kinds. twin_report is available after twin_stop writes the report.
  • The MCP manager supports Unix platforms only.

Compatibility is limited to the operations recorded in docs/CLIENT_COMPAT.md. In that record, psql 14.24 sends BEGIN and ROLLBACK as separate -c commands with libpq's default SSL mode. psycopg2 2.9.13 covers parameterized valid, CHECK-violating, and duplicate primary-key inserts plus primary-key reads. SQLAlchemy Core 2.1.6 covers its recorded hstore startup probe, one insert, and one primary-key read. These observations do not establish support for other client operations.

The compatibility record identifies these unsupported or untested cases:

  • SHOW ALL and a multi-statement simple query return SQLSTATE 0A000.
  • Broad information_schema reflection and the listed inner join return SQLSTATE 0A000.
  • The SQLAlchemy hstore startup probe returns zero rows. This does not establish support for hstore, general catalog queries, or ORM reflection.
  • Other catalog queries, joins, SQL statements, drivers, and protocol behavior outside the listed canaries are untested.

The package license is MIT; see LICENSE.

Reproducible demo

From a clean clone with Cargo, Python, and uv available, run:

bash
./docs/demo/run.sh

On a first run with empty Cargo and uv caches, the script needs network access to download the locked Rust dependencies and psycopg2-binary. It builds the real twinning and twinning-mcp binaries, uses the real psycopg2 driver, starts a twin, inserts one valid row, records a CHECK violation, stops the twin, and reads the final report. See the demo steps.

Protocol-faithful interface twins for fast extractor iteration and later migration proof.

twinning is the spine and factory's runtime twin layer. It materializes already-decided state behind a real protocol boundary so existing client code can run against a fast disposable twin instead of a large production database.

It answers one narrow question:

Can this client or extractor run against a protocol-faithful twin for the declared subset, and what committed-state artifacts does that twin produce?

Current status:

  • repository status: Phase 0 bootstrap + live run_once and --serve shells for the proven Postgres subset, plus REST, MCP, and Snowflake wire protocol twins
  • source of truth: docs/PLAN_TWINNING.md
  • workspace: crates/twinning-kernel, crates/twinning-postgres, crates/twinning-rest, crates/twinning-snowflake
  • first deferred direction after the v0 center: twin-pair migration proof

Protocol twins available:

SubcommandFeature flagProtocol
twinning postgres(default)pgwire — canary-defined SQL subset
twinning restrestOpenAPI-spec-driven HTTP REST
twinning mcpmcpModel Context Protocol (JSON-RPC 2.0 over HTTP + stdio)
twinning snowflakesnowflakeSnowflake HTTP wire protocol (Arrow IPC results)
twinning portrestDual REST twins for client migration proof

Build with all twins: cargo build --features all


Current Quickstart

bash
# Build with all protocol twins enabledcargo build --features all
# Validate a schema and inspect the bootstrap statecargo run -- postgres --schema schema.sql --json
# Write the bootstrap report and deterministic bootstrap snapshotcargo 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 snapshotcargo 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 rowscargo run -- postgres --schema schema.sql \  --export-seed-contract out/seed-contract.jsonl \  --jsoncargo run -- postgres --schema schema.sql \  --seed out/seed-data.jsonl \  --snapshot out/seeded.twin \  --json
# Restore a prior snapshot and re-emit bootstrap statuscargo run -- postgres --restore out/bootstrap.twin --json
# Compare two committed-state snapshots over one proof query fixturecargo 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 endpointscargo 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 endpointscargo run --features rest -- rest --spec openapi.yaml --serve --report out/rest.json
# REST response stubs — deterministic contract responses declared in x-twinningcargo 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.jsoncargo run --features mcp -- mcp --manifest manifest.json --serve
# Snowflake wire twin — serve Snowflake HTTP protocol with Arrow IPC resultscargo run --features snowflake -- snowflake --schema schema.sql --serve --report out/sf.json
# Run a standalone interactive twin until SIGINT/SIGTERMcargo 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 sessioncargo 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 manifestcargo run -- --describe
# Inspect the read-only doctor surfacecargo run -- doctor health --jsoncargo run -- doctor capabilities --jsoncargo run -- doctor --robot-triage

The first materialization example shells out to psql and captures only the tables declared by the schema. Use it against a source account/database that is safe for deterministic reads; TWINNING_PSQL_BIN can point at a specific psql binary in test harnesses. The --run and --serve examples use the current live pgwire shell and final artifact path.

Seed JSONL is a contract/data pair, not a generator. --export-seed-contract writes a deterministic schema-shaped template for another agent to fill. --seed imports filled rows through the Postgres kernel and constraint executor before bootstrap finalization or live startup, so seeded rows become committed state in reports, snapshots, and the first run_once client session. V1 is schema-backed only: seed import/export cannot be combined with --restore, and --seed cannot be combined with --materialize-source-url.

Example Output

Human mode (default):

text
twinning postgres bootstrap readyendpoint: 127.0.0.1:5432schema: 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 backendverify: 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 mode (--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."}

Bootstrap reports show the validation-oriented next_step string above. When --run is present, the report switches to mode: "run_once" and points operators at the final run metadata instead.

Run-once mode (--run <COMMAND>):

json
{  "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."}

Interactive mode (--serve):

json
{  "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."}

Refusal mode (bootstrap/configuration failure):

json
{  "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"  }}

Why twinning exists

Two loops need the same primitive:

  • Extractor iteration. Agent-written extractors need a fast Postgres-behaving target that fails quickly on type coercion, constraint violations, and unsupported SQL shapes.
  • Migration proof. Later, the same kernel and snapshot contract should make historical-query replay and twin-pair migration proof possible without pointing legacy workloads at production.

You provide:

  • a schema DDL file or a prior snapshot
  • optionally a compiled verify.constraint.v1 artifact
  • later, a real client or extractor pointed at the twin

twinning returns:

  • one deterministic twinning.v0 report over the declared committed state
  • one content-addressed twinning.snapshot.v0 snapshot with canonical committed-state bytes; envelope metadata such as creation time and restore lineage remains explicit but is not the equality surface
  • explicit refusal behavior instead of silent partial semantics
  • later, protocol-visible runtime behavior for the canary-defined Postgres subset

What Exists Now

Implemented now:

Postgres twin (default):

  • DDL parsing with sqlparser-rs, deterministic normalized catalog construction
  • verify-artifact loading, bootstrap report and snapshot generation
  • pgwire listener + startup/session shell for the declared live subset
  • normalized read/mutation IR, row-store execution for canary-defined SQL shapes
  • live --run and --serve modes with SIGINT/SIGTERM finalization
  • embedded verify execution, twin-pair migration proof orchestration

REST twin (--features rest):

  • OpenAPI-spec-driven HTTP endpoint generation
  • auth shape enforcement (bearer/apiKey), chaos injection, routing modes
  • deterministic x-twinning.response-stubs for fixture-backed contract responses
  • canary manifest validation, startup report, port dual-twin migration proof

MCP twin (--features mcp):

  • JSON-RPC 2.0 dispatcher over HTTP and stdio transports
  • Catalog from live MCP server introspection or static manifest
  • All 7 MCP methods: initialize, tools/list, tools/call, resources/list, resources/read, prompts/list, prompts/get
  • Typed stub responses for tools with output schemas; unsupported_shape for stateful/schema-less tools
  • Auth enforcement, session log, startup report

Snowflake wire twin (--features snowflake):

  • Snowflake HTTP REST protocol (5 core endpoints)
  • Arrow IPC rowsetBase64 result encoding with full Snowflake type fidelity
  • SHOW and DESCRIBE responses for JDBC/DBeaver/dbt compatibility
  • DDL catalog ingestion, query dispatch with SqlRoute classification
  • Session lifecycle, startup report, materialize path

Not implemented yet:

  • SQL/session shapes outside the checked-in canary manifests
  • Joined reads (explicit protocol-visible refusal in current manifest)
  • Concurrent writers or multi-writer semantics
  • Heavier replay/proof backends beyond the in-memory snapshot-backed proof path

This means the repo can validate bootstrap assets, run one child command, or serve interactive clients for the proven subset, but it still refuses broader live traffic instead of pretending to be a complete database.


Runtime Contract

Command surface:

text
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 prooftwinning doctor [SUBCOMMAND]          # read-only health/capabilities

Current options:

  • --schema <FILE>: SQL DDL file defining tables, constraints, and indexes
  • --verify <FILE>: compiled verify.constraint.v1 artifact
  • --declaration <FILE>: optional twinning.catalog-declaration.v0 parent catalog subset identity
  • --host <HOST>: bind host (default 127.0.0.1)
  • --port <PORT>: bind port (default 5432)
  • --run <COMMAND>: run one child command against the live pgwire shell, then freeze final artifacts
  • --serve: run a standalone interactive pgwire shell until SIGINT/SIGTERM, then freeze final artifacts
  • --report <FILE>: write twinning.v0
  • --snapshot <FILE>: write twinning.snapshot.v0
  • --query-trace <FILE>: write a live query trace artifact, redacted by default, in --run or --serve
  • --capture-refused-statements: with --query-trace, capture refused Postgres SQL text only; the local trace may contain SQL literals, never bind values
  • --restore <FILE>: restore a prior twinning.snapshot.v0
  • --export-seed-contract <FILE>: write twinning.seed-contract.v0 JSONL for the schema-loaded Postgres catalog
  • --seed <FILE>: import filled twinning.seed-data.v0 JSONL as committed Postgres state
  • --materialize-source-url <URL>: capture declared source rows into the final report/snapshot
  • --json: emit machine-readable status
  • --describe: print operator.json

REST response stubs are declared inside the OpenAPI document under x-twinning.response-stubs and are consumed through the existing twinning rest --spec <FILE> path. They are deterministic contract fixtures: the runtime matches method, mounted path, and optional canonical JSON request body equality, then returns the declared status, headers, and JSON, text, or file-backed body after auth, chaos, and matched request-body validation checks. File-backed bodies use body-file and are validated at startup. They are not generated dummy data, not a live provider simulator, and not a separate REST --seed mode.

For matched JSON routes, the REST twin validates the declared OpenAPI requestBody.content.application/json.schema before response stubs, materialization, or unsupported_shape route refusal. Schema failures return deterministic request paths such as $.edges[0].downstream_key; malformed JSON and unsupported content types keep their existing refusal mappings. If a valid request reaches a non-materialized route, request_valid: true only means the request matched the declared request schema. It does not mean side effects were modeled or persisted.

Use separate specs or thin spec overlays to model separate API scenarios for the same upstream service, such as happy path, no-match, malformed/error, and ambiguity twins. The OpenFIGI fixture at tests/fixtures/rest/openfigi_v2_v3/response-stub-schema.yaml demonstrates a local /v3/mapping response that returns the OpenFIGI top-level batch array instead of the generic {"data":null,"warning":null} fallback.

Managed paths:

  • Canonical config location: ~/.cmdrvl/config/twinning/config.toml
  • Canonical tool-managed state directory: ~/.cmdrvl/state/twinning/
  • Canonical rebuildable cache directory: ~/.cmdrvl/cache/twinning/
  • Migration ledger and deprecation notices: ~/.cmdrvl/migrations/applied.jsonl and ~/.cmdrvl/notices/deprecated-paths.jsonl
  • Current inventory has no legacy twinning-managed home or repo config path to copy. Reports, snapshots, query traces, seed contracts, proof bundles, and protocol session reports are written only when the operator supplies an explicit output path.

Read-only doctor surface:

  • doctor health --json: emit twinning.v0 health diagnostics without reading schema, snapshot, or verify files
  • doctor capabilities --json: list machine-readable commands, output contracts, detector fixtures, and safety boundaries
  • doctor robot-docs: print concise agent-facing command notes
  • doctor --robot-triage: emit structured follow-up findings

doctor --fix is intentionally not available. The read-only doctor detector catalog is fixture-backed, and any future fix mode needs verbatim backups, explicit inverses, and undo tests before it is exposed.

Exit codes:

ExitMeaning
0clean bootstrap, run_once, or --serve completion without embedded verify failure
1live finalization completed but embedded verify reported FAIL
2refusal / bootstrap failure / CLI error

Live-shape discipline:

  • bootstrap/configuration failures stay process-level refusals
  • unsupported live protocol or SQL shapes become client-visible errors
  • the twin stays up after unsupported live traffic
  • reports and snapshots see committed state only

Spine Boundaries

twinning owns:

  • runtime/session behavior
  • materialized twin state
  • snapshots
  • raw twin-native metrics

twinning does not own:

  • claim resolution or canonicalization (decoding, canon)
  • constraint semantics (verify)
  • gold-set scoring (benchmark)
  • proceed/escalate/block decisions (assess)
  • evidence sealing (pack)

Critical boundary:

  • the live twin must execute embedded verify
  • it must attach raw verify.report.v1 payloads
  • it must not export state and shell out to batch verify
  • twin-pair proof reports may reference raw verify/benchmark/assess artifact identities, but must not score or reinterpret them
  • twin-pair proof cases include replay-result diff inputs with snapshot provenance, result hashes, and SQLSTATE parity, not timing-derived fields

Where twinning fits

Factory role:

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

Current development sequencing:

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

Related tools:

If you need...Use
Claim resolution and canonical mutation selectiondecoding
Constraint semantics and reportsverify
Gold-set scoringbenchmark
Policy decisionsassess
Evidence sealingpack

twinning only answers:

Can we materialize and exercise candidate state behind a protocol-faithful twin boundary for the declared subset?


Artifacts

Current artifact contracts:

  • twinning.v0 — bootstrap or later runtime report
  • twinning.snapshot.v0 — content-addressed snapshot
  • twinning.query-trace.v0: opt-in live query lineage artifact with SQL text redacted
  • twinning.query-trace.v1: opt-in refused-statement capture; refused SQL text may contain SQL literals and bind values remain redacted
  • twinning.twin-pair-proof.v0 — interface-equivalence receipt for two Postgres twins
  • twinning.twin-pair-replay-result.v0 — per-case replay diff inputs nested in twin-pair proof reports
  • twinning.twin-pair-replay-manifest.v0 — declared Postgres-subset replay manifest for twin-pair proof queries
  • twinning.twin-pair-orchestration-manifest.v0 — manifest-first twin-pair proof orchestration contract
  • twinning.canary-manifest.v0 — normative compatibility manifest for the supported subset

Checked-in manifest:

Schemas:

Snapshot contract highlights:

  • hashes include committed-state identity and canonical relation ordering
  • hashes exclude timestamps, live sessions, warnings, and debug strings
  • bootstrap snapshots remain catalog-only; run_once snapshots freeze committed relation contents for the executed subset

Refusal Codes

Refusals are structured errors with exit code 2. Each includes a code, message, detail, and (when applicable) a next_command suggesting what to run instead.

CodeWhenNext step
E_BOOTSTRAP_SOURCE_REQUIREDNeither --schema nor --restore providedAdd --schema schema.sql
E_AMBIGUOUS_BOOTSTRAP_SOURCEBoth --schema and --restore providedUse exactly one
E_ENGINE_UNIMPLEMENTEDNon-Postgres engine requestedUse twinning postgres ...
E_IO_READInput file not readableCheck path and permissions
E_IO_WRITEOutput file not writableCheck path and permissions
E_SCHEMA_PARSEDDL parsing failedFix SQL syntax in schema file
E_DECLARATION_PARSECatalog declaration malformed or mismatchedRegenerate the declaration for the selected schema
E_VERIFY_ARTIFACT_PARSEVerify artifact malformedRegenerate with verify
E_SNAPSHOT_VERIFYSnapshot hash mismatch or version errorRe-emit from schema source
E_SEED_BOOTSTRAP_SOURCESeed import/export requested with --restoreUse --schema
E_SEED_SOURCE_COMPOSITION--seed combined with --materialize-source-urlPick one source for v1
E_SEED_JSONLSeed JSONL is malformed or violates catalog/constraint rulesRegenerate or fix seed rows
E_REST_INVALID_X_TWINNINGREST x-twinning response stubs are malformed or target no mounted routeFix the OpenAPI x-twinning extension
E_TWIN_PAIR_PROOFTwin-pair proof inputs or query fixture are incompatibleUse snapshots with the same schema/catalog/declaration and a supported query fixture
E_SERIALIZATIONInternal JSON rendering failureReport bug

Refusals are never silent. If twinning cannot do what you asked, it tells you why and what to try instead.


What twinning Is Not

If you need...UseNot twinning
Claim resolution, canonical mutation selectiondecodingtwinning does not decide truth
Constraint semantics and validation rulesverifytwinning executes verify, it does not define constraints
Gold-set scoringbenchmarktwinning materializes state, it does not score it
Policy proceed/block decisionsassesstwinning reports, it does not adjudicate
Evidence sealingpacktwinning is runtime, not archive
A real Postgres instancedocker run postgrestwinning speaks the protocol for a narrow subset, it is not a database
A general SQL engineDuckDB, SQLitetwinning only supports canary-defined shapes

twinning only answers: Can this client run against a protocol-faithful twin for the declared subset, and what committed-state artifacts does that twin produce?


Installation

Homebrew (tagged releases)

Tagged releases publish twinning to cmdrvl/tap:

bash
brew install cmdrvl/tap/twinning

Until the first tagged release is cut, use the source build below.

From source (current)

bash
git clone https://github.com/cmdrvl/twinning.gitcd twinningcargo build --release# Binary at target/release/twinning

Cargo fetches the pinned cmdrvl/verify Git revision for verify-core and verify-engine; a sibling checkout is not required.


Agent / CI Integration

twinning is designed for agent-driven pipelines. Parse JSON output programmatically:

bash
# Check bootstrap readinessresult=$(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 routingcargo run -- postgres --schema schema.sql --jsoncase $? in  0) echo "clean bootstrap" ;;  1) echo "verify violations (future)" ;;  2) echo "refusal or error" ;;esac

Troubleshooting

FAIL outcome in run_once mode

The child command completed with a non-success exit, timeout, signal, or an embedded verify failure. Inspect the run metadata and any attached verify payload in twinning.v0, fix the candidate or supported-shape drift, and rerun.

E_SCHEMA_PARSE on valid-looking SQL

twinning uses sqlparser-rs for DDL parsing. Ensure your schema uses standard Postgres CREATE TABLE syntax. Extensions, custom types, and procedural SQL are not supported in v0.

E_SNAPSHOT_VERIFY hash mismatch

The snapshot was modified after creation, or was produced by a different twinning version. Re-emit from the original schema source with --schema and --snapshot.

E_ENGINE_UNIMPLEMENTED for mysql or oracle

Only the Postgres engine is implemented. MySQL and Oracle are declared in the CLI for forward compatibility but currently refused. See docs/PLAN_TWINNING_FUTURES.md for the roadmap.


Limitations (v0)

  • Postgres only. MySQL, Oracle, VSAM, IMS are deferred.
  • Canary-defined live shells only. --run and --serve bind pgwire for the manifest-backed subset; unsupported SQL and protocol shapes remain explicit live errors.
  • Canary-defined subset. Only SQL shapes named in the canary manifest will be supported.
  • No concurrent writers. The intended live model is single-writer admission with explicit contention refusal.
  • In-memory snapshot-backed proof orchestration only. Restore-backed and schema-plus-load proof endpoints are supported when the committed state fits the current memory budget; heavier replay/proof backends remain deferred behind the backend policy.

Repository Plan


Quality Gate

bash
cargo fmt --checkcargo clippy --all-targets -- -D warningscargo test./scripts/ubs_gate.sh

Built by CMD+RVL. Support: [email protected] or GitHub issues. Questions about filings or structured finance data? Chat with Cairn over text at textcairn.com.

來源:README.md,提交 3d7d463

工具

7

twin_doctor

Check the twinning binary and configured work directory for the declared-subset Postgres and spec-based REST twin server.

無需輸入參數。

twin_list

List retained Postgres and spec-based REST twins managed for the declared client subset.

無需輸入參數。

twin_pair_proof

Compare declared-subset Postgres-to-Postgres committed-state snapshots by replaying point lookups, filtered scans and aggregate counts from the supplied query file. Join cases are reported as skip. Oracle/TNS fidelity is deferred.

輸入參數report_pathqueries_path必填left_snapshot_path必填right_snapshot_path必填

twin_report

Read a bounded report for a stopped declared-subset Postgres or spec-based REST twin. Opt-in refused Postgres SQL text appears only here and can contain SQL literals.

輸入參數twin_id必填

twin_seed_contract

Create a seed contract for a schema supported by the declared Postgres subset.

輸入參數kind必填schema_path必填

twin_start

Start a Postgres twin for the declared client subset or a REST twin built from an OpenAPI spec; the REST twin refuses requests the spec does not define. Optional Postgres declaration_path sets catalog identity. Optional snapshot_path is written only when the twin stops. Opt-in refused SQL capture writes text only to the local trace file and twin_report; SQL text can contain literals, and bind values are never captured.

輸入參數kind必填auth_modeseed_pathspec_pathschema_pathttl_minutesverify_pathrestore_pathsnapshot_pathdeclaration_pathserver_variablescapture_refused_statements

twin_stop

Stop a managed declared-subset Postgres or REST twin and return its run summary.

輸入參數twin_id必填

版本歷史

1
  1. v0.7.1最新Nov 3, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分

其他 Cmdrvl 整合