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

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