{"agent_doc":"/agent.md","api_root":"/i/api/v1/:tenant","routes":[{"description":"AGENT.md system bootstrap doc (text/markdown; Bearer token required when ASPEN_ENABLE_AUTH=1 — POST /auth/login to begin)","method":"GET","path":"/agent.md"},{"description":"download the Rust trigger-authoring SDK as a versioned starter kit (.tar.gz: SDK + template crate + build.sh); X-Aspen-SDK-Version header; public","method":"GET","path":"/trigger-sdk"},{"description":"list tenant names","method":"GET","path":"/tenants"},{"description":"system configuration: enabled capability gates (auth, tenant_admin, deploy) + DB backend + trigger engine availability (incl. query-capable triggers); public","method":"GET","path":"/config"},{"description":"request a one-time email login code; body {email}; always a generic 200","method":"POST","path":"/auth/login"},{"description":"exchange an OTP for a session bearer token; body {email, code} → {token, expires_at, user} or 401","method":"POST","path":"/auth/verify"},{"description":"the authenticated identity + user + tenant memberships (Bearer token)","method":"GET","path":"/auth/me"},{"description":"revoke the presented bearer token","method":"POST","path":"/auth/logout"},{"description":"mint a static API token; body {label?, expires_in_days?} → plaintext shown ONCE","method":"POST","path":"/auth/tokens"},{"description":"list the caller's tokens (metadata only, never the secret)","method":"GET","path":"/auth/tokens"},{"description":"revoke one of the caller's tokens","method":"DELETE","path":"/auth/tokens/:id"},{"description":"allowlist a user; body {email, display_name?, metadata?}","method":"POST","path":"/auth/users"},{"description":"list users","method":"GET","path":"/auth/users"},{"description":"one user + memberships","method":"GET","path":"/auth/users/:id"},{"description":"update display_name / metadata","method":"PATCH","path":"/auth/users/:id"},{"description":"soft-disable a user (no OTPs, tokens stop resolving)","method":"POST","path":"/auth/users/:id/disable"},{"description":"assign a user to a tenant; body {role?} (recorded, not yet enforced)","method":"PUT","path":"/auth/users/:id/memberships/:tenant"},{"description":"remove a tenant assignment","method":"DELETE","path":"/auth/users/:id/memberships/:tenant"},{"description":"create a record; body {actor, fields, migration_mode?}","method":"POST","path":"/i/api/v1/:tenant/objects/:entity/records"},{"description":"batch create; body {actor, records:[{...}], migration_mode?} → 201/207","method":"POST","path":"/i/api/v1/:tenant/objects/:entity/records/batch"},{"description":"list records; optional ?stage=<key>&offset=&limit=","method":"GET","path":"/i/api/v1/:tenant/objects/:entity/records"},{"description":"read one record","method":"GET","path":"/i/api/v1/:tenant/objects/:entity/records/:id"},{"description":"set non-state fields; body {fields:{...}}","method":"PATCH","path":"/i/api/v1/:tenant/objects/:entity/records/:id"},{"description":"hard-delete a record","method":"DELETE","path":"/i/api/v1/:tenant/objects/:entity/records/:id"},{"description":"fire a lifecycle transition; body {actor}","method":"POST","path":"/i/api/v1/:tenant/objects/:entity/records/:id/actions/transition/:key"},{"description":"enroll an episodic (opt-in) record into its governing pipeline's initial stage; body {actor} → {from:null, to:<initial>}","method":"POST","path":"/i/api/v1/:tenant/objects/:entity/records/:id/actions/enter-pipeline"},{"description":"withdraw a record from its pipeline back to stateless; body {actor} → {from:<current>, to:null}; rejected for bound pipelines","method":"POST","path":"/i/api/v1/:tenant/objects/:entity/records/:id/actions/exit-pipeline"},{"description":"list transitions fireable from current state","method":"GET","path":"/i/api/v1/:tenant/objects/:entity/records/:id/actions/available-transitions"},{"description":"state_history audit trail; optional ?offset=&limit=","method":"GET","path":"/i/api/v1/:tenant/objects/:entity/records/:id/history"},{"description":"field_history audit trail (non-state field changes); optional ?offset=&limit=","method":"GET","path":"/i/api/v1/:tenant/objects/:entity/records/:id/field-history"},{"description":"list active and historical pipeline instances for a record; optional ?offset=&limit=","method":"GET","path":"/i/api/v1/:tenant/objects/:entity/records/:id/pipelines"},{"description":"list-view-backed grid rows (list view → XQL); optional ?filter=<xql-where>&offset=&limit=","method":"GET","path":"/i/api/v1/:tenant/objects/:entity/list-views/:lv/records"},{"description":"picklist options for a field: [{name,label,active}] (404 unknown entity/field, 400 non-picklist)","method":"GET","path":"/i/api/v1/:tenant/objects/:entity/fields/:field/options"},{"description":"id/polyid target picker: bound-LIKE search over the display field; ?q=&offset=&limit= → [{id,display,...}]","method":"GET","path":"/i/api/v1/:tenant/objects/:entity/lookup"},{"description":"list all object components","method":"GET","path":"/i/api/v1/:tenant/component/describe"},{"description":"one object component (404 if unknown)","method":"GET","path":"/i/api/v1/:tenant/component/describe/:name"},{"description":"effective component for a context (stub: returns describe)","method":"POST","path":"/i/api/v1/:tenant/component/effective/:name"},{"description":"effective behavioral model for an object/subtype: identity + lifecycle (states/guards/actions/bound|episodic) + relationships (out/in) + reactions (observers in/out) + scripts; ?depth=N walks edges to neighbours; 404 unknown","method":"GET","path":"/i/api/v1/:tenant/component/behavior/:name"},{"description":"reverse-dependency / blast-radius: OTHER components referencing :name (schema_dependents) + live data counts for objects/subtypes (records, incoming_relationships, incoming_polyid_refs); ?field=<f> restricts to references of that field; 404 unknown","method":"GET","path":"/i/api/v1/:tenant/component/:name/dependents"},{"description":"download a record-trigger's compiled .wasm bytes (application/wasm) — the body the behavior view marks opaque; makes a trigger fully reconstructable over the API; 404 unknown trigger","method":"GET","path":"/i/api/v1/:tenant/component/trigger/:name/module"},{"description":"XQL query; body {query, describe?}","method":"POST","path":"/i/api/v1/:tenant/query"},{"description":"XQL row count; body {query}","method":"POST","path":"/i/api/v1/:tenant/rowcount"},{"description":"open XQL cursor (§10.8); body {query, actor?} → page 0","method":"POST","path":"/i/api/v1/:tenant/cursor"},{"description":"fetch XQL cursor page; ?l=<page>&d=forward|backward, body {actor?}","method":"POST","path":"/i/api/v1/:tenant/cursor/:id"},{"description":"create a relationship edge; body {actor, type, from:{id,type}, to:{id,type}, fields?, metadata?} → 201 {id} (rich edge types accept their typed `fields`)","method":"POST","path":"/i/api/v1/:tenant/relationships"},{"description":"bulk-create edges; body {actor, relationships:[{type, from, to, fields?, metadata?}]} → 201 all-ok / 207 multi-status {results, success_count, error_count}","method":"POST","path":"/i/api/v1/:tenant/relationships/batch"},{"description":"read one relationship edge (forward-oriented view incl. typed fields); 404 unknown","method":"GET","path":"/i/api/v1/:tenant/relationships/:id"},{"description":"list a record's edges oriented to it; ?direction=both|out|in (default both) &active=true|false (default true)","method":"GET","path":"/i/api/v1/:tenant/objects/:entity/records/:id/relationships"},{"description":"soft-end a temporal edge (stamp ended_at); body {actor} → {id, ended:true}","method":"POST","path":"/i/api/v1/:tenant/relationships/:id/end"},{"description":"hard-delete a relationship edge → {id}","method":"DELETE","path":"/i/api/v1/:tenant/relationships/:id"},{"description":"a pipeline's authored definition: stages (in order, with initial/terminal) + transitions (from/to/guard); 404 unknown key","method":"GET","path":"/i/api/v1/:tenant/pipelines/:key"},{"description":"start/enroll a subject in a pipeline; body {actor, pipeline, subject:{id,type}, metadata?}","method":"POST","path":"/i/api/v1/:tenant/pipeline-instances"},{"description":"bulk-enroll; body {actor, instances:[{pipeline, subject:{id,type}, metadata?}]} → 201 all-ok / 207 multi-status {results, success_count, error_count}","method":"POST","path":"/i/api/v1/:tenant/pipeline-instances/batch"},{"description":"read one pipeline instance","method":"GET","path":"/i/api/v1/:tenant/pipeline-instances/:id"},{"description":"fire a transition on one pipeline instance; body {actor}","method":"POST","path":"/i/api/v1/:tenant/pipeline-instances/:id/actions/transition/:key"},{"description":"end an optional active pipeline instance; body {actor}","method":"POST","path":"/i/api/v1/:tenant/pipeline-instances/:id/end"},{"description":"navigation/tabs source: [{name,label,object,icon}] for all active views","method":"GET","path":"/i/api/v1/:tenant/views"},{"description":"view definition (ViewComponent); 404 unknown","method":"GET","path":"/i/api/v1/:tenant/views/:name"},{"description":"run view; grid rows + columns; optional ?filter=<xql-where>&offset=&limit=","method":"GET","path":"/i/api/v1/:tenant/views/:name/records"},{"description":"membership check + full object read; 404 if record not in view","method":"GET","path":"/i/api/v1/:tenant/views/:name/records/:id"},{"description":"§VW4 view effective model: {view, write_capability, object}; 404 unknown","method":"GET","path":"/i/api/v1/:tenant/views/:name/effective"},{"description":"client-authored UI metadata staging doc (custom list views, …); empty doc if absent","method":"GET","path":"/i/api/v1/:tenant/user-metadata"},{"description":"overwrite the user-metadata staging doc; body is the whole JSON document","method":"PUT","path":"/i/api/v1/:tenant/user-metadata"},{"description":"Model Context Protocol endpoint (JSON-RPC 2.0): basic record CRUD tools — create/get/update/delete/list, XQL query, lifecycle transitions, and read-only introspection (describe_object/object_behavior/object_dependents) (only when ASPEN_ENABLE_MCP=1)","method":"POST","path":"/i/api/v1/:tenant/mcp"},{"description":"dry-run: validate + plan + shadow-apply the submitted schema; nothing live touched; body {actor, files:[{path,content}], expected_plan_hash?} (only when ASPEN_ENABLE_DEPLOY=1)","method":"POST","path":"/i/api/v1/:tenant/deploy/verify"},{"description":"apply the submitted schema and hot-swap the live model; body {actor, files:[{path,content}], expected_plan_hash?} (only when ASPEN_ENABLE_DEPLOY=1)","method":"POST","path":"/i/api/v1/:tenant/deploy/apply"}],"service":"aspen-api","trigger_sdk":"/trigger-sdk"}