Skip to content

Office Action Contract

Status: Accepted implementation contract

Date: 2026-07-28

This document defines the stable Agent Action transport and safety contract for the Office families listed in Office Web, API v1, and Action surface compatibility. It supplements, rather than replaces, the product-specific REST contracts. Public delivery routes are not Action routes and retain their resource-specific authorization.

The Action HTTP surface is:

Method and routeIdentityContract
GET /api/v1/actions/manifestUser session or ari_cli_* CLI keyReturns the external Agent catalog. An optional agentId is accepted only for an Agent owned by the authenticated user.
GET /api/v1/actions/agent-manifestari_* Agent tokenReturns the external Agent catalog for an authenticated Agent runtime.
POST /api/v1/actions/callari_* Agent tokenExecutes one flat or umbrella Action call.
POST /api/v1/actions/confirm/{confirmationId}Triggering userApproves a pending high-impact call.
POST /api/v1/actions/confirm/{confirmationId}/rejectTriggering userRejects a pending high-impact call.

The manifest body contains a content-addressed manifestVersion; manifest responses expose the same value as a strong ETag. Consumers should cache by that value and refresh their schemas when it changes.

Action definitions and umbrella mappings in apps/rust-server/src/actions/ are the executable source of truth. The manifest is generated at runtime from that registry. This repository does not keep a second generated Action catalog, OpenAPI document, or SDK package that could drift from it. The durable human-readable references are this document, apps/rust-server/src/routes/mcp_tools_readme.md, and API v1 lifecycle. REST ownership is generated into Rust backend route inventory.

The public manifest prefers one underscore-named umbrella per Office family. An umbrella call uses sub_action and optional params:

{
"id": "stable-call-id",
"action": "arinova_sheet",
"arguments": {
"sub_action": "rename_workbook",
"params": {
"workbookId": "00000000-0000-0000-0000-000000000001",
"name": "Forecast"
}
}
}

The equivalent historical flat action remains directly executable:

{
"id": "another-stable-call-id",
"action": "arinova.sheet.rename_workbook",
"arguments": {
"workbookId": "00000000-0000-0000-0000-000000000001",
"name": "Forecast"
}
}

Resolution order is a compatibility and security invariant:

  1. Resolve the umbrella and validate sub_action/params.
  2. Select the registered flat definition.
  3. Validate the resolved argument schema and size.
  4. Apply the resolved create-capability gate.
  5. Apply idempotency and rate limiting.
  6. Apply conversation membership and public-context policy.
  7. Persist the redacted audit intent and apply confirmation/drift policy.
  8. Invoke the product handler, including its current resource authorization, and persist the terminal audit projection.

The response action and persisted audit action remain the public name used by the caller. Umbrella audit metadata also records subAction and flatActionResolved. A flat call records its flat name without fabricated umbrella metadata. Unknown top-level arguments are rejected after resolution; the umbrella itself accepts only sub_action and params.

Manifest umbrella entries use permissionScope: "umbrella" because their selected operation is not known during discovery. Execution always enforces the resolved flat definition’s scope, confirmation, public-context policy, argument limit, timeout, redaction paths, and handler.

Permission scopes are stable registry metadata, not a substitute for resource authorization. Agent calls must also match the owner and hold the current direct or Space-derived resource grant/role required by the product. Knowing a resource UUID is never sufficient.

UmbrellaScope vocabulary used by the added surfaceHigh-impact confirmation contract
arinova_kanbankanban:board:read, kanban:board:create, kanban:board:writedelete_column uses user_confirm and strict drift; a Done or non-empty column remains protected.
arinova_notenotebook:read, notebook:create, notebook:write, notebook:deletedelete_notebook uses user_confirm and strict drift; it must still be archived, empty, non-default, owned, and writable.
arinova_calendarcalendar:read, calendar:create, calendar:write, calendar:deletedelete_calendar uses user_confirm and strict drift; default and device-mirrored calendars remain protected.
arinova_docdoc:read, doc:write, doc:exportThe added unarchive/export operations do not require confirmation; existing product validation still applies.
arinova_sheetsheet:read, sheet:create, sheet:write, sheet:export, plus sheet:version:*Added rename/archive/unarchive/export operations do not require confirmation. Version restore retains user_confirm and optimistic-head validation.
arinova_slideslide:read, slide:write, slide:export, plus slide:version:*Added archive/unarchive/export operations do not require confirmation. Permanent deletes and version restore retain user_confirm.
arinova_mindmapmindmap:read, mindmap:write, mindmap:export, plus mindmap:version:*Added archive/unarchive/export operations do not require confirmation. Destructive replace/delete and version restore retain their registered confirmation policy.
arinova_image_projectimage_project:read, image_project:create, image_project:writeNo current resource Action uses confirmation. Revision commit instead requires a strict optimistic revision and managed project assets.
arinova_formform:read, form:write, form:export, plus form:version:*Added reopen/export operations do not require confirmation. Publish, permanent delete, and version restore retain user_confirm.
arinova_workflowworkflow:read, workflow:create, workflow:update, workflow:delete, workflow:runDelete, activate, run, and cancel-run use user_confirm and strict drift.

arinova.office_apps.enable is a flat, non-umbrella setup Action with office_apps:write. Its input is {"apps": [...]}, whose item enum is locked to the 14 installable first-party App kinds. It is visible in every Agent catalog, but execution requires the triggering user to be the Agent owner and is never allowed in a public/community context. The low-risk additive mutation uses confirmation: none, driftPolicy: none, and returns the requested kinds partitioned into enabled and alreadyEnabled. Repeating a request is therefore naturally idempotent. Dry-run validates and canonicalizes the list without changing settings. There is deliberately no Agent-facing disable Action; removing Apps remains an explicit owner UI operation.

Creating a Doc, Kanban board, Calendar, Image Project, Workflow, Form, Mindmap, Slide deck, Workbook, or Notebook also passes the owner-managed create-capability gate. The gate is applied equally to umbrella calls, flat calls, and dry runs. Disabling future creation does not revoke an otherwise valid grant to an existing resource.

All added Office writes are unavailable in public/community conversation contexts. A read-only flat definition may opt in explicitly through its registry policy, but an umbrella name never broadens that decision. Public share tokens cannot call Actions and Action grants do not authorize public delivery administration.

dryRun: true applies the same identity, create-capability, schema, resource, and policy validation as execution. Product handlers return bounded would*, validated-resource, or export-plan metadata. A dry run creates no Office resource mutation, version checkpoint, event, cache invalidation, export, billing entry, or workflow queue dispatch. The transport may retain its redacted control-plane call/audit row; that row is not a product side effect, is excluded from normal message Action state, and does not broadcast an Action card.

The inbound id is the Action idempotency key, scoped to the Agent and conversation. A retry must keep the same public action, sub-action, and canonical arguments. An exact retry replays the stored safe result; reuse with different intent returns IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_ARGS. Retryable Office creates, exports, Image Project commits, and Workflow runs derive their internal resource or operation key from this stable call identity so a transport retry does not duplicate the domain side effect.

Office definitions advertise cancellable: false; no generic Action-call cancellation is promised once their handler starts. arinova_workflow’s cancel_run is a confirmed Workflow domain operation and is distinct from cancelling the Action transport itself.

An execute call whose resolved flat definition declares user_confirm returns status: "requires_confirmation" with a confirmation identifier, summary, and expiry. Dry-run bypasses the approval pause and reports the validated would* outcome. Only the triggering user can approve or reject.

Approval resumes the already audited intent, resolves the original flat definition, rechecks the current conversation surface, and invokes the same product handler used by a direct call. That handler revalidates current Agent policy and resource grant, archived/read-only safeguards, optimistic head/revision, and other product invariants. A grant revoked while approval is pending therefore fails closed instead of authorizing from a stale snapshot.

POST /api/v1/actions/call always returns the stable Action result shape:

{
"type": "action_result",
"id": "stable-call-id",
"taskId": null,
"action": "arinova_sheet",
"status": "success",
"result": {},
"error": null,
"confirmation": null,
"progress": null,
"traceId": "trace-uuid",
"actionVersion": "1.0.0",
"completedAt": "2026-07-28T00:00:00Z",
"dryRun": false
}

Errors use { "code", "message", "details" } inside the same envelope. Office consumers must branch on the stable machine code, not the human message. Relevant codes include UNKNOWN_ACTION, INVALID_ARGUMENTS, MISSING_REQUIRED_ARGUMENT, PERMISSION_DENIED, RESOURCE_NOT_FOUND, RESOURCE_CONFLICT, IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_ARGS, RATE_LIMITED, ACTION_TIMEOUT, and INTERNAL_ERROR. Confirmation HTTP routes additionally expose stable CONFIRMATION_EXPIRED and ACTION_ALREADY_RESOLVED API errors. traceId is safe to give operators; internal database/provider details remain sanitized.

The audit model records the owner, actual Agent actor, public action, sub-action, resolved flat action, resource kind/id when present, status, trace, and redacted arguments/result projection. Raw document bodies, form responses, speaker notes, prompts, image bytes, storage keys, and exported file content must not be persisted in audit or metrics. Export results contain only bounded File Center metadata and safe resource links.

Build a7f47a5ca54ddcf7806cd48b81ce1b9827042766