> ## Documentation Index
> Fetch the complete documentation index at: https://docs.algovoi.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Substrate 2 Addons

> Bolt additional services onto the Substrate 2 control plane. Any service with a health endpoint joins with two environment variables and self registers.

The Substrate 2 control plane bridges the four services that ship in the bundle, and it
accepts **addons** — any additional service you bolt on to share the issuer trust set and
appear in one posture. The contract is small and language-agnostic: a `/health` endpoint
and two environment variables.

## Addons vs the commercial add-on products

Two different things are sometimes both called "add-ons", and they integrate differently:

* **Control-plane addons** *(this page)* — any service that bridges into the control plane
  with two environment variables (`S2_HUB_URL` + `S2_HUB_TOKEN`): it self-registers, pulls
  the issuer trust set, and appears in the posture. The four bundled services are these, and
  so is any custom service you run.

* **AlgoVoi commercial add-on products** — separately-licensed products such as
  [Agent Passport](/agent-passport), [Settlement Verification](/settlement-verify),
  [Payment Mandate](/payment-mandate), [Spend Guardrail](/spend-guardrail),
  [Compliance Gate](/compliance-gate-v2) and [Verifiable Audit Log](/audit-log). Each is
  bought as its own SKU, installed from its own download, and binds to Substrate 2 through
  the **evidence model** — a verified action becomes a signed, audit-ready receipt that folds
  into the Substrate 2 chain (see the [application matrix](/substrate-2#application-matrix)).
  They are not control-plane addons by default, and they are not part of the Substrate 2
  bundle.

A commercial product can *also* be made a control-plane addon: give it the same two-env-var
contract below and it appears in the posture and shares the issuer trust set, on top of its
evidence binding. That is a natural fit for the credential and trust products (Agent
Passport, ATB), less so for the pure receipt and payment products, which bind via evidence
anyway.

## The bundled services

After you install the bundle (`python algovoi_unbundle.py --license @licence.key --install bundle.algv`),
four console commands are on your `PATH`:

| Service                 | Command                           | Port |
| ----------------------- | --------------------------------- | ---- |
| Control plane           | `algovoi-substrate2-controlplane` | 8094 |
| Federation validator    | `algovoi-federation-validator`    | 8092 |
| ZK receipt              | `algovoi-zkp-receipt`             | 8093 |
| ATB credential verifier | `algovoi-atb-credential-verifier` | 8095 |

Start the control plane first. It generates an admin token on first run at
`<S2CP_DATA_DIR>/admin_token` (default `/app/data`), and persists to SQLite there (point
`S2CP_DB` at a `postgresql://...` DSN to use PostgreSQL instead).

```bash theme={null}
S2CP_DATA_DIR=./data algovoi-substrate2-controlplane     # serves on :8094
TOKEN=$(cat ./data/admin_token)
```

## Bridge a service into the control plane

Each bundled service is already an addon. Point it at the control plane with two env vars
and on startup it **self-registers** and **pulls its issuer trust set**:

```bash theme={null}
S2_HUB_URL=http://localhost:8094 \
S2_HUB_TOKEN=$TOKEN \
S2_HUB_SELF_URL=http://localhost:8092 \
algovoi-federation-validator
```

`S2_HUB_SELF_URL` is the address the control plane uses to poll the service's health (use the
service's own reachable URL on your network). Confirm it joined:

```bash theme={null}
curl -s http://localhost:8094/v1/posture
```

It now appears in the posture, the control plane polls its health, and it shares the issuer
trust set you manage in one place.

## Register an issuer

The services verify credentials against issuer public keys held by the control plane.
Register one (admin token required); every bridged service then picks it up:

```bash theme={null}
curl -X POST http://localhost:8094/v1/issuers \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"did":"did:web:your-issuer","public_key_b64":"<falcon1024-pk-base64>"}'
```

## Add a custom addon

Any service, in any language, joins the same way. It needs:

1. **A `/health` endpoint** returning HTTP 200.
2. **Two HTTP calls to the control plane on startup:**
   * `GET  /v1/issuer-pks` → pull the trust set (`{did: pk_b64}`)
   * `POST /v1/services` → self-register (with the admin token)

Then run it with the same two env vars plus its own reachable URL:

```bash theme={null}
S2_HUB_URL=http://localhost:8094 \
S2_HUB_TOKEN=$TOKEN \
S2_HUB_SELF_URL=http://your-addon:9000 \
your-addon
```

A Python addon can copy the bundled `hub_client` (\~50 lines) to make those two calls; a
non-Python addon makes the same two requests directly. The addon then appears in the
posture alongside the rest of the estate, with no shared library or SDK to adopt.

## Control plane API

| Endpoint                         | Purpose                                            |
| -------------------------------- | -------------------------------------------------- |
| `GET /health`                    | liveness + issuer/service counts                   |
| `GET /v1/issuer-pks`             | the `{did: pk_b64}` trust set the services consume |
| `GET /.well-known/atb-keys.json` | canonical hub doc the ATB verifier resolves        |
| `POST /v1/issuers`               | register an issuer *(admin)*                       |
| `DELETE /v1/issuers/{did}`       | revoke an issuer *(admin)*                         |
| `POST /v1/services`              | register a service / addon *(admin)*               |
| `GET /v1/posture`                | health across all bridged services                 |
| `GET /v1/audit`                  | the HMAC-chained trust-change log *(admin)*        |

Everything is self-hosted and offline; the control plane makes no outbound calls of its own.
