9.2 KiB
amduat-api
amduat-api builds amduatd, a minimal HTTP server over a Unix domain socket that exposes Amduat substrate operations for a single ASL store root.
Build
cmake -S . -B build
cmake --build build -j
To build without the embedded UI:
cmake -S . -B build -DAMDUATD_ENABLE_UI=OFF
When the UI is enabled (default), /v1/ui serves the same embedded HTML as before.
Core dependency
This repo vendors the core implementation as a git submodule at vendor/amduat.
git submodule update --init --recursive
Quickstart (local)
Initialize a store:
./vendor/amduat/build/amduat-asl init --root .amduat-asl
Run the daemon (fs backend default):
./build/amduatd --root .amduat-asl --sock amduatd.sock
Run the daemon with the index-backed store:
./build/amduatd --root .amduat-asl --sock amduatd.sock --store-backend index
Note: /v1/fed/records requires the index backend.
Federation (dev)
Federation is opt-in and disabled by default. Enabling federation requires the index-backed store and explicit flags:
./build/amduatd --root .amduat-asl --sock amduatd.sock --store-backend index \
--fed-enable --fed-transport unix --fed-unix-sock peer.sock \
--fed-domain-id 1 --fed-registry-ref <registry_ref_hex>
Flags:
--fed-enableturns on the coordinator tick loop.--fed-transport stub|unixselects transport (stubby default).--fed-unix-sock PATHconfigures the unix transport socket path.--fed-domain-id IDsets the local domain id.--fed-registry-ref REFseeds the registry reference (hex ref).--fed-require-spacerejects/v1/fed/*requests that do not resolve a space.
X-Amduat-Space is honored for /v1/fed/* requests the same way as other
endpoints. If --space is configured, unix transport requests will include the
same X-Amduat-Space header when contacting peers.
Run the daemon with derivation indexing enabled:
./build/amduatd --root .amduat-asl --sock amduatd.sock --enable-derivation-index
To fail /v1/pel/run if the derivation index write fails:
./build/amduatd --root .amduat-asl --sock amduatd.sock --derivation-index-strict
Dev loop (build + restart):
./scripts/dev-restart.sh
Query store meta:
curl --unix-socket amduatd.sock http://localhost/v1/meta
Browser UI (use socat to forward the Unix socket):
socat TCP-LISTEN:8080,fork,reuseaddr UNIX-CONNECT:amduatd.sock
Then open http://localhost:8080/v1/ui (concept editor).
Discover the store-backed API contract ref:
curl --unix-socket amduatd.sock 'http://localhost/v1/contract?format=ref'
Fetch the contract bytes (JSON):
curl --unix-socket amduatd.sock http://localhost/v1/contract
Upload raw bytes:
curl --unix-socket amduatd.sock -X POST http://localhost/v1/artifacts \
-H 'Content-Type: application/octet-stream' \
--data-binary 'hello'
Download raw bytes:
curl --unix-socket amduatd.sock http://localhost/v1/artifacts/<ref>
Download artifact framing (ENC/ASL1-CORE v1):
curl --unix-socket amduatd.sock \
'http://localhost/v1/artifacts/<ref>?format=artifact' --output artifact.bin
Run a PEL program from store-backed refs (default scheme_ref=dag):
curl --unix-socket amduatd.sock -X POST http://localhost/v1/pel/run \
-H 'Content-Type: application/json' \
-d '{"program_ref":"<program_ref>","input_refs":["<input_ref_0>"],"params_ref":"<params_ref>"}'
When derivation indexing is enabled, successful PEL runs record derivations under
<root>/index/derivations/by_artifact/ keyed by output refs (plus result/trace/receipt refs).
Define a PEL/PROGRAM-DAG/1 program (store-backed):
curl --unix-socket amduatd.sock -X POST http://localhost/v1/pel/programs \
-H 'Content-Type: application/json' \
-d '{"nodes":[{"id":1,"op":{"name":"pel.bytes.concat","version":1},"inputs":[{"external":{"input_index":0}},{"external":{"input_index":1}}],"params_hex":""}],"roots":[{"node_id":1,"output_index":0}]}'
Create a named concept and publish a ref (so you can use the name instead of hex refs):
curl --unix-socket amduatd.sock -X POST http://localhost/v1/concepts \
-H 'Content-Type: application/json' \
-d '{"name":"hello","ref":"<program_ref>"}'
Publish a new version:
curl --unix-socket amduatd.sock -X POST http://localhost/v1/concepts/hello/publish \
-H 'Content-Type: application/json' \
-d '{"ref":"<program_ref_v2>"}'
Resolve the latest ref:
curl --unix-socket amduatd.sock http://localhost/v1/resolve/hello
Inspect concepts:
curl --unix-socket amduatd.sock http://localhost/v1/concepts
curl --unix-socket amduatd.sock http://localhost/v1/concepts/hello
Artifact info (length + type tag):
curl --unix-socket amduatd.sock 'http://localhost/v1/artifacts/<ref>?format=info'
Space selection
Requests can select a space via the X-Amduat-Space header:
curl --unix-socket amduatd.sock http://localhost/v1/concepts \
-H 'X-Amduat-Space: demo'
Precedence rules:
X-Amduat-Spaceheader (if present)- daemon
--spacedefault (if configured) - unscoped names (no space)
When capability tokens are used, the requested space must match the token's space (or the token must be unscoped), otherwise the request is rejected.
Space doctor
Check deterministic invariants for the effective space:
curl --unix-socket amduatd.sock http://localhost/v1/space/doctor
curl --unix-socket amduatd.sock http://localhost/v1/space/doctor \
-H 'X-Amduat-Space: demo'
When the daemon uses the fs store backend, index-only checks are reported as
"skipped"; the index backend runs them.
Current endpoints
GET /v1/meta→{store_id, encoding_profile_id, hash_id, api_contract_ref}GET /v1/contract→ contract bytes (JSON) (+X-Amduat-Contract-Refheader)GET /v1/contract?format=ref→{ref}GET /v1/space/doctor→ deterministic space health checksGET /v1/ui→ browser UI for authoring/running programsGET /v1/fed/records?domain_id=...&from_logseq=...&limit=...→{domain_id, snapshot_id, log_prefix, next_logseq, records[]}(published artifacts + tombstones + PER + TGK edges)GET /v1/fed/artifacts/{ref}→ raw bytes for federation resolveGET /v1/fed/status→{status, domain_id, registry_ref, last_tick_ms}POST /v1/artifacts- raw bytes:
Content-Type: application/octet-stream(+ optionalX-Amduat-Type-Tag: 0x...) - artifact framing:
Content-Type: application/vnd.amduat.asl.artifact+v1
- raw bytes:
GET|HEAD /v1/artifacts/{ref}- raw bytes default
- artifact framing:
?format=artifact
POST /v1/concepts- request:
{name, ref?}(nameis lowercase;refpublishes an initial version) - response:
{name, concept_ref}
- request:
POST /v1/concepts/{name}/publish→ publishes a new version{ref}GET /v1/concepts→{concepts:[{name, concept_ref}]}GET /v1/concepts/{name}→{name, concept_ref, latest_ref, versions[]}GET /v1/resolve/{name}→{ref}(latest published)POST /v1/pel/run- request:
{program_ref, input_refs[], params_ref?, scheme_ref?}(program_ref/input_refs/params_refaccept hex refs or concept names; omitscheme_refto usedag) - request receipt (optional):
{receipt:{input_manifest_ref, environment_ref, evaluator_id, executor_ref, started_at, completed_at, sbom_ref?, parity_digest_hex?, executor_fingerprint_ref?, run_id_hex?, limits?, logs?, determinism_level?, rng_seed_hex?, signature_hex?}} - response:
{result_ref, trace_ref?, receipt_ref?, output_refs[], status}
- request:
POST /v1/pel/programs- request: authoring JSON for
PEL/PROGRAM-DAG/1(kernel ops only;params_hexis raw hex bytes) - response:
{program_ref}
- request: authoring JSON for
POST /v1/context_frames
Receipt example (with v1.1 fields):
{
"program_ref": "ab12...",
"input_refs": ["cd34..."],
"receipt": {
"input_manifest_ref": "ef56...",
"environment_ref": "7890...",
"evaluator_id": "local-amduatd",
"executor_ref": "1122...",
"started_at": 1712345678,
"completed_at": 1712345688,
"executor_fingerprint_ref": "3344...",
"run_id_hex": "deadbeef",
"limits": {
"cpu_ms": 12,
"wall_ms": 20,
"max_rss_kib": 1024,
"io_reads": 1,
"io_writes": 0
},
"logs": [
{"kind": 1, "log_ref": "5566...", "sha256_hex": "aabbcc"}
],
"determinism_level": 2,
"rng_seed_hex": "010203",
"signature_hex": "bead"
}
}
Federation records example:
curl --unix-socket amduatd.sock \
'http://localhost/v1/fed/records?domain_id=1&from_logseq=0&limit=256'
{
"domain_id": 1,
"snapshot_id": 42,
"log_prefix": 1234,
"next_logseq": 120,
"records": [
{
"domain_id": 1,
"type": 0,
"ref": "ab12...",
"logseq": 100,
"snapshot_id": 42,
"log_prefix": 1234,
"visibility": 1,
"has_source": false,
"source_domain": 0
}
]
}
Response example:
{
"result_ref": "aa11...",
"trace_ref": "bb22...",
"receipt_ref": "cc33...",
"output_refs": ["dd44..."],
"status": "OK"
}
Notes
- This is intentionally a local-first surface (Unix socket, no TLS). HTTPS can be added later without changing the semantics.