{
  "schemaVersion": "1.0",
  "title": "Run a governed Hermes operator lifecycle",
  "description": "Use this guide to take one direct Hermes operator objective from its AIP approval to completion, a provider approval, a failure, or a controlled stop. It keeps every identity and approval decision attached to the work it governs.",
  "canonical": "https://getaip.org/docs/connectors/hermes-agent/guides/operator-lifecycle",
  "route": "/docs/connectors/hermes-agent/guides/operator-lifecycle",
  "source": "docs/connectors/hermes-agent/guides/operator-lifecycle.md",
  "protocol": "Agent Interoperability Protocol",
  "protocolVersion": "1.0",
  "section": "Connectors",
  "documentType": "Connector",
  "language": "en",
  "downloads": {
    "md": "/docs/download/connectors/hermes-agent/guides/operator-lifecycle.md",
    "txt": "/docs/download/connectors/hermes-agent/guides/operator-lifecycle.txt",
    "json": "/docs/download/connectors/hermes-agent/guides/operator-lifecycle.json",
    "pdf": "/docs/download/connectors/hermes-agent/guides/operator-lifecycle.pdf"
  },
  "content": {
    "format": "text/markdown",
    "markdown": "---\ntitle: Run a governed Hermes operator lifecycle\ndescription: >-\n  Submit one bounded operator objective, pass both approval layers, resume the\n  same Hermes run, and recover or cancel without duplicating uncertain work\nkind: how-to\naudience: application-developer\nappliesTo: \"1.x\"\nwritingStandard: \"aip-docs/1.0\"\nlastReviewedRevision: \"97be86e9efedf07ecf1783b03800f683f107fb04\"\nconnector: hermes-agent\ncapabilityIds:\n  - cap:hermes_agent:<endpoint_id>:operator\n---\n\n# Run a governed Hermes operator lifecycle\n\nUse this guide to take one direct Hermes operator objective from its AIP\napproval to completion, a provider approval, a failure, or a controlled stop.\nIt keeps every identity and approval decision attached to the work it governs.\n\nThe operator can execute models, tools, messages, code, and external network\noperations. Never create a replacement Action after an uncertain start,\napproval, or cancellation. Query and reconcile the recorded identities first.\n\nThis guide covers direct objectives and their provider-approval resumes. For\nfirst-class AIP delegation, use the operator capability reference instead.\n\n## Understand the identity ledger\n\nOne objective can acquire several related identifiers.\n\n| Identity | Owner | Lifetime and use |\n|---|---|---|\n| Source Action ID | AIP runtime | Stable identity of the original objective and operator binding |\n| Source idempotency key | AIP runtime | Required capability-scoped replay key for that exact objective |\n| AIP approval ID | AIP runtime | Authorizes one high-risk source or resume Action |\n| Approval decision ID | AIP runtime | Makes one approval vote replayable without duplicating it |\n| Hermes `run_id` | Hermes process | Addresses the volatile provider run after start is bound |\n| Hermes `session_id` | Connector and Hermes | Deterministically `aip-operator-<source_action_id>` |\n| Provider approval generation | Connector binding | Distinguishes successive Hermes approval prompts in one run |\n| Resume Action ID | AIP runtime | New identity for one provider approval response |\n| Resume idempotency key | AIP runtime | New required key for that exact resume Action |\n\nPersist the complete ledger in application state. Do not use `run_id`, an\napproval ID, or a resume Action ID in place of the source Action ID.\n\n## Separate the two approval loops\n\nThe lifecycle has two independent approval layers.\n\n| Layer | AIP result | What the reviewer decides | How work continues |\n|---|---|---|---|\n| Capability approval | `pending_approval` with an AIP `approval_id` | Whether this exact high-risk Action may execute | A verified AIP decision resumes the same queued Action |\n| Hermes provider approval | `requires_human` with output status `waiting_for_approval` | Whether pending tool work inside the bound Hermes run may proceed | A new operator resume Action carries `once`, `session`, `always`, or `deny` |\n\nAn AIP approval does not answer a Hermes prompt. A Hermes choice does not\nauthorize a high-risk AIP Action. Every resume Action passes the first layer\nbefore it can change the second.\n\n## Before you start\n\nConfirm all of these conditions:\n\n- the endpoint-qualified `operator` capability is admitted and visible to the\n  request tenant;\n- the requester can invoke the capability and read its Action lifecycle;\n- a transport-authenticated reviewer who differs from the requester has\n  tenant-policy approval authority;\n- the AIP Action, approval, lifecycle, idempotency, and connector profile-state\n  backends have the durability claimed by the deployment;\n- every downstream capability the objective may use is separately admitted and\n  governed;\n- raw objective, provider event, tool, and result data is handled as\n  confidential and PII-bearing.\n\nThe capability timeout is 15 minutes. The generated AIP approval request also\nexpires after 15 minutes. These are configured contract values, not observed\navailability or completion guarantees.\n\n## 1. Allocate the source identity\n\nGenerate the source Action ID and idempotency key before submission. Retain\nthem with the endpoint, tenant, requester, and exact objective input.\n\n```sh\nexport AIP_CAPABILITY_ID='cap:hermes_agent:primary:operator'\nexport AIP_SOURCE_ACTION_ID='act_0123456789abcdef0123456789abcdef'\nexport AIP_SOURCE_KEY='operator-objective-case-example-2030-01'\n```\n\nOne source Action ID identifies one exact endpoint and input. Reusing it with a\nchanged objective, context, constraint, endpoint, or delegation shape is an\nidempotency collision.\n\nThe connector uses the source ID to create the stable Hermes session ID and to\nkey the durable operator binding. The provider `POST /v1/runs` route is not\nidempotent; the binding's start claim is the second replay fence.\n\n## 2. Prepare a bounded objective\n\nCreate `operator-objective.json` with one outcome and explicit limits:\n\n```json\n{\n  \"objective\": \"Read the open support case and prepare a factual summary.\",\n  \"context\": {\n    \"case_id\": \"case-example-2030\"\n  },\n  \"candidate_capabilities\": [\n    \"cap:support:case.get\"\n  ],\n  \"constraints\": {\n    \"allow_mutations\": false,\n    \"maximum_records\": 1\n  }\n}\n```\n\nThe input must select exactly one of `objective` or `resume`. A direct\nobjective can also carry arbitrary JSON `context`, up to 256 non-empty\ncapability hints, and an object of constraints.\n\n`candidate_capabilities` is a model hint. It cannot admit a capability, grant\nauthority, bypass approval, widen tenant access, or override a schema. Keep\nuntrusted instructions inside data fields and make deployment policy the\nauthority boundary.\n\n## 3. Submit the source Action asynchronously\n\nSubmit the objective with its stable identity and required key:\n\n```sh\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIP_REQUESTER_TOKEN_FILE\" \\\n  action call \"$AIP_URL\" \\\n  \"$AIP_CAPABILITY_ID\" \\\n  --action-id \"$AIP_SOURCE_ACTION_ID\" \\\n  --idempotency-key \"$AIP_SOURCE_KEY\" \\\n  --mode async \\\n  --input @operator-objective.json\n```\n\nWithout a prior verified decision, the high-risk Action does not reach Hermes.\nThe expected response is `pending_approval`, with essential evidence shaped\nlike this:\n\n```json\n{\n  \"action_id\": \"act_0123456789abcdef0123456789abcdef\",\n  \"status\": \"pending_approval\",\n  \"output\": {\n    \"requires_human_approval\": true,\n    \"approval_id\": \"appr_0123456789abcdef0123456789abcdef\",\n    \"capability_id\": \"cap:hermes_agent:primary:operator\"\n  },\n  \"error\": {\n    \"code\": \"policy.human_approval_required\"\n  }\n}\n```\n\nSave the exact `approval_id`. Do not retry the Action to make approval appear;\nthe original Action is already queued behind that record.\n\n## 4. Review the AIP approval record\n\nRead the generated record with the reviewer's authenticated identity:\n\n```sh\nexport AIP_SOURCE_APPROVAL_ID='appr_0123456789abcdef0123456789abcdef'\n\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIP_APPROVER_TOKEN_FILE\" \\\n  approval get \"$AIP_URL\" \"$AIP_SOURCE_APPROVAL_ID\" \\\n  --include-action-status \\\n  --include-receipts\n```\n\nVerify all of these fields before deciding:\n\n1. `action_id` equals the retained source Action ID;\n2. `capability_id` equals the endpoint-qualified operator capability;\n3. requester, subject, operator, tenant, and expiry match the intended work;\n4. the input-snapshot evidence hash covers the submitted objective;\n5. the immutable `policy_hash` is present and unchanged;\n6. reason, risk, side effects, constraints, and evidence support the decision;\n7. the authenticated reviewer is admitted by the required authority policy.\n\nDo not copy raw input into logs merely to review it. Use the bounded approval\nview and an explicitly authorized evidence export when sensitive detail is\nrequired.\n\n## 5. Decide the AIP approval\n\nCreate `source-approval-decision.json`. Copy the exact approval and policy hash\nfrom the record, use a current timestamp, and allocate a stable decision ID:\n\n```json\n{\n  \"approval_id\": \"appr_0123456789abcdef0123456789abcdef\",\n  \"decision\": \"approved\",\n  \"approver\": {\n    \"id\": \"human:operator-reviewer\",\n    \"kind\": \"human\"\n  },\n  \"decided_at\": \"2030-01-15T10:00:00Z\",\n  \"reason\": \"Read-only objective and constraints match the reviewed case.\",\n  \"decision_id\": \"decision_operator_source_001\",\n  \"policy_hash\": \"replace_with_exact_policy_hash\"\n}\n```\n\nThe `approver` must match the transport-authenticated principal. The runtime\nresolves authority itself and records the authority path. The request already\ncontains its input-snapshot and policy-decision evidence; a non-empty decision\nreason satisfies the remaining operator requirement.\n\nSubmit the decision:\n\n```sh\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIP_APPROVER_TOKEN_FILE\" \\\n  approval decide \"$AIP_URL\" @source-approval-decision.json\n```\n\nAn approved terminal decision leases and resumes the same queued source\nAction. Do not submit the objective again and do not attach the decision to a\nreplacement Action. The decision request can remain open while the resumed\noperator executes; observe the Action from a separate consumer.\n\n## 6. Follow the source Action\n\nFollow events and chunks under the source Action ID:\n\n```sh\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIP_REQUESTER_TOKEN_FILE\" \\\n  action events \"$AIP_URL\" \\\n  \"$AIP_SOURCE_ACTION_ID\" \\\n  --include-chunks \\\n  --follow\n```\n\nThe connector publishes provider events under the source Action ID and keeps\none sequence across later resumes.\n\n| Provider event | AIP chunk kind | Application action |\n|---|---|---|\n| `message.delta` | Data | Append visible text from the structured delta |\n| `reasoning.available` | Thought | Retain only under the deployment's reasoning policy |\n| `tool.started`, `tool.completed` | Tool | Correlate tool progress; do not infer the external effect |\n| `approval.request` | PendingApproval | Stop presenting progress as autonomous; review the prompt |\n| `run.failed` | Error | Preserve the typed failure and uncertain effects |\n| `run.completed`, `run.cancelled` | Done | Wait for the corresponding Action result |\n| Any other event | Progress | Preserve the event name without inventing semantics |\n\nInitial observation tries the provider SSE stream. A reconnect, source replay,\nor connector restart polls the bound `run_id` instead of resuming that provider\nstream. AIP chunks already persisted remain readable; unobserved provider\nframes are not reconstructed.\n\n## 7. Classify the first operator result\n\nRead the source status with its result and recorded chunks:\n\n```sh\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIP_REQUESTER_TOKEN_FILE\" \\\n  action status \"$AIP_URL\" \\\n  \"$AIP_SOURCE_ACTION_ID\" \\\n  --include-result \\\n  --include-receipts \\\n  --include-chunks\n```\n\nUse both the AIP status and operator output.\n\n| AIP result | Operator output status | Decision |\n|---|---|---|\n| `completed` | `completed` | Accept only after required downstream effects are independently confirmed |\n| `failed` | `failed` | Inspect the typed error and retain partial effects |\n| `cancelled` | `cancelled` | Treat prior effects as potentially committed |\n| `requires_human` | `waiting_for_approval` | Review the provider prompt and create a new resume Action |\n| `pending_approval` | No provider run yet | Complete the AIP capability approval; do not create a provider resume |\n| `failed` | `outcome_unknown` | Freeze replay and begin manual reconciliation |\n\nAccumulated text, a Done chunk, model prose, or a closed connection is not a\nterminal business decision by itself.\n\n## 8. Review the Hermes provider prompt\n\nA provider approval result retains the source binding and a redacted prompt:\n\n```json\n{\n  \"action_id\": \"act_0123456789abcdef0123456789abcdef\",\n  \"status\": \"requires_human\",\n  \"output\": {\n    \"endpoint_id\": \"primary\",\n    \"run_id\": \"run_0123456789abcdef0123456789abcdef\",\n    \"session_id\": \"aip-operator-act_0123456789abcdef0123456789abcdef\",\n    \"source_action_id\": \"act_0123456789abcdef0123456789abcdef\",\n    \"status\": \"waiting_for_approval\",\n    \"last_event\": \"approval.request\",\n    \"pending_approval\": {\n      \"event\": \"approval.request\",\n      \"description\": \"Review the redacted provider operation\"\n    }\n  }\n}\n```\n\nRetain the `run_id`, but continue to address the operator binding by\n`source_action_id`. Review the actual redacted command, tool, pattern, scope,\nand consequence supplied by the deployment.\n\nChoose the narrowest provider decision:\n\n| Choice | Provider meaning | Use |\n|---|---|---|\n| `once` | Allow this pending operation without persisting an allow rule | Default for one reviewed operation |\n| `session` | Allow the matching pattern for this Hermes gateway session | Only after reviewing the session scope |\n| `always` | Persist the matching allow rule in Hermes configuration | Exceptional administrative decision |\n| `deny` | Reject this pending operation | Use when the operation is not authorized or needed |\n\nLeave `resolve_all` false unless every currently queued provider prompt in the\nrun has been reviewed. AIP approval of the resume does not review those prompts\nfor you.\n\n## 9. Prepare a separately identified resume\n\nAllocate a new Action ID and key for one exact provider decision:\n\n```sh\nexport AIP_RESUME_ACTION_ID='act_abcdef0123456789abcdef0123456789'\nexport AIP_RESUME_KEY='operator-resume-case-example-2030-01'\n```\n\nCreate `operator-resume.json`:\n\n```json\n{\n  \"resume\": {\n    \"source_action_id\": \"act_0123456789abcdef0123456789abcdef\",\n    \"choice\": \"once\",\n    \"resolve_all\": false\n  }\n}\n```\n\nUse `deny` instead of `once` to refuse the provider operation. Never reuse the\nsource Action ID for a resume. Never reuse a prior resume ID, key, approval ID,\nor decision ID for a later provider approval generation.\n\nThe resume capability endpoint must be the same endpoint that owns the source\nbinding. A different endpoint fails before it can answer the provider prompt.\n\n## 10. Approve and observe the resume Action\n\nSubmit the resume as another asynchronous operator Action:\n\n```sh\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIP_REQUESTER_TOKEN_FILE\" \\\n  action call \"$AIP_URL\" \\\n  \"$AIP_CAPABILITY_ID\" \\\n  --action-id \"$AIP_RESUME_ACTION_ID\" \\\n  --idempotency-key \"$AIP_RESUME_KEY\" \\\n  --mode async \\\n  --input @operator-resume.json\n```\n\nThis Action first returns its own AIP `pending_approval`. Repeat steps 4 and 5\nwith the new approval ID, exact new policy hash, and a new decision ID. Review\nthe resume input itself: the decision authorizes sending that exact provider\nchoice to the exact source run.\n\nAfter AIP approval, the connector records a fenced provider-command entry\nbefore calling Hermes. A definitive provider `4xx` rejects the command. A\ntransport failure, provider `5xx`, or lost command owner makes the provider\napproval outcome unknown and blocks replay.\n\nContinue reading operator chunks from the source Action ID. Read settlement\nfrom the current resume Action ID:\n\n```sh\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIP_REQUESTER_TOKEN_FILE\" \\\n  action status \"$AIP_URL\" \\\n  \"$AIP_RESUME_ACTION_ID\" \\\n  --include-result \\\n  --include-receipts \\\n  --wait-ms 60000\n```\n\nIf Hermes raises another provider prompt, allocate another resume Action and\nrepeat this step. Do not mutate or replay the preceding resume.\n\n## 11. Settle from the latest invocation result\n\nAfter a resume, the connector deliberately separates stream and result\nidentity.\n\n| Evidence | Identity | Meaning |\n|---|---|---|\n| Operator chunks | Original source Action ID | Ordered provider progress across the complete bound run |\n| Current ActionResult `action_id` | Latest resume Action ID | Result of this separately governed invocation |\n| Output `source_action_id` | Original source Action ID | Binding whose provider state produced the result |\n| Output `run_id` | Hermes provider run | Volatile provider correlation only |\n\nThe earlier source ActionResult remains `requires_human`; the resume does not\nrewrite it to completed. Do not wait for that old result to change. Accept the\nlatest resume result only when its `output.source_action_id` matches the source\nledger and its output status is terminal.\n\nA representative terminal correlation is:\n\n```json\n{\n  \"action_id\": \"act_abcdef0123456789abcdef0123456789\",\n  \"status\": \"completed\",\n  \"output\": {\n    \"source_action_id\": \"act_0123456789abcdef0123456789abcdef\",\n    \"run_id\": \"run_0123456789abcdef0123456789abcdef\",\n    \"status\": \"completed\",\n    \"last_event\": \"run.completed\"\n  }\n}\n```\n\nProvider completion proves the governed Hermes run ended. Confirm important\ndownstream AIP Actions and external effects from their own authoritative\nlifecycle records rather than from operator prose.\n\n## 12. Recover a disconnect or process restart\n\nOn application delivery loss:\n\n1. keep the source and current invocation IDs unchanged;\n2. query status for the current invocation before considering any submission;\n3. read bounded events and chunks under the source ID from the last native\n   cursor;\n4. read the current AIP approval record if its result is `pending_approval`;\n5. read the current provider prompt if its result is `requires_human`;\n6. accept only a terminal result whose source correlation matches the ledger.\n\nClosing an `action events --follow` connection does not cancel the AIP Action\nor Hermes request. Resume the native delivery route; do not reconnect directly\nto the provider SSE URL.\n\nThe operator binding can survive only when the configured profile-state backend\nis process-durable. Hermes `run_id`, event queue, active task, and provider\napproval queue are process memory. A provider `404` after restart or retention\nloss is an evidence gap, not proof that the run never executed.\n\nDo not create a replacement objective when the provider handle is missing. The\nconnector intentionally refuses to repeat an external start whose outcome may\nalready exist.\n\n## 13. Cancel according to the current phase\n\nNative cancellation has different effects depending on whether an operator\nAction is active.\n\n| Phase | Action to cancel or decide | Provider effect |\n|---|---|---|\n| Waiting for initial AIP approval | Cancel the source Action | No provider run has started |\n| Source Action actively executing | Cancel the source Action | Active connector callback records intent and attempts provider stop |\n| Provider returned `requires_human` | Submit a governed resume with `deny` | Rejects the pending provider operation and returns control to Hermes |\n| Resume Action waiting for AIP approval | Cancel that resume Action | Prevents that provider decision; the source run remains waiting |\n| Resume Action actively executing | Cancel the resume Action | Connector maps its input to the source binding and attempts provider stop |\n| No operator Action is active, but full stop is required | Invoke separately approved `run_stop` with retained `run_id` | Requests provider interruption; binding needs operational reconciliation |\n\nCancel an active Action explicitly:\n\n```sh\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIP_REQUESTER_TOKEN_FILE\" \\\n  action cancel \"$AIP_URL\" \\\n  \"$AIP_RESUME_ACTION_ID\" \\\n  --reason 'The requester withdrew the governed objective'\n```\n\nThe runtime calls the connector only for an active Action. After an invocation\nhas returned `requires_human`, cancelling that inactive native record does not\ncall Hermes. The public operator input has no standalone stop branch.\n\nFor an active invocation, the connector records cancellation intent, maps a\nresume back to the source binding, sends provider stop after a `run_id` is\nbound, and polls within the configured grace. The provider binding can settle\ncompleted, failed, cancelled, or outcome unknown.\n\nThe native cancel response is an AIP cancellation acknowledgement. It does not\nexpose that provider classification and is not proof that Hermes stopped.\nNeither path rolls back model, tool, message, code, or network effects.\n\n## 14. Freeze unsafe unknown outcomes\n\n| Error or observation | What may have happened | Required decision |\n|---|---|---|\n| `operator_outcome_unknown` | Hermes may have accepted a start before `run_id` was bound | Freeze the source identity; reconcile provider and profile state manually |\n| `approval_outcome_unknown` | Hermes may have applied a resume command | Freeze that resume and source; never resend the choice blindly |\n| `cancellation_outcome_unknown` | Stop did not reach a confirmed provider terminal state | Treat provider state and effects as uncertain |\n| Provider `404` after a bound run | Provider process state may be lost or expired | Preserve the gap; do not infer that no run existed |\n| `operator_start_rejected` on provider `4xx` | Hermes definitively rejected the start | Correct the cause before creating a separately reviewed Action |\n| Initial AIP approval denied or expired | No provider run started for that source Action | Keep the terminal record; do not reuse its identifiers |\n| Resume AIP approval denied or expired | No provider choice was sent by that resume; the source run can remain waiting | Keep both records; create a new reviewed resume only for a still-current prompt |\n\nUnknown is a terminal safety classification, not a temporary retry hint. Keep\nthe input fingerprint, endpoint, source and resume IDs, approval records,\nbinding revision, provider diagnostics, and timestamps for reconciliation.\n\n## 15. Verify the integration\n\nBefore accepting the client, use controlled evidence to verify that it:\n\n1. allocates the source Action ID and required key before submission;\n2. persists the exact objective and endpoint with that identity;\n3. distinguishes AIP `pending_approval` from provider `requires_human`;\n4. validates approval ID, policy hash, evidence, authority, and expiry;\n5. lets an approved decision resume the same source Action;\n6. follows operator chunks under the source Action ID;\n7. treats candidate capabilities only as hints;\n8. creates a new Action, key, approval, and decision for every provider resume;\n9. leaves `resolve_all` false unless all queued prompts were reviewed;\n10. reads terminal settlement from the latest resume Action when one exists;\n11. preserves `source_action_id`, `run_id`, and current invocation ID separately;\n12. recovers delivery without submitting replacement work;\n13. cancels only with phase-aware expectations and verifies provider effects;\n14. freezes all three unknown-outcome classes without automatic replay;\n15. redacts objectives, provider prompts, tool data, results, and diagnostics.\n\nThis checklist is source-aligned integration evidence. It is not live provider,\nlatency, storage-durability, cancellation, or production qualification.\n\n## Related documentation\n\n- [Operator and delegation capability](../capabilities/operator-and-delegation.md)\n- [Structured runs and approvals](../capabilities/durable-runs-and-approvals.md)\n- [Use native AIP](../../../guides/use-native-aip.md)\n- [Approvals and policy](../../../concepts/approvals-and-policy.md)\n- [Actions and sessions](../../../concepts/actions-and-sessions.md)\n- [Errors and recovery](../../../reference/errors.md)\n",
    "text": "Run a governed Hermes operator lifecycle\n\nUse this guide to take one direct Hermes operator objective from its AIP\napproval to completion, a provider approval, a failure, or a controlled stop.\nIt keeps every identity and approval decision attached to the work it governs.\n\nThe operator can execute models, tools, messages, code, and external network\noperations. Never create a replacement Action after an uncertain start,\napproval, or cancellation. Query and reconcile the recorded identities first.\n\nThis guide covers direct objectives and their provider-approval resumes. For\nfirst-class AIP delegation, use the operator capability reference instead.\n\nUnderstand the identity ledger\n\nOne objective can acquire several related identifiers.\n\n| Identity | Owner | Lifetime and use |\n\n| Source Action ID | AIP runtime | Stable identity of the original objective and operator binding |\n| Source idempotency key | AIP runtime | Required capability-scoped replay key for that exact objective |\n| AIP approval ID | AIP runtime | Authorizes one high-risk source or resume Action |\n| Approval decision ID | AIP runtime | Makes one approval vote replayable without duplicating it |\n| Hermes runid | Hermes process | Addresses the volatile provider run after start is bound |\n| Hermes sessionid | Connector and Hermes | Deterministically aip-operator- |\n| Provider approval generation | Connector binding | Distinguishes successive Hermes approval prompts in one run |\n| Resume Action ID | AIP runtime | New identity for one provider approval response |\n| Resume idempotency key | AIP runtime | New required key for that exact resume Action |\n\nPersist the complete ledger in application state. Do not use runid, an\napproval ID, or a resume Action ID in place of the source Action ID.\n\nSeparate the two approval loops\n\nThe lifecycle has two independent approval layers.\n\n| Layer | AIP result | What the reviewer decides | How work continues |\n\n| Capability approval | pendingapproval with an AIP approvalid | Whether this exact high-risk Action may execute | A verified AIP decision resumes the same queued Action |\n| Hermes provider approval | requireshuman with output status waitingforapproval | Whether pending tool work inside the bound Hermes run may proceed | A new operator resume Action carries once, session, always, or deny |\n\nAn AIP approval does not answer a Hermes prompt. A Hermes choice does not\nauthorize a high-risk AIP Action. Every resume Action passes the first layer\nbefore it can change the second.\n\nBefore you start\n\nConfirm all of these conditions:\n• the endpoint-qualified operator capability is admitted and visible to the\n  request tenant;\n• the requester can invoke the capability and read its Action lifecycle;\n• a transport-authenticated reviewer who differs from the requester has\n  tenant-policy approval authority;\n• the AIP Action, approval, lifecycle, idempotency, and connector profile-state\n  backends have the durability claimed by the deployment;\n• every downstream capability the objective may use is separately admitted and\n  governed;\n• raw objective, provider event, tool, and result data is handled as\n  confidential and PII-bearing.\n\nThe capability timeout is 15 minutes. The generated AIP approval request also\nexpires after 15 minutes. These are configured contract values, not observed\navailability or completion guarantees.\n1. Allocate the source identity\n\nGenerate the source Action ID and idempotency key before submission. Retain\nthem with the endpoint, tenant, requester, and exact objective input.\n\nexport AIPCAPABILITYID='cap:hermesagent:primary:operator'\nexport AIPSOURCEACTIONID='act0123456789abcdef0123456789abcdef'\nexport AIPSOURCEKEY='operator-objective-case-example-2030-01'\n\nOne source Action ID identifies one exact endpoint and input. Reusing it with a\nchanged objective, context, constraint, endpoint, or delegation shape is an\nidempotency collision.\n\nThe connector uses the source ID to create the stable Hermes session ID and to\nkey the durable operator binding. The provider POST /v1/runs route is not\nidempotent; the binding's start claim is the second replay fence.\n2. Prepare a bounded objective\n\nCreate operator-objective.json with one outcome and explicit limits:\n\n{\n  \"objective\": \"Read the open support case and prepare a factual summary.\",\n  \"context\": {\n    \"caseid\": \"case-example-2030\"\n  },\n  \"candidatecapabilities\": [\n    \"cap:support:case.get\"\n  ],\n  \"constraints\": {\n    \"allowmutations\": false,\n    \"maximumrecords\": 1\n  }\n}\n\nThe input must select exactly one of objective or resume. A direct\nobjective can also carry arbitrary JSON context, up to 256 non-empty\ncapability hints, and an object of constraints.\n\ncandidatecapabilities is a model hint. It cannot admit a capability, grant\nauthority, bypass approval, widen tenant access, or override a schema. Keep\nuntrusted instructions inside data fields and make deployment policy the\nauthority boundary.\n3. Submit the source Action asynchronously\n\nSubmit the objective with its stable identity and required key:\n\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIPREQUESTERTOKENFILE\" \\\n  action call \"$AIPURL\" \\\n  \"$AIPCAPABILITYID\" \\\n  --action-id \"$AIPSOURCEACTIONID\" \\\n  --idempotency-key \"$AIPSOURCEKEY\" \\\n  --mode async \\\n  --input @operator-objective.json\n\nWithout a prior verified decision, the high-risk Action does not reach Hermes.\nThe expected response is pendingapproval, with essential evidence shaped\nlike this:\n\n{\n  \"actionid\": \"act0123456789abcdef0123456789abcdef\",\n  \"status\": \"pendingapproval\",\n  \"output\": {\n    \"requireshumanapproval\": true,\n    \"approvalid\": \"appr0123456789abcdef0123456789abcdef\",\n    \"capabilityid\": \"cap:hermesagent:primary:operator\"\n  },\n  \"error\": {\n    \"code\": \"policy.humanapprovalrequired\"\n  }\n}\n\nSave the exact approvalid. Do not retry the Action to make approval appear;\nthe original Action is already queued behind that record.\n4. Review the AIP approval record\n\nRead the generated record with the reviewer's authenticated identity:\n\nexport AIPSOURCEAPPROVALID='appr0123456789abcdef0123456789abcdef'\n\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIPAPPROVERTOKENFILE\" \\\n  approval get \"$AIPURL\" \"$AIPSOURCEAPPROVALID\" \\\n  --include-action-status \\\n  --include-receipts\n\nVerify all of these fields before deciding:\n1. actionid equals the retained source Action ID;\n2. capabilityid equals the endpoint-qualified operator capability;\n3. requester, subject, operator, tenant, and expiry match the intended work;\n4. the input-snapshot evidence hash covers the submitted objective;\n5. the immutable policyhash is present and unchanged;\n6. reason, risk, side effects, constraints, and evidence support the decision;\n7. the authenticated reviewer is admitted by the required authority policy.\n\nDo not copy raw input into logs merely to review it. Use the bounded approval\nview and an explicitly authorized evidence export when sensitive detail is\nrequired.\n5. Decide the AIP approval\n\nCreate source-approval-decision.json. Copy the exact approval and policy hash\nfrom the record, use a current timestamp, and allocate a stable decision ID:\n\n{\n  \"approvalid\": \"appr0123456789abcdef0123456789abcdef\",\n  \"decision\": \"approved\",\n  \"approver\": {\n    \"id\": \"human:operator-reviewer\",\n    \"kind\": \"human\"\n  },\n  \"decidedat\": \"2030-01-15T10:00:00Z\",\n  \"reason\": \"Read-only objective and constraints match the reviewed case.\",\n  \"decisionid\": \"decisionoperatorsource001\",\n  \"policyhash\": \"replacewithexactpolicyhash\"\n}\n\nThe approver must match the transport-authenticated principal. The runtime\nresolves authority itself and records the authority path. The request already\ncontains its input-snapshot and policy-decision evidence; a non-empty decision\nreason satisfies the remaining operator requirement.\n\nSubmit the decision:\n\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIPAPPROVERTOKENFILE\" \\\n  approval decide \"$AIPURL\" @source-approval-decision.json\n\nAn approved terminal decision leases and resumes the same queued source\nAction. Do not submit the objective again and do not attach the decision to a\nreplacement Action. The decision request can remain open while the resumed\noperator executes; observe the Action from a separate consumer.\n6. Follow the source Action\n\nFollow events and chunks under the source Action ID:\n\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIPREQUESTERTOKENFILE\" \\\n  action events \"$AIPURL\" \\\n  \"$AIPSOURCEACTIONID\" \\\n  --include-chunks \\\n  --follow\n\nThe connector publishes provider events under the source Action ID and keeps\none sequence across later resumes.\n\n| Provider event | AIP chunk kind | Application action |\n\n| message.delta | Data | Append visible text from the structured delta |\n| reasoning.available | Thought | Retain only under the deployment's reasoning policy |\n| tool.started, tool.completed | Tool | Correlate tool progress; do not infer the external effect |\n| approval.request | PendingApproval | Stop presenting progress as autonomous; review the prompt |\n| run.failed | Error | Preserve the typed failure and uncertain effects |\n| run.completed, run.cancelled | Done | Wait for the corresponding Action result |\n| Any other event | Progress | Preserve the event name without inventing semantics |\n\nInitial observation tries the provider SSE stream. A reconnect, source replay,\nor connector restart polls the bound runid instead of resuming that provider\nstream. AIP chunks already persisted remain readable; unobserved provider\nframes are not reconstructed.\n7. Classify the first operator result\n\nRead the source status with its result and recorded chunks:\n\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIPREQUESTERTOKENFILE\" \\\n  action status \"$AIPURL\" \\\n  \"$AIPSOURCEACTIONID\" \\\n  --include-result \\\n  --include-receipts \\\n  --include-chunks\n\nUse both the AIP status and operator output.\n\n| AIP result | Operator output status | Decision |\n\n| completed | completed | Accept only after required downstream effects are independently confirmed |\n| failed | failed | Inspect the typed error and retain partial effects |\n| cancelled | cancelled | Treat prior effects as potentially committed |\n| requireshuman | waitingforapproval | Review the provider prompt and create a new resume Action |\n| pendingapproval | No provider run yet | Complete the AIP capability approval; do not create a provider resume |\n| failed | outcomeunknown | Freeze replay and begin manual reconciliation |\n\nAccumulated text, a Done chunk, model prose, or a closed connection is not a\nterminal business decision by itself.\n8. Review the Hermes provider prompt\n\nA provider approval result retains the source binding and a redacted prompt:\n\n{\n  \"actionid\": \"act0123456789abcdef0123456789abcdef\",\n  \"status\": \"requireshuman\",\n  \"output\": {\n    \"endpointid\": \"primary\",\n    \"runid\": \"run0123456789abcdef0123456789abcdef\",\n    \"sessionid\": \"aip-operator-act0123456789abcdef0123456789abcdef\",\n    \"sourceactionid\": \"act0123456789abcdef0123456789abcdef\",\n    \"status\": \"waitingforapproval\",\n    \"lastevent\": \"approval.request\",\n    \"pendingapproval\": {\n      \"event\": \"approval.request\",\n      \"description\": \"Review the redacted provider operation\"\n    }\n  }\n}\n\nRetain the runid, but continue to address the operator binding by\nsourceactionid. Review the actual redacted command, tool, pattern, scope,\nand consequence supplied by the deployment.\n\nChoose the narrowest provider decision:\n\n| Choice | Provider meaning | Use |\n\n| once | Allow this pending operation without persisting an allow rule | Default for one reviewed operation |\n| session | Allow the matching pattern for this Hermes gateway session | Only after reviewing the session scope |\n| always | Persist the matching allow rule in Hermes configuration | Exceptional administrative decision |\n| deny | Reject this pending operation | Use when the operation is not authorized or needed |\n\nLeave resolveall false unless every currently queued provider prompt in the\nrun has been reviewed. AIP approval of the resume does not review those prompts\nfor you.\n9. Prepare a separately identified resume\n\nAllocate a new Action ID and key for one exact provider decision:\n\nexport AIPRESUMEACTIONID='actabcdef0123456789abcdef0123456789'\nexport AIPRESUMEKEY='operator-resume-case-example-2030-01'\n\nCreate operator-resume.json:\n\n{\n  \"resume\": {\n    \"sourceactionid\": \"act0123456789abcdef0123456789abcdef\",\n    \"choice\": \"once\",\n    \"resolveall\": false\n  }\n}\n\nUse deny instead of once to refuse the provider operation. Never reuse the\nsource Action ID for a resume. Never reuse a prior resume ID, key, approval ID,\nor decision ID for a later provider approval generation.\n\nThe resume capability endpoint must be the same endpoint that owns the source\nbinding. A different endpoint fails before it can answer the provider prompt.\n10. Approve and observe the resume Action\n\nSubmit the resume as another asynchronous operator Action:\n\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIPREQUESTERTOKENFILE\" \\\n  action call \"$AIPURL\" \\\n  \"$AIPCAPABILITYID\" \\\n  --action-id \"$AIPRESUMEACTIONID\" \\\n  --idempotency-key \"$AIPRESUMEKEY\" \\\n  --mode async \\\n  --input @operator-resume.json\n\nThis Action first returns its own AIP pendingapproval. Repeat steps 4 and 5\nwith the new approval ID, exact new policy hash, and a new decision ID. Review\nthe resume input itself: the decision authorizes sending that exact provider\nchoice to the exact source run.\n\nAfter AIP approval, the connector records a fenced provider-command entry\nbefore calling Hermes. A definitive provider 4xx rejects the command. A\ntransport failure, provider 5xx, or lost command owner makes the provider\napproval outcome unknown and blocks replay.\n\nContinue reading operator chunks from the source Action ID. Read settlement\nfrom the current resume Action ID:\n\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIPREQUESTERTOKENFILE\" \\\n  action status \"$AIPURL\" \\\n  \"$AIPRESUMEACTIONID\" \\\n  --include-result \\\n  --include-receipts \\\n  --wait-ms 60000\n\nIf Hermes raises another provider prompt, allocate another resume Action and\nrepeat this step. Do not mutate or replay the preceding resume.\n11. Settle from the latest invocation result\n\nAfter a resume, the connector deliberately separates stream and result\nidentity.\n\n| Evidence | Identity | Meaning |\n\n| Operator chunks | Original source Action ID | Ordered provider progress across the complete bound run |\n| Current ActionResult actionid | Latest resume Action ID | Result of this separately governed invocation |\n| Output sourceactionid | Original source Action ID | Binding whose provider state produced the result |\n| Output runid | Hermes provider run | Volatile provider correlation only |\n\nThe earlier source ActionResult remains requireshuman; the resume does not\nrewrite it to completed. Do not wait for that old result to change. Accept the\nlatest resume result only when its output.sourceactionid matches the source\nledger and its output status is terminal.\n\nA representative terminal correlation is:\n\n{\n  \"actionid\": \"actabcdef0123456789abcdef0123456789\",\n  \"status\": \"completed\",\n  \"output\": {\n    \"sourceactionid\": \"act0123456789abcdef0123456789abcdef\",\n    \"runid\": \"run0123456789abcdef0123456789abcdef\",\n    \"status\": \"completed\",\n    \"lastevent\": \"run.completed\"\n  }\n}\n\nProvider completion proves the governed Hermes run ended. Confirm important\ndownstream AIP Actions and external effects from their own authoritative\nlifecycle records rather than from operator prose.\n12. Recover a disconnect or process restart\n\nOn application delivery loss:\n1. keep the source and current invocation IDs unchanged;\n2. query status for the current invocation before considering any submission;\n3. read bounded events and chunks under the source ID from the last native\n   cursor;\n4. read the current AIP approval record if its result is pendingapproval;\n5. read the current provider prompt if its result is requireshuman;\n6. accept only a terminal result whose source correlation matches the ledger.\n\nClosing an action events --follow connection does not cancel the AIP Action\nor Hermes request. Resume the native delivery route; do not reconnect directly\nto the provider SSE URL.\n\nThe operator binding can survive only when the configured profile-state backend\nis process-durable. Hermes runid, event queue, active task, and provider\napproval queue are process memory. A provider 404 after restart or retention\nloss is an evidence gap, not proof that the run never executed.\n\nDo not create a replacement objective when the provider handle is missing. The\nconnector intentionally refuses to repeat an external start whose outcome may\nalready exist.\n13. Cancel according to the current phase\n\nNative cancellation has different effects depending on whether an operator\nAction is active.\n\n| Phase | Action to cancel or decide | Provider effect |\n\n| Waiting for initial AIP approval | Cancel the source Action | No provider run has started |\n| Source Action actively executing | Cancel the source Action | Active connector callback records intent and attempts provider stop |\n| Provider returned requireshuman | Submit a governed resume with deny | Rejects the pending provider operation and returns control to Hermes |\n| Resume Action waiting for AIP approval | Cancel that resume Action | Prevents that provider decision; the source run remains waiting |\n| Resume Action actively executing | Cancel the resume Action | Connector maps its input to the source binding and attempts provider stop |\n| No operator Action is active, but full stop is required | Invoke separately approved runstop with retained runid | Requests provider interruption; binding needs operational reconciliation |\n\nCancel an active Action explicitly:\n\ncargo run --locked -p aipctl -- \\\n  --native-bearer-token-file \"$AIPREQUESTERTOKENFILE\" \\\n  action cancel \"$AIPURL\" \\\n  \"$AIPRESUMEACTIONID\" \\\n  --reason 'The requester withdrew the governed objective'\n\nThe runtime calls the connector only for an active Action. After an invocation\nhas returned requireshuman, cancelling that inactive native record does not\ncall Hermes. The public operator input has no standalone stop branch.\n\nFor an active invocation, the connector records cancellation intent, maps a\nresume back to the source binding, sends provider stop after a runid is\nbound, and polls within the configured grace. The provider binding can settle\ncompleted, failed, cancelled, or outcome unknown.\n\nThe native cancel response is an AIP cancellation acknowledgement. It does not\nexpose that provider classification and is not proof that Hermes stopped.\nNeither path rolls back model, tool, message, code, or network effects.\n14. Freeze unsafe unknown outcomes\n\n| Error or observation | What may have happened | Required decision |\n\n| operatoroutcomeunknown | Hermes may have accepted a start before runid was bound | Freeze the source identity; reconcile provider and profile state manually |\n| approvaloutcomeunknown | Hermes may have applied a resume command | Freeze that resume and source; never resend the choice blindly |\n| cancellationoutcomeunknown | Stop did not reach a confirmed provider terminal state | Treat provider state and effects as uncertain |\n| Provider 404 after a bound run | Provider process state may be lost or expired | Preserve the gap; do not infer that no run existed |\n| operatorstartrejected on provider 4xx | Hermes definitively rejected the start | Correct the cause before creating a separately reviewed Action |\n| Initial AIP approval denied or expired | No provider run started for that source Action | Keep the terminal record; do not reuse its identifiers |\n| Resume AIP approval denied or expired | No provider choice was sent by that resume; the source run can remain waiting | Keep both records; create a new reviewed resume only for a still-current prompt |\n\nUnknown is a terminal safety classification, not a temporary retry hint. Keep\nthe input fingerprint, endpoint, source and resume IDs, approval records,\nbinding revision, provider diagnostics, and timestamps for reconciliation.\n15. Verify the integration\n\nBefore accepting the client, use controlled evidence to verify that it:\n1. allocates the source Action ID and required key before submission;\n2. persists the exact objective and endpoint with that identity;\n3. distinguishes AIP pendingapproval from provider requireshuman;\n4. validates approval ID, policy hash, evidence, authority, and expiry;\n5. lets an approved decision resume the same source Action;\n6. follows operator chunks under the source Action ID;\n7. treats candidate capabilities only as hints;\n8. creates a new Action, key, approval, and decision for every provider resume;\n9. leaves resolveall false unless all queued prompts were reviewed;\n10. reads terminal settlement from the latest resume Action when one exists;\n11. preserves sourceactionid, runid, and current invocation ID separately;\n12. recovers delivery without submitting replacement work;\n13. cancels only with phase-aware expectations and verifies provider effects;\n14. freezes all three unknown-outcome classes without automatic replay;\n15. redacts objectives, provider prompts, tool data, results, and diagnostics.\n\nThis checklist is source-aligned integration evidence. It is not live provider,\nlatency, storage-durability, cancellation, or production qualification.\n\nRelated documentation\n• Operator and delegation capability (../capabilities/operator-and-delegation.md)\n• Structured runs and approvals (../capabilities/durable-runs-and-approvals.md)\n• Use native AIP (../../../guides/use-native-aip.md)\n• Approvals and policy (../../../concepts/approvals-and-policy.md)\n• Actions and sessions (../../../concepts/actions-and-sessions.md)\n• Errors and recovery (../../../reference/errors.md)\n"
  },
  "integrity": {
    "algorithm": "sha256",
    "sourceDigest": "69e025eaa1d2663ef5ce5f9c8715ffc5ff9e62ecc49a4586665551d27174f324"
  }
}
