Quick install: AGLedger on Docker Compose (Developer Edition)
This is the fastest way to a running AGLedger Server: clone the install repository, run one script, and notarize a record in about five minutes. It brings up the Server, a background worker, and a bundled PostgreSQL with Docker Compose — no Kubernetes, no external database.
The Server comes up as Developer Edition with no license applied: every feature is enabled, and it is free to self-host for evaluation, development, and production on the bundled PostgreSQL. For a production Kubernetes deployment fronted by TLS and backed by your own PostgreSQL, see the Kubernetes install guide.
Validated against API v0.26.1 on 2026-05-27 (Developer Edition, Docker Compose, bundled PostgreSQL 18).
Prerequisites
- Docker Engine 24.0+ and the Docker Compose v2 plugin
jq,curl, andopensslon your PATH (the installer uses them for secret generation and the Docker Hub version lookup)- 4 GB RAM and 2 CPU cores minimum
1. Clone and install
The deployment packaging — Compose files, scripts, and Helm chart — lives in the
agledger-ai/install repository. Clone a tagged release
and run the installer.
$ git clone --branch v0.26.1 https://github.com/agledger-ai/install.git
$ cd install
$ ./scripts/install.sh --version 0.26.1
install.sh generates the cryptographic secrets locally (POSTGRES_PASSWORD, API_KEY_SECRET,
and an Ed25519 VAULT_SIGNING_KEY), writes them to compose/.env, starts PostgreSQL, runs
migrations, mints the first platform API key, and starts the API and worker. Pass --version to
pin a release; omit it to install the latest stable from Docker Hub.
[STEP] Checking prerequisites
[OK] Docker Engine 29.1.3
[OK] Docker Compose 2.40.3
[STEP] Configuring environment
[OK] Generated POSTGRES_PASSWORD
[OK] Generated API_KEY_SECRET
[OK] Generated VAULT_SIGNING_KEY
[STEP] Running database migrations
{"migration":"001_consolidated.sql","msg":"Applied migration"}
{"count":1,"msg":"Migration complete"}
[STEP] Creating platform API key
[OK] Platform API key created
[STEP] Starting all services
[OK] All services started
[STEP] Running preflight checks
✓ VAULT_SIGNING_KEY: Set
✓ PostgreSQL connectivity: Connected
✓ PostgreSQL version: 18.4 (native uuidv7)
✓ Migrations: 1/1 applied — up to date
=============================================================================
AGLedger — Installation Complete
=============================================================================
Version: 0.26.1
API URL: http://localhost:3001
Database: Bundled PostgreSQL
Platform API Key (SAVE THIS — shown only once):
agl_plt_<save-this-securely>
This key has full admin access. Store it securely.
The platform key is printed once. Save it — it is your first credential, and you use it to
provision organizations and agents. The installer also writes it to compose/.env as
PLATFORM_API_KEY so the bundled scripts can find it.
2. Confirm the Server is up and signing
The API serves on http://localhost:3001. Two unauthenticated checks prove it is healthy:
$ curl -s http://localhost:3001/health
{"status":"ok","version":"0.26.1","timestamp":"2026-05-27T21:34:57.181Z"}
$ curl -s http://localhost:3001/health/ready
{"status":"ready","version":"0.26.1","timestamp":"2026-05-27T21:34:57.186Z"}
A Server is only useful if it is signing. The active verification key is published unauthenticated;
the keyId is the fingerprint of the VAULT_SIGNING_KEY the installer generated for you:
$ curl -s http://localhost:3001/v1/verification-keys
{"data":[{"keyId":"c438fa840c35f687","algorithm":"Ed25519",
"publicKey":"MCowBQYDK2VwAyEAC1cEMkxIEEKDI4z80PiYqlttimq8S/arTjPE1QMx+88=",
"status":"active","activatedAt":"2026-05-27","retiredAt":null}],
"envelope":"COSE_Sign1","signatureAlgorithm":"Ed25519"}
With no license applied, the Server runs as Developer Edition with every feature enabled:
$ curl -s -H "Authorization: Bearer $PLATFORM_KEY" http://localhost:3001/v1/admin/license
{"validity":"unlicensed","tier":"developer",
"features":["custom_schemas","expression_engine","delegation_chains","audit_export",
"compliance_reports","encrypted_mode","entity_references","proposals","federation"],
"source":"none"}
3. Notarize one record
A fresh install ships with the notarize-generic-v1 contract type and a Default organization,
and zero agents — every record must be tied to a real agent identity. Create one agent, mint it a
key, and notarize.
$ export U=http://localhost:3001
$ export PLATFORM_KEY=agl_plt_<from-step-1>
$ ORG=$(curl -s -H "Authorization: Bearer $PLATFORM_KEY" "$U/v1/admin/orgs" \
| jq -r '.data[0].id')
# create an agent in the Default org
$ AGENT=$(curl -s -X POST -H "Authorization: Bearer $PLATFORM_KEY" -H "Content-Type: application/json" \
-d "{\"name\":\"Quickstart Agent\",\"orgId\":\"$ORG\"}" "$U/v1/admin/agents" | jq -r '.id')
# mint an agent key (the plaintext apiKey is returned once — capture it now)
$ AGENT_KEY=$(curl -s -X POST -H "Authorization: Bearer $PLATFORM_KEY" -H "Content-Type: application/json" \
-d "{\"role\":\"agent\",\"ownerId\":\"$AGENT\",\"ownerType\":\"agent\",\"scopeProfile\":\"agent-full\",\"label\":\"quickstart-key\"}" \
"$U/v1/admin/api-keys" | jq -r '.apiKey')
Now notarize. As an agent key, you do not name the org or principal — the Server resolves both from the key:
$ curl -s -X POST -H "Authorization: Bearer $AGENT_KEY" -H "Content-Type: application/json" \
-d '{"type":"notarize-generic-v1","criteria":{"summary":"About to reconcile invoice INV-4471 against PO-9921"}}' \
"$U/v1/records"
{
"id": "019e6b5e-433f-7610-ba9d-71c6f045875e",
"status": "RECORDED",
"type": "notarize-generic-v1",
"signedStatement": {
"chainPosition": 1,
"leafHash": "4e1b463fa740390ef25a3045d5db6f31b542fe1f1810babb9757c698fb068f61",
"previousHash": null,
"signingKeyId": "c438fa840c35f687",
"signedCheckpointRef": null,
"url": "/v1/records/019e6b5e-433f-7610-ba9d-71c6f045875e/attestation"
}
}
The record is RECORDED and already signed: signingKeyId is the same c438fa840c35f687 you saw
at /v1/verification-keys, so the record is signed with your Server's key, COSE_Sign1 / Ed25519.
That is the whole loop — install, up, signing, notarized.
To verify that record offline with nothing but the published public key, follow the
quick start. The full API surface is the OpenAPI document the Server serves at
/openapi.json.
Stopping, upgrading, removing
$ docker compose ps # from the install/compose directory
$ ./scripts/upgrade.sh 0.26.2 # backs up, then upgrades in place
$ ./scripts/uninstall.sh # stops containers and removes volumes
uninstall.sh keeps compose/.env by default — pass --purge to remove it too.
Production and external databases
This Compose path is single-node: ideal for evaluation, development, and small workloads. For a
production cluster — TLS, your own managed PostgreSQL, horizontal scaling — use the
Kubernetes install guide. To keep Compose but point at a managed PostgreSQL (Aurora,
RDS, Cloud SQL), set DATABASE_URL in compose/.env and install with ./scripts/install.sh --external-db; external-database licensing is per database instance.
Air-gapped
Nothing in install or runtime depends on agledger.ai, Docker Hub, or npm at runtime. For a
restricted network, mirror the image (agledger/agledger:0.26.1) into your internal registry and
run ./scripts/install.sh --image your-registry.example/agledger --version 0.26.1. The Server makes
no outbound calls except the webhook and federation endpoints you configure. The release is
cosign-signed for fully offline verification against the cosign.pub in the install repository; see
the Kubernetes install guide for the verification commands.
Validated against API v0.26.1 on 2026-05-27 (Developer Edition, Docker Compose install).