Skip to content

Admin API

The Admin API is the only runtime write surface for workflow authoring and publication. It is implemented in src/rimthan_admin_api/server.py and exposed by the rimthan-admin-api console script. The participant MCP server never exposes these writes; see Participant Architecture.

Configuration and middleware

AdminApiConfig.from_environment requires:

  • RIMTHAN_ADMIN_PUBLIC_URL: exact HTTPS origin with no path extras;
  • RIMTHAN_ADMIN_DATABASE_URL: PostgreSQL URL;
  • RIMTHAN_ADMIN_BEARER_TOKEN: at least 32 non-whitespace characters;
  • RIMTHAN_PUBLICATION_SIGNING_KEY_ID;
  • RIMTHAN_PUBLICATION_ED25519_PRIVATE_KEY_B64: raw 32-byte Ed25519 private key in unpadded base64url;
  • optional RIMTHAN_ADMIN_ALLOWED_ORIGINS for Studio CORS;
  • bind host and port.

AdminAuthAndLimitMiddleware protects all routes except /healthz, /readyz, and OPTIONS. It checks Authorization: Bearer ... with secrets.compare_digest, limits request bodies to maximum_request_bytes (2 MiB default), converts RegistryError into JSON errors, and adds private no-store and frame/sniffing headers.

When allowed_origins is non-empty, create_admin_app adds Starlette CORSMiddleware with those exact origins, methods GET, POST, and OPTIONS, allowed headers Authorization, Content-Type, and X-Rimthan-Actor, no credentials, and max_age=600. _json_body accepts only JSON objects and maps malformed JSON or non-object bodies to PublicationError. _actor derives actor attribution from X-Rimthan-Actor, defaults to admin, strips whitespace, and requires 1-200 characters; save, migrate, publish, and channel activation pass that actor to store/service methods so revisions, jobs, channels, and audit events are attributed consistently.

App bootstrapping

create_admin_app constructs a PostgresRegistryStore, applies migrations with roles, loads the packaged built-in release through ReleaseLoader, imports that release into PostgreSQL, creates an Ed25519ManifestSigner, builds a trust root for published releases, and wraps everything in AdminDomain.

AdminDomain.service(workflow_kind=...) selects WorkflowEngineDraftCompiler for step-gate workflows and WorkflowDraftCompiler for legacy module-graph workflows. For step-gate publication it attempts to use the currently active production release as source, so aggregate releases preserve previously published workflow definitions, steps, assets, and validators.

Endpoint families

RouteMethodHandlerResponsibility
/healthzGEThealthProcess health without auth.
/readyzGETreadyVerifies store can list channels.
/admin/v1/workflowsGETworkflowsList current workflow draft heads.
/admin/v1/workflows/starterGETworkflow_starterReturn packaged starter/workflow-engine/research-decision.draft.json as a step-gate starter.
/admin/v1/workflowsPOSTsave_workflowSave a legacy or step-gate draft revision with optimistic concurrency and editor layout.
/admin/v1/workflows/{workflow_id}/migrate-to-enginePOSTmigrate_workflowExplicitly replace a legacy draft head with a step-gate revision.
/admin/v1/workflows/{workflow_id}GETworkflowReturn current draft head.
/admin/v1/workflows/{workflow_id}/revisionsGETworkflow_revisionsList immutable revision summaries.
/admin/v1/workflows/{workflow_id}/revisions/{revision}GETworkflow_revisionReturn exact revision snapshot and editor layout.
/admin/v1/workflows/{workflow_id}/validatePOSTvalidate_workflowCompile an exact revision as preview and return manifest, digest, counts, and dependency diff.
/admin/v1/workflows/{workflow_id}/publishPOSTpublish_workflowPublish an exact revision and optionally activate a channel.
/admin/v1/modulesGETmodulesReturn source modules and presentation bundles for Studio editing.
/admin/v1/assetsGETassetsReturn registry asset and validator definition drafts.
/admin/v1/releasesGETreleasesList immutable releases.
/admin/v1/releases/{release_id}GETrelease_detailReturn metadata, manifest, workflow dependency view, and legacy module dependency view.
/admin/v1/channelsGETchannelsList active channel states.
/admin/v1/channels/{channel}/activatePOSTactivateGeneration-fenced rollback or activation of an existing signed release.
/admin/v1/trust-rootGETtrustReturn the public trust root used by MCP.

Draft save and migration behavior

save_workflow chooses store.save_engine_workflow_draft when workflow_kind is step-gate or the document contains definition; otherwise it uses save_workflow_draft. The store validates the document, computes a semantic digest that excludes layout and revision metadata, enforces expected-revision concurrency, writes the mutable head, appends an immutable revision row, and records an audit event.

migrate_workflow is intentionally separate. It requires the route workflow ID to match document.workflow_id, requires an existing legacy module-graph head, advances revision by one, changes workflow_kind to step-gate, saves engine assets and validators, and records workflow_migrated_to_engine. This separation prevents accidental kind changes.

Validation preview and publication

validate_workflow loads one stored revision, selects the compiler by document shape, compiles with a preview release value (default 0.0.0-preview), checks the compiled source revision equals the stored semantic digest, and returns:

  • workflow revision and source revision;
  • compiled manifest SHA-256 and complete manifest;
  • module, presentation, workflow definition, step, asset, and validator counts;
  • source registry release;
  • dependency diff from _compiled_manifest_diff showing added, removed, changed, and retained immutable identities.

publish_workflow delegates to PublicationService.publish with workflow ID, revision, target release, optional target channel, actor, idempotency key, and expected channel generation. It returns status: published, job ID, release ID, manifest SHA-256, and channel state.

Release detail

release_detail loads a release by UUID and verifies it with the trust root when release_mode == "published". It constructs workflow_dependencies by walking every workflow definition and its steps, collecting step instruction assets, output schemas, host assets, validator references, validator instruction assets, and validator output schemas. It also returns legacy module_dependencies. Workflow Studio uses this to display compiled dependency views.

Tests

  • tests/test_admin_api.py::test_admin_api_authors_publishes_and_lists_a_signed_release covers auth, CORS preflight, draft save, revision history, publish, release listing, channel listing, trust root, MCP refresh, rollback, migration to engine, aggregate publication, and workflow-engine MCP startup from published releases.
  • tests/test_postgres_publication_e2e.py covers the same domain below HTTP, including immutable triggers and channel generation conflicts.
  • apps/admin-web/tests/studio.spec.ts mocks Admin API routes to prove Studio restores immutable history and exposes release dependency detail.

Focused validation

  • Without PostgreSQL: uv run pytest tests/test_workflow_engine.py tests/test_workflow_publication.py
  • With admin PostgreSQL DSN: RIMTHAN_TEST_ADMIN_POSTGRES_DSN=... uv run pytest tests/test_admin_api.py

Generated from the committed OpenWiki knowledge bundle.