Invocation Model

How all agent work flows through a single unified entry point with consistent policy enforcement — agent existence/state checks, provider-drain gating, rate limiting, idempotency, and observability.

Agents do not declare accepted invocation sources

There is no TriggerConfig/TriggerRegistry anywhere in hoziron-core, no TriggerMismatch variant in ErrorCategory, and no triggers field on the agent manifest. Source-acceptance gating happens upstream of invoke_agent, per source, not inside it:

SourceHow it's gated
ApiNo gating — every agent accepts direct API calls
ChannelAgentBinding/router config plus per-channel RBAC, resolved by the channel bridge before invoke_agent is ever called
CronPlatform-managed — a cron job is bound to one agent at creation time; there's no separate "does this agent accept cron" check
ConditionSame as Cron — platform-managed, bound at creation (ADR-065)
WorkflowPinned by the workflow step's own agent reference in the workflow definition

See "Mediated Ingress (ADR-061)" below for why this is a deliberate structural choice.

Unified Entry Point

Every agent invocation — whether from the API, a channel message, a cron schedule, a matched condition, or a workflow step — flows through the same invoke_agent pipeline:

The provider-drain gate (Issue #407) only applies to standalone sources (Api/Channel/Cron/Condition) — a Workflow-sourced invocation is already gated by the workflow's own admission state, so it's exempted here to avoid double-gating.

Invocation Sources

Each invocation carries metadata about its origin (InvocationSource, crates/platform/hoziron-core/src/invocation/context.rs):

SourceDescription
ApiDirect HTTP API call
ChannelMessage from a channel integration — carries channel_type, channel_id, sender_id, sender_name
CronFired by a scheduled job — carries schedule_id, expression, scheduled_at
ConditionFired by a matched condition (ADR-065) — carries condition_id, a display-only rendering of the matched expression (condition kind + key + operator, never a raw memory value — this is a load-bearing invariant so a PII-bearing memory fact can never leak into audit/model context through this field), and matched_at
WorkflowStep in a multi-agent pipeline — carries workflow_id, step_index, upstream_agent_id

There is no Event source — system/lifecycle events are not a live invocation origin.

InvocationContext

The full payload delivered to the invocation layer:

{
  "source": {
    "Workflow": {
      "workflow_id": "a1b2c3d4-...",
      "step_index": 2,
      "upstream_agent_id": "550e8400-..."
    }
  },
  "message": "Process this claim...",
  "idempotency_key": "req-abc123",
  "correlation_id": "7c9e6679-..."
}
FieldPurpose
sourceOrigin metadata for routing, telemetry, and audit
messageThe payload to deliver to the agent
idempotency_keyOptional deduplication key (requests with same key return cached result)
correlation_idUUID for distributed tracing across steps/services
workflow_typeOptional entitlement/budget category (e.g. "fnol"); derived from InvocationSource::Workflow or the agent's configured mapping when unset

Rate Limiting

Per-agent sliding window rate limiter:

  • Window: 60 seconds (sliding)
  • Default limit: 60 invocations per minute per agent
  • Implementation: in-memory HashMap<AgentId, Vec<Instant>> — timestamps older than 60s are evicted on each check
  • Disabled: set limit to 0 for a specific agent

When exceeded:

{
  "error": {
    "category": "RateLimited",
    "message": "Agent has exceeded the rate limit of 60 invocations per minute",
    "details": {"agent_id": "...", "limit": "60"}
  }
}

Idempotency

Optional deduplication for exactly-once semantics:

  • Requests with the same idempotency_key return the cached result without re-executing
  • Cache is in-memory with TTL (bounded size)
  • Useful for webhook retries and workflow step replays

Mediated Ingress (ADR-061)

Every source in the table above funnels through invoke_agent and therefore through hoziron-core — this is a deliberate structural invariant, not an incidental convenience. An agent turn may only be originated by core, through this mediated path, with a request type the kernel cannot construct on its own. Concretely:

  • The kernel's send_message* family is not a callable agent-turn origin from outside core — there is no parallel "fast path" that bypasses the checks above or the inbound PII seam.
  • Kernel-internal triggers that must originate a turn (cron, condition, workflow resumption) do so through a core-authored dispatch closure (the drive_run pattern) — the kernel owns timing/matching, core owns the mediated dispatch implementation the kernel's generic closure parameter calls into. This preserves the trust gradient: the kernel calls a function pointer, never core directly.
  • There is no kernel-internal event/publish mechanism that can originate a turn outside this seam — every path into an agent's context is mediated.
  • Interior traffic (agent→agent messages, memory writes with already-tokenized content) is not re-mediated — the trust boundary is the agent domain as a whole, not each individual agent-to-agent hop.

Telemetry

Every invocation records structured metrics:

{
  "agent_id": "550e8400-...",
  "source": "Workflow",
  "duration_ms": 2100,
  "tokens_used": 342,
  "success": true,
  "correlation_id": "7c9e6679-..."
}

Available via the API as per-agent invocation metrics:

  • Total invocations
  • Error count / error rate
  • Average duration
  • Per-source breakdown (how many from API vs Channel vs Cron vs Condition vs Workflow)

InvocationResult

The structured response returned from every invocation:

{
  "content": "There are 23 open claims in the queue.",
  "tokens_used": 342,
  "duration_ms": 2100,
  "correlation_id": "7c9e6679-...",
  "source": {"Api": {}}
}

Related:

  • agent-execution.md — what happens once a turn is admitted
  • ../architecture/object-model.md — the AgentState/Runnable lifecycle contract
  • ../reference/api/cron.md — condition jobs (ADR-065), the one piece of proactive scheduling that's live today
  • docs/decisions/056-unified-activation-gate.md, 061-agent-turn-ingress-authority.md, 065-core-mediated-proactive-scheduling.md