Go to file
2026-01-24 10:16:22 +01:00
docs Add selectable fs/index store backend for amduatd 2026-01-24 08:44:28 +01:00
federation federation 2026-01-21 19:51:26 +01:00
ops Reorganize notes into tier1/ops docs 2026-01-17 10:33:23 +01:00
registry Add read-only capability tokens 2026-01-23 23:08:41 +01:00
scripts Add dev restart script 2025-12-22 19:57:22 +01:00
src Add per-request space selection via X-Amduat-Space 2026-01-24 10:16:22 +01:00
tests Add per-request space selection via X-Amduat-Space 2026-01-24 10:16:22 +01:00
tier1 Relocate core tier1 specs to vendor 2026-01-17 11:18:06 +01:00
vendor Add space scoping to amduatd 2026-01-23 22:28:56 +01:00
.gitignore removed tier1/ from .gitignore 2026-01-17 06:28:40 +01:00
.gitmodules Initial commit 2025-12-22 15:23:23 +01:00
AGENTS.md Add initial AGENTS.md and README.md 2025-12-22 15:32:02 +01:00
CMakeLists.txt Add per-request space selection via X-Amduat-Space 2026-01-24 10:16:22 +01:00
README.md Add per-request space selection via X-Amduat-Space 2026-01-24 10:16:22 +01:00

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.

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-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.

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/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):

{
  "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.