Skip to content
AIPDocs
AIP 1.055 pagesConnector
Release status
DocumentationAIP 1.0ConnectorConnectors

Hermes Agent Connector

Purpose

aip-connector-hermes-agent maps the stable Hermes API-server surface to AIP capabilities and can, when explicitly enabled, register each Hermes instance as a governed AIP router/operator principal. Product-specific Hermes DTOs remain inside the connector. AIP core types and lifecycle semantics are not coupled to Hermes.

The implementation was checked against the official Hermes Agent checkout and revision recorded in upstream-baselines.md. The authoritative upstream contract is gateway/platforms/api_server.py.

Published Surface

For every configured endpoint <endpoint>, the connector publishes:

  • health and API discovery;
  • model, skill, and toolset discovery;
  • Chat Completions and Responses API operations;
  • structured run start, status, events, approval, and stop operations;
  • persisted session CRUD, messages, fork, chat, and streaming chat operations;
  • stored response lookup and deletion;
  • cap:hermes_agent:<endpoint>:operator for governed long-running operator work.

The operator also owns the stable AIP principal agent:hermes_operator:<endpoint>. A connector-owned delegation router is registered with aip-gateway only when delegation is explicitly enabled. Static native HTTP and NATS routes retain precedence over connector routers.

The connector implements InboundConnector, OutboundConnector, ChannelConnector, and EscalationConnector. Channel ingress uses the same strict AIP envelope mapper as ordinary inbound events. Channel egress sends a normalized ActionResult to the deployment-selected persisted Hermes session; multi-endpoint deployments must supply both endpoint_id and session_id in trusted connector context.

An endpoint may be bound to one verified AIP tenant through HermesAgentEndpoint::with_tenant_id. Frozen invocations and connector-owned delegations then reject a missing, expired, or different tenant before any provider request is sent.

Operator Lifecycle

The connector uses Hermes structured runs instead of the stateless chat route:

AIP action/delegation
  -> durable start claim
  -> POST /v1/runs
  -> durable action-to-run binding
  -> GET /v1/runs/{run_id}/events
  -> status polling after disconnect or process restart
  -> completed | failed | cancelled | waiting_for_approval | outcome_unknown

State is stored in the runtime-owned ProfileStateStore namespace aip.connector.hermes_agent.operator_runs.v1. Postgres deployments therefore share the same atomic CAS backend for AIP delegation outbox state and Hermes run correlation.

Start Idempotency

Hermes POST /v1/runs does not provide a durable provider idempotency key. The connector consequently implements the strongest safe boundary available:

  1. persist the AIP action and canonical request fingerprint;
  2. acquire an exclusive CAS start claim before the HTTP request;
  3. persist the returned run_id before consuming events;
  4. replay terminal results and poll already-bound runs without starting a new run;
  5. mark the outcome unknown when the process or transport fails between provider acceptance and durable run-id binding.

An unknown start outcome is never retried automatically. This may require operator reconciliation, but it prevents a duplicate agent run and duplicate side effects.

Streaming and Recovery

Hermes structured-run SSE has no replay cursor and a disconnected subscriber may lose intermediate events. AIP therefore publishes events incrementally while connected, persists the last observed event and AIP stream sequence, and uses GET /v1/runs/{run_id} as the authoritative recovery path. Terminal run status is retained by the referenced Hermes revision for one hour.

Raw Hermes SSE operations use explicit terminal classifiers. run.failed, response.failed, response.incomplete, and terminal error events produce a failed AIP action; run.cancelled produces a cancelled action. Closing a stream without an explicit terminal event is an incomplete failure, not a successful result.

Provider Approval

A Hermes approval.request event returns requires_human and persists a redacted pending approval. Resumption uses a new AIP operator action:

{
  "resume": {
    "source_action_id": "act_...",
    "choice": "once",
    "resolve_all": false
  }
}

Each response is bound to the resume action id, canonical fingerprint, and a monotonic approval generation. A durable command ledger prevents a replayed response from approving a later Hermes prompt. A transport failure after sending an approval is outcome-unknown and is not replayed.

The operator capability itself requires normal AIP approval before execution. Connector-owned delegation additionally requires a terminal approved record in the runtime ApprovalStore by default. The durable decision must match the child action_id, capability id, decision payload, and expiration time. Payload claims alone are never accepted as authority.

Approval resume owns a fenced queue lease for the entire resumed action. A heartbeat renews both the action lease and any transferred idempotency reservation while Hermes is running. Losing either fence cancels the active execution and prevents terminal settlement by the stale worker. This is required because a provider-backed Hermes run can exceed the initial lease TTL.

The standalone daemon remains fail-closed for governed action execution until a deployment installs a trusted identity directory with --trusted-identity-file or AIPD_TRUSTED_IDENTITY_FILE. The JSON array maps transport-authenticated principal ids to non-zero revisions and optional verified tenant, opaque credential, sanitized identity, and expiration data. The daemon rejects duplicate, revoked, expired, and zero-revision entries.

Approval decisions additionally require an approval authority directory with --approval-authority-file or AIPD_APPROVAL_AUTHORITY_FILE. The JSON file contains serialized AuthorityMembership records, must be a regular file smaller than 1 MiB, and must not be group- or world-writable. Duplicate, expired, revoked, and zero-revision memberships are rejected at startup. This directory contains authorization policy, not bearer credentials; production deployments should still mount it read-only from a policy-controlled source.

Cancellation

Cancellation intent is persisted before POST /v1/runs/{run_id}/stop. The connector then polls run status for the configured grace interval. Only a provider-reported cancelled state is recorded as cancelled. A completion or failure racing with cancellation remains the authoritative terminal result. If Hermes does not expose a terminal state, the binding becomes outcome-unknown.

Router Policy

Delegation is fail-closed. HermesOperatorPolicy requires all of the following:

  • delegation_enabled = true;
  • an explicit delegated capability-prefix allowlist;
  • an explicit delegated scope-prefix allowlist;
  • a runtime-owned approval store when delegated approval is required;
  • bounded delegation depth, input size, events, execution time, claim TTL, and cancellation reconciliation time.

The literal prefix * is an explicit unrestricted opt-in for one dimension. It should not be used in production when narrower prefixes are available.

Hermes model output is not authoritative for a delegated business result. The delegation payload contains an exact aip_call_arguments object, including the protocol-assigned child action id, immutable action contract, approval, transaction, and validated delegation chain. Hermes is instructed to invoke the stable aip_call MCP tool exactly once with that object.

After the Hermes run completes, RuntimeHermesDelegatedResultResolver reads the native durable AIP action record and result. It verifies the exact action id, capability, input, execution mode, idempotency key, timeout, conversation, memory context, delegation chain, federation, callback, observability, compliance, approval, and transaction fields. It also requires the transport-authenticated Hermes principal, action:write authority, trusted runtime identity projection, and tenant partition to match the delegation. Only that verified native result becomes the child ActionResult. Final model prose is ignored. A missing action, altered contract, wrong principal, wrong tenant, or inconsistent lifecycle state fails closed with a typed non-secret protocol error.

The runtime rejects self-hops, discontinuous delegation chains, repeated principals, and cycles before dispatch. A permanent connector policy denial is settled once and is not retried by the durable delegation outbox.

aipd exposes the policy through CLI options and equivalent environment variables. A minimal restricted configuration is:

AIPD_HERMES_ENDPOINTS='hermes-1=http://hermes-1:8642'
AIPD_HERMES_API_KEY='replace-with-secret-manager-reference'
AIPD_HERMES_OPERATOR_DELEGATION_ENABLED=true
AIPD_HERMES_OPERATOR_CAPABILITY_PREFIXES='cap:support_sandbox:'
AIPD_HERMES_OPERATOR_SCOPE_PREFIXES='support.'
AIPD_HERMES_OPERATOR_MODEL='deployment/model-route'

Trusted instructions should be mounted as a file and selected with --hermes-operator-instructions-file or AIPD_HERMES_OPERATOR_INSTRUCTIONS_FILE. Do not concatenate tenant or user input into this file.

AIP MCP Inside Hermes

The connector can make Hermes an AIP operator, but Hermes must also be given an AIP tool path when it is expected to call other capabilities. Configure the same aipd deployment as a Streamable HTTP MCP server in the Hermes profile:

mcp_servers:
  aip:
    url: "http://aipd:8080/mcp"
    headers:
      Authorization: "Bearer ${AIP_MCP_TOKEN}"
    timeout: 300
    connect_timeout: 15
    supports_parallel_tool_calls: false
    tools:
      include:
        - aip_capabilities
        - aip_call
        - aip_action_status
        - aip_action_result
        - aip_action_events
        - aip_action_cancel

The internal Hermes allowlist deliberately excludes aip_delegate. The external AIP orchestrator owns first-class delegation and injects the complete parent/child graph. Giving a model recursive access to aip_delegate can create an unbounded delegation loop because the delegated prompt is itself an agent task. Add that tool only behind a separate broker that propagates and validates the original delegation chain, and grant delegation:create only to that broker identity.

Each Hermes instance must use its own OAuth access token and AIP principal, for example agent:hermes_operator:hermes-1. A normal internal operator token needs only the MCP connection scope and the scopes required by its selected read/query tools; it must not inherit the external orchestrator’s delegation, approval, or broad audit scopes. Supported protected-resource scopes and the small set of scopes required to establish an MCP transport are separate configuration fields.

The operator’s aip_call must preserve the action_id and every supplied execution-contract field. A generated replacement action id is a contract violation: it cannot satisfy first-class delegation and is rejected by the authoritative result resolver.

Hermes must not receive database credentials or direct access to systems of record when the workflow is intended to prove the AIP path. Facts and side effects must be obtained through AIP capabilities.

MCP configuration is a deployment responsibility because it contains endpoint, tenant, and credential policy. The Rust connector never writes Hermes profile files or transports bearer tokens through action payloads.

The lightweight Hermes image must install the official mcp extra from the pinned upstream checkout. Installing the base package alone does not include the Streamable HTTP MCP client modules used by hermes mcp test.

Trusted Execution Projection

The frozen connector path consumes the non-serializable AIP ExecutionContext. It sends only bounded, verified metadata to Hermes:

  • X-AIP-Principal-Id from the transport-authenticated actor;
  • X-AIP-Tenant-Id from verified tenant membership;
  • X-AIP-Authentication-Issuer from the trusted authenticator;
  • X-AIP-Trace-Id and X-AIP-Correlation-Id from the trusted trace context;
  • X-AIP-Deadline-Unix-Ms from the runtime deadline;
  • X-AIP-Delegation-Chain from the validated native action chain; and
  • Idempotency-Key from the native action contract.

Payload _aip fields remain a legacy correlation input for the old untyped connector API. They never override the authenticated actor, verified tenant, trusted trace, deadline, or validated delegation chain in the frozen path. Opaque credential handles and raw provider credentials are never serialized into these headers.

Network and Credential Safety

The default HTTP client:

  • accepts only administrator-configured HTTP or HTTPS endpoint URLs;
  • does not follow redirects, preventing bearer propagation to a redirected origin;
  • uses bounded connection and request timeouts;
  • never serializes endpoint API keys or prints them through Debug;
  • maps provider and transport failures to typed AIP connector errors;
  • bounds SSE frames, event counts, input bytes, and total operator duration.

Production deployments should use TLS, private service discovery, secret manager injection, network egress policy, and independent Hermes service accounts per tenant or trust domain.

Qualification Requirements

A release claiming Hermes operator support must retain evidence for:

  1. every published route against the pinned upstream revision;
  2. concurrent same-action execution starting exactly one Hermes run;
  3. process failure before run-id binding producing outcome-unknown without replay;
  4. SSE delta, tool, approval, failure, cancellation, and terminal mapping;
  5. approval replay and generation isolation;
  6. cancellation/completion races and unconfirmed cancellation;
  7. restart recovery with the production storage backend;
  8. AIP gateway delegation routing to two isolated Hermes instances;
  9. Hermes tool use through authenticated AIP MCP, including a real downstream capability call, exact child-action execution, and retained AIP receipts;
  10. negative authorization, tenant isolation, allowlist, timeout, malformed response, and provider-outage cases.

The deterministic RFC 0004 release gate is executable with:

cargo test -p aip-connector-hermes-agent --test frozen_conformance

It runs atomic manifest admission and all twelve shared behavior families. Identity, schema, idempotency, retry/DLQ, cancellation, streaming, uncertain-outcome, approval/quorum, audit/receipts/redaction, and restart recovery execute against the public connector and runtime boundaries. Transactions and webhooks are reported as not applicable because the Hermes manifest publishes neither contract.

The isolated-live two-Hermes driver is executable with:

AIPD_MCP_ACCESS_TOKEN='external-orchestrator-token' \
AIPD_NATIVE_BEARER_TOKEN='independent-approver-token' \
cargo run -p aip-connector-hermes-agent --bin aipd-hermes-operator-smoke -- \
  --endpoint-id hermes-1 \
  --endpoint-id hermes-2

The retained qualification record is hermes-agent-isolated-live.md. Unit and deterministic process-boundary tests remain necessary but do not replace this isolated-live provider-backed evidence.