Skip to main content

Bulla

Receipts for Agents.

Bulla creates portable ActionReceipts for consequential agent transactions. A receiving system can verify the record locally, apply its own ReliancePolicy, and reconcile the receipt set against its own event records.

Answerable-computing profiles for inference procurement, witnessed history, consequence rules, and correction networks live in repository source. They are not part of the installed package.

Glyph Standard publishes the ActionReceipt format, Bulla, and the public test suite.

The application creates the receipt where an action is accepted or completed: an API gateway, tool router, payment handler, or agent runtime. The model does not need to know about Bulla or write JSON.

Install and run one transaction

Bulla supports Python 3.10 and later. Receipt creation and file-integrity checks run locally and require no hosted Bulla service.

python -m pip install "bulla==0.48.0"
bulla demo

The fixed demo creates a receipt for one constructed USD 125 payment, checks the saved file, rejects an altered copy, and compares the receipt set with a separately supplied receiver record containing one additional action.

FIRST ACTION DEMO · CONSTRUCTED LOCAL SCENARIO

ACTION
recorded action       payments.charge
amount                USD 125.00
declared limit        USD 200.00

ALTERATION CONTROL
record integrity      FAILED
original receipt      UNCHANGED

OMISSION CONTROL
coverage before       1/1
coverage after        1/2
unreceipted action    pay_demo_043
original integrity    VERIFIED

The altered file fails its integrity check. The separate receiver record exposes an action with no matching receipt. Neither result establishes that funds moved or that the receiver record contains every action.

Use bulla demo --out DIR to choose a fresh output directory or bulla demo --format json for the versioned machine report. Bulla refuses to replace an existing path.

Provider logs and receiver records

Provider logs are useful, and Bulla does not replace them. They usually describe an activity stream inside the provider's system, use a provider-specific schema, and remain under the provider's custody.

An ActionReceipt has a different job: hand the receiving party one portable record for one transaction. If a provider exports the relevant event, binds it to the buyer's request and accepted terms, authenticates it, and lets the buyer retain it, that export can become evidence for an ActionReceipt. The standard format means a buyer does not need a different log integration for every provider.

Provider log ActionReceipt
Primary use Operate and debug the provider Hand one transaction to the receiving party
Custody Usually controlled by the provider Retained by each receiving party
Format Provider-specific Open and versioned
Scope System activity stream One action or transaction
Verification Whatever the provider exposes Local checks defined by the format
Completeness Not assumed Not assumed

Buyers, gateways, and marketplaces can require receipt support before routing work or accepting a delivery. A provider that supports the format can qualify for those workflows and use the same agreed transaction file for acceptance, audit, and disputes. This repository does not claim that receipts improve payment speed, insurance pricing, or reputation.

The receipt is not the decision

An ActionReceipt preserves the request, accepted permissions and limits, reported result, and supplied evidence. It does not make the next decision. The customer, auditor, marketplace, or downstream agent applies its own policy to the retained record.

An eligible consequence is still separate from authority to execute it. A receipt does not establish that the reported event occurred or that the receiver record contains every relevant event.

Add Bulla where the application acts

wrap_action creates the JSON file around the application call:

from bulla import wrap_action

with wrap_action(
    "payments.charge",
    {"event_id": "pay-1", "amount_minor": 12500},
) as action:
    action.set_result("sha256:" + "0" * 64)

receipt = action.receipt

The receipt can record the action claim, declared authority and limits, supplied evidence references, and challenge path. The exact fields are defined by the ActionReceipt standard.

Verify one receipt

Download the constructed payment receipt and check it locally:

curl -fsSLo constructed-payment-authorization-v0.2.json \
  https://glyphstandard.com/examples/payment-authorization-v0.2.json
bulla receipt verify constructed-payment-authorization-v0.2.json --format json

The receipt records a USD 125.00 charge, declares a USD 200.00 limit, and carries an executable rule for checking the limit. The dimensional report includes:

integrity             VERIFIED
authenticity          UNVERIFIED
authority             UNAUTHENTICATED
declared_bounds       CONFORMS
grounding             SELF_ASSERTED
recourse              NAMED
reachability          UNVERIFIED
reliance_decision     NOT_COMPUTED

These are separate results, not one global safety or truth verdict. The same receipt is available at spec/vectors/payment-authorization.json; its expected result is pinned in spec/vectors/expected.json and recomputed in CI.

Check receipt coverage

event_coverage compares valid receipts with a receiver record supplied outside the receipt set. For an exact saved-record match, add record_sha256 using observed_record_sha256; the receipt must carry the same digest in its result or evidence references. Without that field, coverage is action-ID correlation.

from bulla.action_receipt import verify_receipt
from bulla.coverage import event_coverage
from bulla.wrap import receipt_for

receipt = receipt_for("network.egress", {"event_id": "action-001"})
assert verify_receipt(receipt).ok

complete = event_coverage([{"id": "action-001"}], [receipt])
assert complete["coverage"] == 1.0
assert complete["unreceipted_delta"] == []

with_gap = event_coverage(
    [{"id": "action-001"}, {"id": "action-002"}],
    [receipt],
)
assert with_gap["coverage"] == 0.5
assert with_gap["unreceipted_delta"] == ["action-002"]

Receipt integrity is unchanged in the second comparison. The supplied receiver record contains one action with no matching receipt. Bulla does not establish that the record itself is complete.

Apply a receiver policy

ReliancePolicy turns a complete verification view into RELY, REFUSE, or ESCALATE. Bulla publishes strict and pragmatic policies, plus an evidence-strict policy that requires both a third-party-anchored or execution-verified label and the receiver's acceptance of the exact evidence digest/class pair through separately supplied grounding context.

from bulla import (
    EVIDENCE_STRICT_RELIANCE_POLICY,
    decide,
    receipt_for,
    verify_receipt,
)

receipt = receipt_for("network.egress", {"event_id": "action-001"})
verification = verify_receipt(receipt)
decision = decide(verification, EVIDENCE_STRICT_RELIANCE_POLICY)
assert decision.outcome == "refuse"
assert {item["dimension"] for item in decision.unmet} >= {
    "verified_to", "effective_grounding"
}

The application chooses the policy and decides what downstream action follows. Receipt-carried grounding labels do not satisfy the evidence-strict policy by themselves. After validating an anchor or recomputing evidence, a receiver may pass its resulting verified_evidence_grounding mapping to verify_receipt. That external context is a receiver input, not a fact the packet may supply. When the receiver records the result as a bulla.rely receipt, Bulla binds the exact context hash into the signed subject; replay verification requires the same context as a separate input. A serialized verification view cannot promote its own grounding status. Even then, a grounding class does not establish occurrence, worldly truth, organizational independence, custody, settlement, or downstream effect.

Keep the verification kit

The package carries the v0.2 specification, constructed examples, expected dimensional reports, and a zero-dependency checker as one immutable archive:

bulla receipt kit --out action-receipt-v0.2-verification-kit.zip

Expected archive digest:

sha256:8f2cdd16bcbd1a1121f49545b6a6512872b188221ca30ec054dfd6b2fb2142ab

After extracting the archive, run python3 verify.py to check the kit or run its standalone checker against a saved v0.2 receipt:

python3 verify.py receipt RECEIPT.json --format text

The checker imports no Bulla code and makes no network request. The manifest checks the archive contents. Authenticate the archive itself with the detached digest or signed release receipt.

bulla receipt drill runs both the installed Bulla checker and the retained standalone checker while network access is denied:

bulla receipt drill RECEIPT.json --format text

Published package and source profiles

Bulla 0.48.0 ships ActionReceipt creation and verification, explicit reliance policy, and coverage reconciliation. The following examples are experimental repository-source profiles. They do not add installed commands or stable Python exports.

Experimental: evaluate one receiving policy

The source-only Acceptance Contract alpha demonstrates an agent-to-agent deployment handoff. A deploy agent reports that staging is ready; the receiving release policy also requires a rollback-test record for the exact build and contract. Missing evidence produces a conditional request, PASS permits eligibility, and FAIL refuses it. Even the eligible result leaves authorization unissued and execution unattempted.

PYTHONPATH=src python3 examples/acceptance-contract/run_demo.py \
  --story --out /tmp/bulla-acceptance
python3 -I spec/acceptance-contract/check.py \
  /tmp/bulla-acceptance/missing \
  --context /tmp/bulla-acceptance/context.json \
  --format story

This profile is inspectable in source and excluded from the installed package.

Experimental: trace a correction through declared reliance

The source-only Reliance Map profile starts from an accepted declared graph. When an authenticated correction notice targets one source digest, the verifier identifies the exact descendants that require rechecking. Complete branches with no declared path are reported separately; incomplete lineage remains unresolved.

The constructed corpus contains 10,000 declared decisions: 2,500 require rechecking, 5,000 have no declared path under the accepted graph, and 2,500 remain unresolved because their lineage is incomplete. Python and standalone Node produce the same report.

PYTHONPATH=src python3 spec/reliance-map/check.py \
  spec/reliance-map/generated/graph.json \
  --ledger spec/reliance-map/generated/correction-ledger.json \
  --context spec/reliance-map/generated/context.json

node spec/reliance-map/check.mjs \
  spec/reliance-map/generated/graph.json \
  --ledger spec/reliance-map/generated/correction-ledger.json \
  --context spec/reliance-map/generated/context.json

The map does not capture dependencies automatically, establish that a correction is true, reverse an action, or authorize a consequence. The profile and its Handoff Admission parsing dependency are excluded from the installed package.

Experimental: bind recourse to witness equivocation

The source-only Witness Covenant profile binds a dedicated test-ledger allocation to one objective fault: two authentic, same-size checkpoints for the same log and epoch carry different roots. The verifier keeps checkpoint authenticity, equivocation, challenge state, capital, eligibility, authorization, and an attempted ledger event separate.

A bond changes recourse only. It does not make a receipt true, make the witness independent, establish custody or collection, or upgrade a provider claim.

PYTHONPATH=src python3 spec/witness-covenant/check.py \
  spec/witness-covenant/vectors/fork-closed \
  --context spec/witness-covenant/contexts/fork-closed.json

node spec/witness-covenant/check.mjs \
  spec/witness-covenant/vectors/fork-closed \
  --context spec/witness-covenant/contexts/fork-closed.json

Experimental: verify an answerability network

The source-only Answerability Network profile composes a constructed inference procurement, ActionReceipt, witnessed checkpoint, covenant, and 10,000-decision declared reliance graph. When the verifier receives two authentic incompatible checkpoint views, it identifies 2,500 declared descendants for recheck, leaves 5,000 complete unrelated decisions unaffected under the accepted graph, and keeps 2,500 incomplete branches unresolved.

Only the witness covenant's bounded remedy can become eligible. Provider claims and unrelated branches do not inherit the witness fault.

PYTHONPATH=src python3 spec/answerability-network/check.py \
  spec/answerability-network/vectors/fork-closed \
  --context spec/answerability-network/contexts/fork-closed.json

node spec/answerability-network/check.mjs \
  spec/answerability-network/vectors/fork-closed \
  --context spec/answerability-network/contexts/fork-closed.json

Where Bulla fits

  • Payments: record the request, authorization, amount limits, supplied evidence, and dispute path.
  • Permissions and writes: bind an operation to its stated principal and policy.
  • Gateways and provider handoffs: retain the request and terms that crossed an organizational boundary.

ActionReceipt v0.2 remains the normative default. ActionReceipt v0.4 is an opt-in experimental draft. Source-only research profiles remain inspectable on GitHub but are excluded from the installed package unless the distribution policy explicitly releases them.

Limits

  • File integrity does not establish that the reported action occurred or that every recorded field is true.
  • A signature authenticates an accepted key; it does not create authority.
  • Coverage is relative to the supplied receiver record.
  • Bulla does not establish that the supplied receiver record is complete.
  • Unsigned receipts remain unauthenticated.
  • Reliance remains NOT_COMPUTED unless a reliance policy is supplied.

Multidimensional reports reject Boolean coercion. Callers inspect the named dimensions or apply an explicit reliance policy.

Documentation

License and security

Bulla is the developer toolkit. ActionReceipt is the open format implemented by Bulla. Glyph Standard, Inc. maintains the specification; Res Agentica contains the broader research program.

Bulla is licensed under the Apache License 2.0. Report vulnerabilities privately through GitHub Security Advisories or the security policy.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bulla-0.48.0.tar.gz (5.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bulla-0.48.0-py3-none-any.whl (797.5 kB view details)

Uploaded Python 3

File details

Details for the file bulla-0.48.0.tar.gz.

File metadata

  • Download URL: bulla-0.48.0.tar.gz
  • Upload date:
  • Size: 5.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bulla-0.48.0.tar.gz
Algorithm Hash digest
SHA256 82d21b4346e8c41609988c875db7f79f337cd4995a043e7c41d8a1c000cac94c
MD5 2c7ff8501894f0dd5cef020cfbfe270d
BLAKE2b-256 2462a83622364f34ca0f32ca26e0d2daa1c12c043921625bb679131f029685d1

See more details on using hashes here.

Provenance

The following attestation bundles were made for bulla-0.48.0.tar.gz:

Publisher: publish.yml on jkomkov/bulla

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bulla-0.48.0-py3-none-any.whl.

File metadata

  • Download URL: bulla-0.48.0-py3-none-any.whl
  • Upload date:
  • Size: 797.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bulla-0.48.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d74aaf2bcc73a0a145bdec0c0aca1b66b862a046f3ace174d1b56100cb33c169
MD5 49e99fd48457de461dedfd98ff4a71e6
BLAKE2b-256 b04afc99cb64c318ac2af4e0942f2f3593b0d3a53d0bd53673cf1f26b9f82b26

See more details on using hashes here.

Provenance

The following attestation bundles were made for bulla-0.48.0-py3-none-any.whl:

Publisher: publish.yml on jkomkov/bulla

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.48.0 This release

2 files

0.47.1

2 files

0.46.0

2 files

0.45.1

2 files

0.44.4

2 files

0.44.1

2 files

0.44.0

2 files

0.43.0

2 files

0.42.0

2 files

0.41.0

2 files

0.40.0

2 files

0.37.0

2 files

0.36.0

2 files

0.35.0

2 files

0.34.0

2 files

0.33.0

2 files

0.32.0

2 files

0.24.0

2 files

0.23.0

2 files

0.22.0

2 files

0.21.0

2 files

0.20.0

2 files

0.19.0

2 files

0.18.0

2 files

0.17.0

2 files

0.16.0

2 files

0.15.0

2 files

0.8.0

2 files

0.7.1

2 files

0.7.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page