Crucible / Docs

Use the AOS Hub API

AOS Hub exposes unary, Connect-compatible JSON routes over HTTP. Requests use JSON bodies and responses use JSON; clients do not need a gRPC runtime.

#Endpoint shape

Methods are mounted at:

POST /aos.hub.v1.<Service>/<Method>

For example:

curl -fsS \
  -H 'Content-Type: application/json' \
  -d '{"slug":"acme/cdn"}' \
  https://hub.example.com/aos.hub.v1.RegistryService/GetRegistry

An empty request may be sent as {}. API errors use a JSON envelope with a machine-readable code and a human-readable message.

The service families cover registries, organizations, projects, storage, packages, channels, audits, instance settings, identity and access, webhooks, publishing, Git surfaces, and binary caches. The complete request and response schema is in hub.proto.

#Authentication

Public registry reads do not require authentication. Private reads and changes require a bearer access token with the necessary permission:

Authorization: Bearer <access-token>

The simple /<flat-slug>/-/api/... routes documented in the web guide are always public-only: they do not use a browser session or bearer token, and the current router accepts only single-segment slugs. Use the unary service routes for canonical organization/registry paths and authenticated visibility.

Interactive clients start an RFC 8628 device grant with POST /oauth2/device_authorization, show the returned verification URL and user code, and poll POST /oauth2/token at the advertised interval. A successful poll returns a one-hour access token and a rotating refresh credential. aos hub login implements this flow:

aos hub login --hub https://hub.example.com

The device request uses client_id=aos-cli, an optional canonical stable resource scope, and an optional space-separated permission value. Polling uses grant type urn:ietf:params:oauth:grant-type:device_code. Refresh uses grant type refresh_token; every successful refresh returns a replacement refresh credential. Reusing a consumed credential revokes the complete family. POST /oauth2/revoke accepts the refresh credential, client_id=aos-cli, and token_type_hint=refresh_token.

Publishing automation may instead start with a provisioning token whose secret begins with aos_. The Hub stores only its hash. Exchange it with the explicit grant type urn:aos:params:oauth:grant-type:provisioning-token and the secret as an Authorization: Bearer credential. A native operator can mint scoped provisioning tokens with aos-hub token mint.

All OAuth credential responses carry Cache-Control: no-store. Native and Cloudflare Worker deployments mount the same handlers and return the same structured pending, slow-down, denial, expiry, and invalid-grant errors.

The CLI obtains user credentials through aos hub login; the browser console obtains a short-lived bearer from its signed-in session without exposing it to the user. Bootstrap administration through the local aos-hub command on native deployments or the web console on either runtime. Non-browser API clients still need a suitably scoped device-flow or provisioning credential.

Browser authentication uses an opaque session cookie and is intentionally separate from API bearer tokens.

Inspect a bearer without exposing its secret through IdentityService/WhoAmI:

curl -fsS \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <access-token>' \
  -d '{}' \
  https://hub.example.com/aos.hub.v1.IdentityService/WhoAmI

The response identifies the live user or service account, lists current role grants, and separately reports this token's scope, permissions, and expiry.

IdentityService manages generic access tokens with ListAccessTokens, PlanIssueAccessToken/IssueAccessToken, and PlanRetireAccessToken/RetireAccessToken. Requests use canonical stable authorization scopes and native permission verbs such as read, publish, binding.manage, or cache.gc.plan. There are no registry-token RPC aliases. Token metadata includes its non-secret comment, creation, expiry, last-use, rotation, retirement, and lifecycle state; the plaintext secret is returned once by the issuance apply response.

Service accounts use ListServiceAccounts, GetServiceAccount, and reviewed create, update, and delete pairs. A rename changes only the human-facing <org>/<name> reference; the numeric principal identity remains stable. Delete removes direct memberships atomically, while retained token metadata becomes unusable immediately because its owner is no longer live. The former AutomationPrincipal API names are not served.

Organization invitations use ListInvitations, GetInvitation, reviewed PlanCreateInvitation/CreateInvitation and PlanCancelInvitation/CancelInvitation pairs, plus the authenticated AcceptInvitation identity ceremony. Creation returns a 256-bit aosi_ acceptance secret; only its SHA-256 verifier and AES-GCM-sealed recovery copy are stored. Retrying the exact same apply idempotency key returns the same unsealed secret, while a different apply is rejected. Acceptance or cancellation erases the recovery copy immediately; bounded maintenance erases expired copies. A pending invitation is not a user or membership. Acceptance succeeds only for a live user whose canonical email and organization match the invitation, and atomically consumes the secret while creating the exact direct membership. History remains visible as pending, accepted, cancelled, or time-derived expired metadata. Connect responses carry Cache-Control: no-store, Pragma: no-cache, and Referrer-Policy: no-referrer, so secret-bearing mutation results are not retained by shared caches or leaked as referrers.

Organization SSO uses two explicit IdentityService resources. The identity-provider surface consists of GetIdentityProvider, reviewed PlanSetIdentityProvider/SetIdentityProvider, and reviewed PlanRemoveIdentityProvider/RemoveIdentityProvider. Reads report only whether a client secret is configured. A plaintext replacement is accepted at the request edge, sealed before plan persistence, and never returned.

Email-domain ownership uses ListOrganizationDomains, GetOrganizationDomain, and reviewed claim, verify, and release pairs. A new claim requires expectedResourceVersion: "absent"; subsequent operations use the exact returned resource version. Verification performs DNS resolution in both native and Worker deployments and commits only when the exact reviewed TXT challenge is present. Claim, audit, and plan completion are one atomic database transaction, including on MySQL.

#Topology and cache bytes

TopologyService/ExplainSurfaceRequest explains how one absolute HTTP request selects a live simultaneous route. TopologyService/ListObjectPresence returns physical evidence for one logical object across all placements. Placements are addressed by their stable surface-local names. Cache placement eviction uses the reviewed BinaryCacheService/PlanRunPlacementEviction/RunPlacementEviction pair and is separate from logical GC.

Cache producers call BinaryCacheService/CreateCacheObjectUploads with one canonical machine path and declared byte size, or parallel paths/sizes arrays containing at most 256 unique objects. The batch response preserves input order and exact retries return the same live tickets. A non-empty uploadUrl accepts the exact bytes with PUT; direct-origin URLs are capabilities and must not receive the Hub bearer, while /BinaryCacheService/UploadObject/... is a typed authenticated Hub proxy. An empty URL requires BeginCacheMultipartUpload, numbered PUT requests to the returned partUploadUrl, and CompleteCacheMultipartUpload; clients abort failed uploads with AbortCacheMultipartUpload.

#Scripting

The remote client covers common calls and provides stable JSON output:

aos --json hub registry list --hub https://hub.example.com
aos --json hub registry get acme/cdn --hub https://hub.example.com

Pass --token '<access-token>' to commands that require authentication. Use the schema when building a client or integration.

#Read native release documentation

aos.hub.v1.DocumentationService uses the registry's normal read authorization. Native references are retained with completed signed releases. Hub checks the publication's documentation directory and exact options.json byte identity before returning or rendering the aos.module.documentation document. Packages without a native documentation artifact return not found. The /{registry}/-/api/v1/ documentation, ability, and option reads accept the same registry read bearer as their RPC counterparts; a browser session cookie alone does not authenticate these JSON routes. Credentialed responses use private, no-store caching even when the document digest identifies immutable bytes.

MethodNative behavior
GetPackageDocumentationSelects registry/package/version/platform, with an optional exact release pin.
SearchPackageDocumentationSearches generated package, option, or operation rows; each result carries release, registry commit, and document digest.
ListPackageOptionsLists typed native options with prefix, owner, portable type JSON, and extensibility filters.
GetPackageOptionSelects an option by exact nonempty literal path segments.
ComparePackageDocumentationCompares two package versions on the same platform and returns aos.module.documentation.comparison.
GetDocumentationArtifactRetrieves the exact native reference matching a document digest.
GetPackageDocumentationSchemaReturns the selected native reference bytes and documentation identity.

For a pinned document read:

curl -fsS -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <access-token>' \
  -d '{"registry":"acme/packages","package":"sample","version":"1.0","platform":"x86_64-linux","release":"1.0.0"}' \
  https://hub.example.com/aos.hub.v1.DocumentationService/GetPackageDocumentation

Empty version/platform selectors use Hub's deterministic default selection. An explicit release never falls back to another release. The HTTP package options list also honors its release query; the options RPC uses version/platform selection. The response identity includes the verified commit, tag object, completed snapshot, exact document digest and size, and artifact store path/NAR identity. The canonicalJson transport field carries the exact signed JSON bytes as protobuf JSON base64. Decode those bytes before checking their digest; do not parse and reserialize the document first. etag is the document digest. A search-to-read client should send the result's release with its exact package, version, and platform, then check the returned commit and digest against the result.

The schema-named method returns the package's native reference; it does not return an independently authored schema. Interface metadata identifies each interface's release owner: package interfaces use the owning package release, and OS/base interfaces use the OS release. moduleRequirements entries preserve owner, package, and packageVersion; osRequirements entries preserve owner and osVersion for the selected host OS. Plain dependencies inherit the recipe's generated package.versionRequirement; explicit source pins remain exact. These fields are generated from the same module declarations; they do not report a resolver decision. The generic reference schema is available through local documentation tooling. Native comparison output keeps option path segments and [ability, operation] pairs separate, and compares option type/mutability/extension policy and operation input/result types, handler availability, and configured instances. It also reports interface release owner changes and module requirement changes by exact [owner, package] pairs. Prose changes and observed runtime state are outside that comparison.

#Read native release declarations and reporter assertions

GetPackageAbilityReference returns the exact native reference bytes with the completed release, commit, tag, snapshot, and document digest. The retired manifest/provider-plan identity fields are reserved. GetReleaseAbilityGraph returns aos.module.release-graph: an authenticated release and platform pin with exact package references. It aggregates declarations; it does not infer executed effects or handler edges.

ReportPackageAbilityDeployment accepts aos.module.deployment-report, binding one enrolled deployment slot and strictly increasing sequence to an exact native package reference. Hub checks the desired transaction graph, declaration input and result contracts, and any reported result values. The active enrolled principal and current enrollment resource version must match. Reports expire within 300 seconds; reads require audit.read and recheck enrollment liveness. Exact identities and checked values establish the report's scope, not proof of live runtime state. The graph is desired state and outputs are reporter assertions. Migrating from retired report formats clears their assertion bytes while preserving enrollment and the sequence replay fence.

#Inspect a native runtime document

This stateless endpoint is available when the browse UI is mounted:

POST /-/api/runtime-documentation
POST /-/api/runtime-documentation?format=html

Send raw JSON with schema aos.module.documentation or aos.package.transaction. The shared native reader validates the document; transaction input includes checked graph identities, dependencies, and ordering. The default response is parsed JSON; format=html returns an HTML fragment with package/operation links or the ordered execution path. Invalid documents or formats return HTTP 400. Requests share the Hub's 8 MiB body ceiling.

curl --data-binary @options.json -H 'Content-Type: application/json' \
  'https://hub.example/-/api/runtime-documentation?format=html'

The endpoint does not retain uploads, evaluate Nix, execute handlers, authenticate release provenance, or add documents to a release index. Successful inspection responses use Cache-Control: no-store. This read-only browser support endpoint is separate from the release documentation Connect service. See the runtime abilities guide for native declaration and transaction examples.

#Unpublished registry release candidates

aos.hub.v1.PublishService exposes these Connect methods. Every operation, including inventory reads, requires the registry's Publish permission.

MethodPurpose
UpsertStagedReleaseSave or attach one portable candidate revision with compare-and-swap
GetStagedReleaseRead its exact signed commit, withheld pointer bytes, and inventory
ListStagedReleasesList permissioned candidates with page_size, page_token, and next_page_token
FinalizeStagedReleasePublish the frozen revision and reserved signed release identity
DiscardStagedReleaseRelinquish a candidate after an exact revision check

Each method is a POST to /aos.hub.v1.PublishService/<method>. UpsertStagedRelease takes registry, exactly one of canonical revision_json or gzip revision_gzip bytes in the shared aos.registry-stage/v1 schema, expected_revision (0 for creation; the observed revision for an edit or attachment), and an optional publication_id that may initially be empty. The Connect envelope is capped at 8 MiB, decoded revision JSON at 32 MiB, and compressed bytes at 6 MiB minus 4 KiB. A revision has at most 50,000 objects. Protobuf JSON encodes gzip bytes as base64; pointer bytes within the revision also use base64 strings. Detail reads return revision_gzip; list summaries leave both payload fields empty. These limits cover metadata, not artifacts; bulk object admission uses the existing chunked publication-manifest protocol.

FinalizeStagedRelease takes registry, stage_id, expected_revision, and release_id matching the version declared by that revision. Releasing freezes the revision; retries continue the exact signed tag, commit, and release/OCI bindings after public verification. Discarded or superseded candidate roots retain a 24-hour grace period, while released and shared roots remain retained. Default public catalogs and channel pointers never discover unfinished stages.

For an AOS distribution timestamp, admission binds the exact prepared envelope to its immutable metadata inventory and applies the existing publication and monotonic timestamp rules. Registry tag verification and consumer verification of distribution TUF signatures against pinned roots are distinct checks. Hub admission does not infer root trust from a candidate-supplied root.

See the console workflow and the common stage contract for candidate inspection, resume, and the distinction between staged bytes and publication.