The protocol is portable. The supported implementation is explicit.
Makoto ships as source: a Python reference library and command-line interface in the core repository, pinned on this site to revision 276008eeec0f. Every language binding and platform integration here drives that one implementation, so a Bash step, a Go sidecar, and an Airflow DAG reach the same decision on the same bundle. There is no published package on PyPI, npm, or the Go module proxy.
| Interface | Current state | Use today |
|---|---|---|
| Command-line interface | Implemented and tested in the core repository | Every protocol operation: keys, origin and transformation statements, handoffs, schema validation, and bundle verification. |
| Python library | Reference implementation in the source tree; internal modules are not a stable API | In-process verification from inside a pinned checkout, when a subprocess per bundle is too costly. |
| Bash, Python, JavaScript, TypeScript, and Go bindings | Documented, executed recipes over the CLI and its JSON report | Gate a job, service, or CI step on a verdict today, with install, attestation, verification, denial handling, and report reading. |
| JavaScript and browser | Interface research; no published package | Server-side verification through the JavaScript binding. A native browser verifier is open work. |
| Go and other native verifiers | No maintained SDK claimed | Start from the schemas, conformance fixtures, canonicalization rules, and published diagnostic codes. |
| Pipeline platforms | Runnable patterns, not shipped adapters | Nine platforms wired through one shared helper, each page stating exactly how it was tested. |
Choose your language
How verification decides →Each binding is one complete program that was run against the pinned core before publication, with its real output shown. All five follow the same six steps: install, validate structure against the hosted schemas, sign an origin statement, verify a handoff bundle, refuse a tampered copy, and read the report.
Pipeline steps and CI
A complete script plus a GitHub Actions job: check-jsonschema, the CLI, and jq over the report.
Ingestion jobs and services
jsonschema validation, subprocess.run around the CLI, typed exceptions, and the in-process reference library.
Node.js services
Ajv2020, spawnSync, a typed denial, and a non-blocking execFile variant for request handlers.
A typed report contract
Declared report types, a narrowing guard over JSON.parse, and a gate that passes tsc --strict.
Services and sidecars
Struct-decoded reports, os/exec with exit-status handling, and a Draft 2020-12 validator.
Structure only
jq, check-jsonschema, jsonschema, pydantic, AJV, and Go against the hosted schemas.
The contract every binding relies on
A binding is thin because the contract is small. Automate on the exit status and the JSON report, never on human-readable output.
0· allow- Every required check passed under the exact policy and expectations supplied. stdout holds the report.
1· deny or indeterminate- stdout holds a complete report;
primaryErrornames the boundary that failed. 2· invalid input- No report. stderr carries one JSON object with
errorClassandmessage. 3· internal error- No report. Treat it as an outage, never as a verdict.
The report’s shape is published as the verification-report schema, and every diagnostic code is listed by step in the ordered checks.
Command line
The CLI is the shortest route to every protocol operation without binding a pipeline to Python internals. Install it from a reviewed revision:
git clone https://github.com/makoto-project/makoto.git
cd makoto
git checkout 276008eeec0f10d5322c4c627b8c103222fee841
uv sync --locked --dev
uv run makoto --helpmakoto key generate- Write an Ed25519 key pair:
--private-outat mode 0600 and--public-out. makoto key inspect- Print the key ID a trust policy uses for a public key.
makoto digest- Print the SHA-256 digest of a file in the form statements use.
makoto attest origin- Sign an origin statement:
--subject name=path,--source-kind,--source-uri, optional--source-metadata. makoto attest transform- Sign a transformation: one
--input-bindingfile per input naming its predecessor envelope, plus--operation-type. makoto envelope inspect/cosign- Show an envelope’s payload digest and signer key IDs, or add a co-signature without changing statement identity.
makoto handoff create- Package heads, reachable statements, and final artifacts into a bundle signed by an authorized handoff key.
makoto verify bundle- Run the fourteen ordered steps against a receiver policy and independent expectations;
--jsonwrites the report. makoto schema validate- Validate a document against a core schema or a digest-pinned profile.
makoto profile create- Create a profile reference that pins a schema by digest and closure digest.
makoto policy check- Validate a trust policy, including the canonical ordering the verifier requires.
Python
The Python package is the reference implementation used by the CLI and its tests. It is not advertised as a separately published distribution, and the PyPI name makoto belongs to an unrelated project. Use the command line for the supported boundary. When a long-running service must verify in-process, the Python binding shows the exact VerificationRequest call the CLI makes, pinned to a revision.
| Implemented module | Responsibility |
|---|---|
makoto.model | Construct statement, predicate, subject, and handoff model objects. |
makoto.dsse | Sign and verify exact DSSE payload bytes. |
makoto.schema and makoto.schema_catalog | Strict JSON parsing, core validation, and digest-pinned resource resolution. |
makoto.graph, makoto.policy, and makoto.report | Evaluate graph structure, receiver authorization policy, and machine-readable outcomes. |
makoto.bundle | Safely read and verify a complete portable handoff bundle. |
Browse the reviewed Python source ↗ · Read the reviewed tests ↗
Platform integrations
For orchestrators, warehouses, and stream processors, one standard-library helper, makoto_boundary.py, wraps signing, handoff, and verification and separates tool failures, signing conflicts, and denials into three exceptions. Read the helper, then pick a platform:
- Airflow
- TaskFlow DAG with a failing gate task. Executed on Airflow 3.3.1.
- Dagster
- Signing assets and a blocking asset check. Executed.
- Prefect
- Signing tasks and a gate that is never retried. Executed.
- dbt
- A
dbtRunnerwrapper around an exported model. Executed. - Spark
- Driver-side signing after
_SUCCESS. Executed. - Kafka
- Signed offset windows and verified commits. Executed against a broker.
- Snowflake
- Pinned unload, signed download, gated load. Stubbed platform calls.
- Databricks
- Three-task job with a gate task. Stubbed runtime.
- Expanso
- Edge seal through the
commandprocessor. Validated pipeline.
The browser is a useful verifier surface, but not a shortcut around trust.
A future browser library can hash received ArrayBuffer bytes, validate schemas from a pinned catalog, verify Ed25519 signatures, and render a report. It still needs receiver-owned authorization policy, explicit expected heads or manifests, resource limits, and negative test vectors. No CDN import or package name is promised until those constraints are implemented and tested.
This site’s repository keeps an earlier API study in sdk/javascript and sdk/python. It models ergonomics, not the current protocol: its documents are an earlier bill-of-materials format with no signatures over exact payload bytes, no receiver policy, and no handoff, so the verifier on this site cannot check them. Its real interfaces, executed as written, are worth reading for shape:
// sdk/javascript/src: generate(options) and verify(dbom, fileBuffer)
import { readFile } from "node:fs/promises";
import { generate, verify } from "./sdk/javascript/src/index.js"; // needs ajv and ajv-formats
const buffer = await readFile("sales.csv");
const dbom = await generate({ fileBuffer: buffer, fileName: "sales.csv", signer: "github:you" });
const result = await verify(dbom, buffer); // { valid: boolean, errors: string[] }
console.log(result.valid ? "valid" : result.errors); // valid# sdk/python/makoto: generate(file_path, signer, ...) and verify(...) -> VerifyResult
from pathlib import Path
from makoto import generate, verify # the study package, not the core implementation
path = str(Path("sales.csv").resolve())
dbom = generate(path, signer="github:you")
print(verify(dbom, file_path=path).valid) # True
Path(path).write_text(Path(path).read_text() + "3,4\n")
print(verify(dbom, file_path=path).errors) # ['File hash mismatch: expected 0ae7..., got 4bb0...']
Read, do not deploy. @makoto/sdk was never published to npm, and the Python study is not on PyPI. Its generate also requires an absolute path: a relative one raises ValueError: relative path can't be expressed as a file URI.
Review the JavaScript design source ↗ · Review the earlier Python API study ↗
What every future SDK must preserve
- Exact bytesDo not parse and silently rewrite signed JSON. DSSE authenticates the payload bytes that were actually signed.
- Closed core shapesCore statements stay portable and strict. Team-specific fields enter through declared, digest-pinned profiles.
- Independent policySignature validity and signer authorization are separate results. The receiver supplies trust policy outside the bundle.
- Graph identityTransformation inputs bind both the predecessor statement digest and the exact subject digest.
- Canonical orderPolicies, manifests, and catalogs are rejected when arrays are out of canonical order, so two implementations never disagree about identity.
- Stable failuresImplementations should agree on allow and deny behaviour and on machine-readable diagnostic codes for every conformance fixture.
An SDK starts with a cross-language conformance result, not an install snippet.
Bring the runtime you need, implement one positive fixture and every relevant denial, then propose the API around behaviour we can compare. The five bindings on this site are the baseline a native implementation must match.