Every decision Beacon makes is signed and streamed to Spectra, forming one audit chain that maps to OWASP ASI and to NIST AI RMF and ISO/IEC 42001 controls. Getting that record into your own systems takes one of three paths: verify it on the endpoint, page it from the tenant, or stream it to a collector you own.
Verifying the chain
Chained events are policy decisions and detections. Each one commits to the previous link in its session, so a gap or an edit breaks verification without anyone having to trust the writer. The chain verifier reads an NDJSON export and answers one question:
alyria verify-chain --events ./decisions.ndjson
Output is a single line, VALID, or INVALID (first broken link at index N) with a non-zero exit, which is what a pipeline should branch on. --events reads standard input when it is omitted, so the same check works in a pipe.
Two things to keep straight:
- Verify the file the agent wrote, in order. Filtering it down to decisions alone and then verifying produces a false failure once an interleaved detection has advanced the chain, because both classes share one sequence.
- The verifier reads. A chain that fails verification is evidence of a problem, not a corrupt file to repair.
Pulling the tenant audit log
Control-plane actions live behind a paginated query:
GET /v1/tenants/{tenantId}/audit
| Parameter | Meaning |
|---|---|
eventType | Optional filter |
from, to | Optional ISO 8601 datetimes |
limit | 1 to 100, default 50 |
offset | 0-based, default 0 |
The response is { entries, total, limit, offset }. Because limit is capped at 100, an export is a loop:
set -euo pipefail
: "${TOKEN:?set TOKEN}" "${TENANT:?set TENANT}"
offset=0
while :; do
page="audit-$offset.json"
if ! curl -sS --fail --max-time 30 \
-H "Authorization: Bearer $TOKEN" \
"https://observatory.example/v1/tenants/$TENANT/audit?from=2026-10-01T00:00:00Z&to=2026-10-31T23:59:59Z&limit=100&offset=$offset" \
-o "$page"; then
echo "export failed at offset $offset: request refused or failed" >&2
exit 1
fi
total=$(jq -er '.total | select(type == "number" and . >= 0 and . == floor)' "$page") || {
echo "export failed at offset $offset: response has no valid total" >&2
exit 1
}
offset=$((offset + 100))
if [ "$offset" -ge "$total" ]; then
break
fi
done
echo "exported $total entries"
--fail is the part that matters: without it curl treats an HTTP 401 or 500 as a successful transfer, writes the error body to disk, and the loop keeps going with a total of null. With it, a refused request stops the export and says where.
The jq check rejects anything that is not a non-negative whole number, so a malformed or unauthenticated response exits before the offset advances. Fix from and to for the whole run so a live tenant cannot shift the window underneath you, and keep the pages with the query bounds and the total you saw. An export is evidence, not a spreadsheet.
This log covers tenant-level actions: signup, token minting, key changes, policy publication. Decisions made on a laptop are in the endpoint chain and in whatever sink you pointed it at.
Streaming to your sink
Decisions are signed at the endpoint and forwarded to Spectra. The service terminates TLS itself, takes a destination policy and its key set, and exposes a health check, so your collector sits in front of a component that already speaks the format:
spectra-service serve --listen 127.0.0.1:8787 --destination-policy <path> --destination-policy-keys <path>
spectra-service healthcheck --host 127.0.0.1 --port 8787 --path /healthz
If your SIEM is the system of record, this is the integration to build. Collecting chain exports and verifying them on your side is the other supported path, and it is more manual.
Retention and what to keep
Audit history is included for 30 days within plan capacity; longer retention is part of an agreed enterprise deployment. Whatever your plan, treat the endpoint chain and the tenant log as two different records with two different retention rules, and export on a schedule rather than when an auditor asks. The evidence you cannot reproduce is the decision you did not collect.