# 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 ```sh cmake -S . -B build cmake --build build -j ``` To build without the embedded UI: ```sh 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`. ```sh git submodule update --init --recursive ``` ## Quickstart (local) Initialize a store: ```sh ./vendor/amduat/build/amduat-asl init --root .amduat-asl ``` Run the daemon (fs backend default): ```sh ./build/amduatd --root .amduat-asl --sock amduatd.sock ``` Run the daemon with the index-backed store: ```sh ./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: ```sh ./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 ``` Flags: - `--fed-enable` turns on the coordinator tick loop. - `--fed-transport stub|unix` selects transport (`stub` by default). - `--fed-unix-sock PATH` configures the unix transport socket path. - `--fed-domain-id ID` sets the local domain id. - `--fed-registry-ref REF` seeds the registry reference (hex ref). - `--fed-require-space` rejects `/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: ```sh ./build/amduatd --root .amduat-asl --sock amduatd.sock --enable-derivation-index ``` To fail `/v1/pel/run` if the derivation index write fails: ```sh ./build/amduatd --root .amduat-asl --sock amduatd.sock --derivation-index-strict ``` Dev loop (build + restart): ```sh ./scripts/dev-restart.sh ``` Query store meta: ```sh curl --unix-socket amduatd.sock http://localhost/v1/meta ``` Browser UI (use `socat` to forward the Unix socket): ```sh 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: ```sh curl --unix-socket amduatd.sock 'http://localhost/v1/contract?format=ref' ``` Fetch the contract bytes (JSON): ```sh curl --unix-socket amduatd.sock http://localhost/v1/contract ``` Upload raw bytes: ```sh curl --unix-socket amduatd.sock -X POST http://localhost/v1/artifacts \ -H 'Content-Type: application/octet-stream' \ --data-binary 'hello' ``` Download raw bytes: ```sh curl --unix-socket amduatd.sock http://localhost/v1/artifacts/ ``` Download artifact framing (`ENC/ASL1-CORE v1`): ```sh curl --unix-socket amduatd.sock \ 'http://localhost/v1/artifacts/?format=artifact' --output artifact.bin ``` Run a PEL program from store-backed refs (default `scheme_ref=dag`): ```sh curl --unix-socket amduatd.sock -X POST http://localhost/v1/pel/run \ -H 'Content-Type: application/json' \ -d '{"program_ref":"","input_refs":[""],"params_ref":""}' ``` When derivation indexing is enabled, successful PEL runs record derivations under `/index/derivations/by_artifact/` keyed by output refs (plus result/trace/receipt refs). Define a PEL/PROGRAM-DAG/1 program (store-backed): ```sh 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): ```sh curl --unix-socket amduatd.sock -X POST http://localhost/v1/concepts \ -H 'Content-Type: application/json' \ -d '{"name":"hello","ref":""}' ``` Publish a new version: ```sh curl --unix-socket amduatd.sock -X POST http://localhost/v1/concepts/hello/publish \ -H 'Content-Type: application/json' \ -d '{"ref":""}' ``` Resolve the latest ref: ```sh curl --unix-socket amduatd.sock http://localhost/v1/resolve/hello ``` Inspect concepts: ```sh curl --unix-socket amduatd.sock http://localhost/v1/concepts curl --unix-socket amduatd.sock http://localhost/v1/concepts/hello ``` Artifact info (length + type tag): ```sh curl --unix-socket amduatd.sock 'http://localhost/v1/artifacts/?format=info' ``` ## Space selection Requests can select a space via the `X-Amduat-Space` header: ```sh curl --unix-socket amduatd.sock http://localhost/v1/concepts \ -H 'X-Amduat-Space: demo' ``` Precedence rules: - `X-Amduat-Space` header (if present) - daemon `--space` default (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: ```sh 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-Ref` header) - `GET /v1/contract?format=ref` → `{ref}` - `GET /v1/space/doctor` → deterministic space health checks - `GET /v1/ui` → browser UI for authoring/running programs - `GET /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 resolve - `GET /v1/fed/status` → `{status, domain_id, registry_ref, last_tick_ms}` - `POST /v1/artifacts` - raw bytes: `Content-Type: application/octet-stream` (+ optional `X-Amduat-Type-Tag: 0x...`) - artifact framing: `Content-Type: application/vnd.amduat.asl.artifact+v1` - `GET|HEAD /v1/artifacts/{ref}` - raw bytes default - artifact framing: `?format=artifact` - `POST /v1/concepts` - request: `{name, ref?}` (`name` is lowercase; `ref` publishes an initial version) - response: `{name, concept_ref}` - `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_ref` accept hex refs or concept names; omit `scheme_ref` to use `dag`) - 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}` - `POST /v1/pel/programs` - request: authoring JSON for `PEL/PROGRAM-DAG/1` (kernel ops only; `params_hex` is raw hex bytes) - response: `{program_ref}` - `POST /v1/context_frames` Receipt example (with v1.1 fields): ```json { "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: ```bash curl --unix-socket amduatd.sock \ 'http://localhost/v1/fed/records?domain_id=1&from_logseq=0&limit=256' ``` ```json { "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: ```json { "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.