Seal

io.github.aurumflux20由 GitHub 帳號 aurumflux20 發布v0.5.0更新於 Oct 24, 2026

Stops agents double-charging across processes: exactly one execution, confirmed by the provider.

概覽

AI 產生的概覽

Seal 是本地 MCP 伺服器兼 Python 函式庫,為助理提供 12 個工具,透過 Postgres 確保付款等不可逆動作只執行一次。

可以做什麼
  • 准入、提交、中止與心跳不可逆動作,確保只有一個呼叫方勝出,閘道模式下使用一次性票據
  • 透過閘道提出並執行動作,由閘道而非代理持有供應商憑證
  • 查詢並驗證封存憑證,包含防竄改雜湊鏈與可攜式簽章收據
  • 登記並巡檢宣告的義務,將未履行的職責標記為違約
  • 查看某條支付路徑已取得的自主等級與放行狀態
適用情境
當多個代理或多台機器可能同時觸發同一不可逆動作(例如扣款、撥款),需要共用儲存判定唯一贏家並留下執行證據時適用。也適合需要對涉及資金的工具呼叫做雙人覆核與稽核收據的團隊。
執行需求
以本機程序透過 stdio 執行(Python 套件 seal-kernel,或 Docker 映像)。沒有環境變數時僅提供自省模式;實際准入動作需要 SEAL_DSN 中的 Postgres 連線字串,閘道模式另需 SEAL_EXECUTORS。選用簽章需安裝簽章附加元件並設定 SEAL_SIGNING_KEY。原始碼測試腳本需 Python 3.10 以上。
安裝前請注意
它管理資金流動:閘道模式會呼叫支付供應商並可能動用真實資金,請先以測試模式金鑰驗證。供應商金鑰存放在閘道自身環境中,同主機上能讀取該環境的程序仍可竊取。已取得自主與分級放行可能讓路徑無人值守執行,需留意額度上限與撤銷。README 另宣傳付費的一致性測試與審查服務。

安裝

在 SourceWeft 中

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

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

其他 MCP 客戶端

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

README

seal

Public register: the Retry-Safety Index lists which agent-payment implementations pay once when the answer is lost — verified safe, found & fixed (with time-to-fix), and how to get verified. Every row links to its proof.

Your agents earn the right to spend without you.

Seal is not Coherence

Seal and EffectFence stop an irreversible action from firing twice while it happens — runtime enforcement on money movement. Coherence never touches your runtime; it reads the record afterwards and grades what an agent claimed against what it proved. Prevention versus proof. Different problems, different code, no overlap.

Free: submit any client, facilitator, SDK or toolkit that moves money — yours or someone else's — and we read it and publish a verdict on the Retry-Safety Index at no cost. Findings come back with the mechanism, the file and line, and a failing test. You are counted, never named, until you ship a fix. Submit for grading →

Seal is an MCP server (seal-mcp, stdio, JSON-RPC 2.0) — and a Python library. It gives an MCP host 12 tools for exactly-once execution of irreversible actions: seal_propose, seal_execute, seal_paths (gateway mode — the agent holds a single-use ticket, never the provider key), plus seal_admit, seal_commit, seal_abort, seal_heartbeat, seal_get, seal_verify, seal_incident_receipt, seal_expect, seal_obligations.

bash
docker run -i ghcr.io/aurumflux20/seal          # or: python -m seal.mcp_server

It starts in introspection-only mode with no environment — initialize and tools/list answer with no database, so a host or registry probe can connect immediately. Set SEAL_DSN to a Postgres DSN to actually admit actions, and SEAL_EXECUTORS=your.module for gateway mode.

jsonc
// claude_desktop_config.json{ "mcpServers": { "seal": { "command": "python", "args": ["-m", "seal.mcp_server"],                            "env": { "SEAL_DSN": "postgres://..." } } } }

Not an engineer? Read docs/PLAIN-ENGLISH.md instead — the same thing with no jargon, including what we can't do.

Everyone else ships a lock: a spend cap you set once and forget. The cap never learns, so an agent that has settled ten thousand clean payments is trusted exactly as little as the one you installed this morning — and you keep clicking Approve.

Seal ships the unlock. It reads what a payment path has actually proven — settlements the provider confirmed, sweeps showing nothing moved behind its back — and computes the autonomy that path has earned. L0 OBSERVED → L5 AUTONOMOUS. Nobody types the level.

████████············  L2 ASSISTED      50 proven · 100% confirmed   [human required]     fifty settlements — but volume alone is not trust.████████████········  L3 DELEGATED     50 proven · 100% confirmed   [unattended]     one clean sweep later: the human stops clicking Approve.····················  L0 OBSERVED      50 proven · 100% confirmed   [SUSPENDED]     one charge the gateway never admitted. fifty clean ones don't outweigh it.
bash
SEAL_DSN="..." python3 license_demo.py     # watch a path earn L3 and lose it

Since 0.4.0 the licence drives the wheel, not just the dashboard. Turn on earned autonomy — Gateway(seal, earned_autonomy=True), or SEAL_EARNED_AUTONOMY=1 for the MCP server — and the gateway lets a path move money unattended only to the extent its own record has earned (L3+), inside the operator's ceilings, never above them. Three things hand the wheel back to a human instantly: a path that hasn't earned it yet, a suspension (money moved behind the gateway's back), and a hold — an execution reached the provider and its outcome is unknown, so the path pulls over until settle() has asked the provider what happened. The hold lifts by itself once the world answers. A human can still approve any single action through the same maker-checker door (tier=LICENCE). Off by default: nothing changes until you switch it on.

Can you prove your agents won't double-charge a customer? Three rungs, one ladder, written-only: a $300 founding conformance run — your implementation through the battery, result published on the Index (first three only; book) · a $1,200 attestation run — your live endpoint against every ambiguous outcome, signed result, findings within five business days, a clean run signed within 24 h (book) · a $12,000 fixed-scope money-path review — one production money path read, tested and attested in 7–10 days, no invoice if no real double-fire is shown on a path you run. For a free self-check first, hostile-facilitator tells you in 60 seconds.

Slow to earn, instant to lose — the only shape that makes a track record mean anything. The full level definitions: docs/AUTONOMY-LEVELS.md.

Seal's ambiguous-outcome doctrine — "could not determine" is terminal, never absent — is now §4.3 of the draft MCP retry-safety proposal, co-authored by us, with our conformance battery as its test suite.

Underneath: exactly-once admission

Two different agents, on two different machines, both decide to charge order 123 at the same instant. In-process idempotency can't help — the guard has to live in a store both agents talk to, and the winner has to be decided atomically there.

Seal is that layer. One Postgres, one row per intent, one winner:

INSERT ... ON CONFLICT DO NOTHING     -- one row, one winner, no check-then-act window

Every admitted action ends in a certificate: a content-addressed hash over intent + args digest + result digest + the previous cert's hash. Editing, deleting or reordering any cert breaks every hash after it — and anyone with the DSN can check, with no network and no trust in us:

bash
SEAL_DSN="..." python3 -m seal verify# chain VERIFIED — 41 cert(s), every link intact   (exit 0; broken chain → exit 1)

The proof

The claim is tested the hostile way: 1,000 real threads released by one barrier against one shared Postgres, where the "charge" increments a measured counter — if two callers run, the counter says 2 and the test fails loudly.

Result, four consecutive runs: ACTUAL_EXECUTIONS = 1. Every loser either replayed the sealed cert, stood down mid-flight, or failed safe when the store was unreachable. A 50-caller post-seal wave: all replayed, none re-ran. Full numbers, including the honest limits: STORM-PROOF.md.

Run it yourself:

bash
pip install seal-kernel
export SEAL_DSN="host=... dbname=seal"python3 -m seal verify          # chain check, no network, no trust in us

To run the 1,000-thread storm proof yourself, clone the repo (the harness ships with the source, not the wheel):

bash
# Needs Python 3.10+. macOS ships 3.9 with pip 21, which fails an editable# install with a misleading "setup.py not found" error — use a venv rather# than debugging that.git clone https://github.com/aurumflux20/seal && cd sealpython3 -m venv .venv && source .venv/bin/activatepython3 -m pip install -U pip && python3 -m pip install -e .
export SEAL_DSN="host=... dbname=seal"python3 storm.py --n 1000

Test YOUR server, not just ours

The exact harness above, generalized into a standalone file with zero dependency on this repo — copy it, point it at your own write-bearing tool, and find out for yourself:

bash
python3 range_safety_test.py --n 1000

It demonstrates itself against a known-unsafe target and a known-safe one before you ever run it for real, so a pass means something. Full writeup, including the three ways an early version of this test lied to us before it was fixed: docs/RANGE-SAFETY-TEST.md.

Usage

python
from seal import Seal
seal = Seal(dsn); seal.setup()
adm = seal.admit("charge", {"order_id": "123", "amount": 4900})if adm.fresh:                     # you won — run the effect, then seal it    result = stripe_charge(...)    cert = seal.seal(adm.intent, adm.fence, result)elif adm.cert is not None:        # already done — here is the receipt    return adm.certelse:                             # someone else is mid-flight — stand down    raise InFlight()

If the effect fails before anything irreversible happened, release the claim so a retry is legitimate: seal.fail(adm.intent, adm.fence, reason).

When a holder dies mid-effect (its lease expires with the intent still open), the next admit() does not hand out a fresh claim. Nothing in an expiry says whether the holder crashed before the provider answered or is still inside a slow provider call, so re-running it would be executing on an unknown outcome — the one thing Seal promises never to do. You get fresh=False, cert=None, reason="lease expired with no witness…"; resolve it with a witness (Gateway.register_witness, or seal.settle(intent, witness)) which heals the record if the effect landed and releases it if it did not. Seal(dsn, blind_reclaim=True) restores the old takeover for providers that are idempotent by construction. The gateway heartbeats the lease for the whole provider call, so a slow Stripe call keeps its claim instead of losing it.

World confirmation — measured against live Stripe, not mocked

A cert saying "admitted once" is a claim about us. The next question is what Stripe (or Resend, or your bank's webhook) actually recorded — and the answer is allowed to disagree with us.

bash
export SEAL_DSN="host=... dbname=..."export STRIPE_TEST_KEY="sk_test_..."   # your own test-mode key, Dashboard -> API keyspython3 stripe_demo.py

What it does, against your real Stripe test account, no mocks:

  1. Two agents fire the same charge at the same instant. Seal admits one. Exactly one real PaymentIntent is created.
  2. The witness asks Stripe: "how many charges carry this intent?" Stripe says one → the cert upgrades to WORLD_FINAL.
  3. A rogue charge is created outside the gateway — the thing no local fence can stop on its own. The witness asks again; Stripe now says two → the cert becomes WORLD_DIVERGED, the domain freezes, and further spend on it is refused automatically.

Two honest things the live run taught us, both fixed and both tested: Stripe's search index is eventually consistent (a fresh charge can take real seconds to appear — the witness polls to a definitive answer rather than ever recording a "not indexed yet" empty read as authoritative absence), and once the world has contradicted the ledger, a later flaky re-count must never quietly downgrade the cert back to WORLD_FINAL — divergence is sticky by design.

Pre-commit world freeze — don't act on facts that already moved

admit() has always taken a read_set — the world facts a decision depends on (a cart total, an inventory count) — and stored it on the cert. Until now nothing ever checked it: a caller who believed they had staleness protection had none. Same defect shape as a bug fixed earlier the same day, one layer up — a guard present in the schema, never enforced.

python
from seal.freshness import CallableChecker
fresh = CallableChecker(lambda rs: current_cart_total(rs["order_id"]) == rs["total"])
adm = seal.admit("charge", {"amount": 5000}, key="order-777",                 read_set={"order_id": "777", "total": 5000}, checker=fresh)# StaleWorldRead is raised BEFORE a fence is granted if the checker says no —# nothing runs on facts that already changed. Gateway.propose() takes the# same read_set/checker kwargs and passes them straight through.

Enforcement point is deliberate: before the fence, not after the effect ran. Checking afterward could only refuse to claim success — it can't stop money moving on stale information, which is the actual failure this exists to prevent. Opt-in and backward-compatible, same rule as everywhere else in this library: only engages when the caller supplies both read_set and checker. Honest limit, printed where it applies rather than left to be discovered: the checker call itself can't be made atomic with the admission INSERT, so a change landing in that narrow gap is a residual window — the same caveat class as a witness's eventually-consistent provider index.

Clearance — permission that has to be earned, not declared

The fence proves an action ran once. Clearance is the layer above it that a company actually buys: which tool paths may an agent fire unattended, and on what evidence.

python
from seal.clearance import Clearance, CLEARED
cl = Clearance(seal)cl.set_policy("charge", CLEARED)                       # an operator's intentcl.record_proof("charge", green=True, storm_n=1000, executions=1)  # from CI
cl.status("charge")["effective"]   # CLEARED — but only because both are true

The rule that makes this more than a toggle: CLEARED is earned, not declared. A path only reports effectively CLEARED if an operator set it and a green storm proof was recorded recently enough. Let the last proof go red, or let it go stale, and status() reports HOLD on its own — nobody has to remember to downgrade it. REVOKED always wins, never auto-recovers, and revoke_all() is one switch that stops every known path at the choke. A range_report() exports counted events and provider-cited certs — the artifact a security questionnaire or a CFO actually reads.

Exclusive Authority — agents get tickets, never the credential

Clearance is policy. Policy an agent can walk around if it still holds sk_live itself isn't a rail, it's a suggestion. Exclusive Authority removes the credential from the agent entirely.

python
from seal.authority import Gateway
gw = Gateway(seal)gw.register_executor("charge", lambda args: stripe_charge(args))  # secret lives HERE only
prop = gw.propose("charge", {"amount": 4900}, key="order-777")if prop["status"] == "cleared":    result = gw.execute(prop["ticket"], {"amount": 4900})  # gateway calls Stripe, not the agent

An agent calls propose() and gets back a ticket — proof an intent was admitted, cleared, and budgeted — never a secret. execute() is the only place the provider is ever called, and the ticket is bound to the exact args that were cleared: it's rejected if what you hand execute() doesn't match what was proposed, single-use, and expires. (The first cut of this didn't bind args to the signature and would have let a ticket cleared for $1 be spent on any amount — found by attacking our own build before it shipped, not after.)

Custody model, stated plainly: the gateway runs inside your own infrastructure. AurumFlux never holds, sees, or transports your provider secret — we ship the software that takes the key out of the agent's hands; we do not become a vault ourselves. Honest limit: a process on the same host that can read the gateway's own environment can still steal the secret. This raises the bar to "steal from the vault," not to physical impossibility.

Graduated Clearance — maker-checker for the amounts that matter

Binary CLEARED is enough for a $5 API call. It is not what a finance org signs off on for a $50,000 payout — they sign off on segregation of duties: the person who proposes a spend is never the person who approves it, on the record. Graduated Clearance adds thresholds on top of Clearance:

python
from seal.graduated import GraduatedClearance, APPROVE
gc = GraduatedClearance(seal)gc.set_thresholds("payout", auto_ceiling=100, dual_ceiling=10_000, required_approvers=2)
# amount 50   -> AUTO, ordinary Clearance applies# amount 5000 -> DUAL, needs 2 distinct human approvals before it can executer = gc.request("payout", 5000, maker="alice", intent=intent)gc.add_vote(r["id"], "bob", APPROVE)gc.add_vote(r["id"], "carol", APPROVE)   # now APPROVED — a THIRD person, not alice

Wired into the gateway: Gateway.propose(..., amount=X) on a path with thresholds configured returns {"status": "needs_approval", "tier": "DUAL"} instead of a ticket until a satisfied approval_id is supplied. The maker cannot approve their own request — enforced in code, not policy — and one approver cannot be counted twice even under a genuine concurrent race, because it's a Postgres UNIQUE constraint on (approval, approver), not an app-level check. A single reject is terminal. An approval authorises exactly one execution and is bound to the exact intent it was requested for. Every decided approval — approved or rejected, with every vote — is appended into the same hash chain the execution certs live in, so seal verify covers governance decisions the same way it covers what actually ran.

Backward-compatible by design: a path nobody ran set_thresholds() on never triggers graduated clearance, even if propose() is called with an amount — existing budget-only integrations are unaffected.

Run the whole story end to end — no payment provider needed, nothing charged:

bash
python3 approval_demo.py

A $200 purchase clears on its own; $12,000 is refused until two distinct humans approve; the requester is refused when they try to approve their own; a duplicate vote from the same approver is refused; one reject is terminal; $250,000 is never automatic; and one revoke stops even the $200 path. It ends on the Range Report, which states approvals in money — approved and rejected totals — rather than a count of event kinds.

Portable receipts — evidence that leaves the building

The dispute that matters spans three parties — the user who authorised an agent, the operator who ran it, and the merchant who got paid — and each holds a database the other two cannot read. seal verify answers "did this run exactly once, and did the world confirm it?", but only to someone holding the DSN, which is to say only to the party being asked to prove its own innocence.

A portable receipt is that answer as a file. Certs are hashed over RFC 8785 canonical JSON and (with a key configured) Ed25519-signed at write time, so a counterparty verifies them with no database, no network, and none of our code — docs/verify-receipt.mjs does it in ~30 lines of Node:

bash
pip install 'seal-kernel[signing]'python -m seal keygen                     # SEAL_SIGNING_KEY= secret · public key= publish itpython -m seal export --intent <id> > receipt.jsonpython -m seal verify-receipt receipt.json --pubkey <hex>    # needs NO DSNnode docs/verify-receipt.mjs receipt.json <hex>              # or no Python at all

Honest limits, on the verdict itself: a pinned-key pass proves these certs were produced by the key holder and are unaltered — it cannot prove completeness (whether other certs exist takes the chain check against the store), and an unpinned pass proves internal consistency only, never authorship. Signing is opt-in; an unsigned store keeps working exactly as before, and v1 certs keep verifying next to v2 forever.

settle() — deduplication is not settlement

Idempotency keys make retrying the same request safe. They do not answer what happened after a timeout where the provider may already have acted. That intent sits open, and before settle() the only resolution was implicit — a future admit(heal_with=…) some caller might never make. Now it is one verb:

python
gateway.settle(intent)      # uses the path's registered witness# CONFIRMED_ONE → healed to WORLD_FINAL, budget reservation settled# ABSENT        → claim released for a clean retry, budget returned# MULTIPLE      → WORLD_DIVERGED on the chain, domain frozen# UNKNOWN       → unresolved, loudly — the claim stands, nothing is guessed

Obligations — the alarm for what an agent FAILS to do

Every guard above — and every agent-safety tool we know of — watches commission: the double-charge, the overspend, the contradiction. Nothing watches omission. An agent that crashed, lost its key, or silently stopped looks exactly like an agent with nothing to do — until payroll doesn't go out, or the refund that was legally due in 14 days quietly doesn't happen.

This repo already refuses that failure mode for its tests (conftest.py: a run where everything skipped is not a pass). Obligations apply the same sentence to production money. It is the dual of the reconcile sweep:

reconcile:    provider effects − admitted intents = out-of-band  (did too much)obligations:  declared duties  − sealed intents   = BREACH       (did too little)
python
from seal.obligation import Obligationsobs = Obligations(seal); obs.setup()
# at decision time, the agent binds its future self:obs.expect(action="refund", key="return-123", due_in_sec=14*86400,           description="statutory refund window for return #123")
# the business heartbeat:obs.expect_recurring(action="renewal", every_sec=86400, min_count=1)
obs.sweep()   # or: python -m seal obligations   (exit 1 on any open breach)

What makes a miss more than a dashboard row: the breach itself is appended to the tamper-evident chain (deleting it breaks every hash after it), and obligation_breached is a licence-suspending event — a path that goes silent on declared work loses its earned autonomy exactly like a path that double-charged. Declaring duties is open to agents (seal_expect over MCP); cancelling one is an operator act with no agent-facing tool, because an obligation an agent could cancel is not an obligation. A breach deliberately does not freeze the path — a frozen refund path cannot cure a missed refund; the levers are evidence, alarm, and the licence.

What a Seal cert does and does not claim

A cert proves the action was admitted exactly once at this gateway and that the recorded result hasn't been altered since. It does not prove the outside world settled it — every v1 cert carries world: "unconfirmed", permanently and on purpose. "We admitted this once" and "Stripe took the money" are different claims; conflating them is exactly the bug class this tool exists to stop. World confirmation (provider adapters that flip that field against Stripe's or your provider's own records) is the next layer, and the cert schema already carries the field so the format won't break.

Relationship to once-kernel, effectfence, and coherence

once-kernel proves one process didn't run an effect twice. effectfence guards one MCP server. Seal is the cross-process layer above both, for the moment your agents outgrow a single machine. The free primitives stay free (Apache-2.0 / MIT), forever.

For claim vs proven on agent PRs and CI (said it ≠ showed it), see the separate project coherence — not part of this repo; different package, different git history.

License

Business Source License 1.1: read it, run it, use it in production internally (commercial included) — just don't resell it as a hosted service. Converts to Apache-2.0 on 2030-08-12.


mcp-name: io.github.aurumflux20/seal

來源:README.md,提交 4259474

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

1
  1. v0.5.0最新Sep 16, 2026

評分

已滿足適用檢查項的 40%

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

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

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

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分

    請在儲存庫或註冊中心條目中宣告授權條款。