AIP-9: OPERATOR.md — agentoperators/v1 (operator runtime protocol)
A single canonical operator shell — pluggable profile, skills, tools, memory, governance — that any agent runtime can implement and any conforming workflow can dispatch to.
| Field | Value |
|---|---|
| AIP | 9 |
| Title | OPERATOR.md — agentoperators/v1 (operator runtime protocol) |
| Status | Draft |
| Type | Core |
| Domain | operators.sh |
| Requires | AIP-3, AIP-6, AIP-7, AIP-42 |
| Extends | AIP-42 AGENT.md (operator = agent + organizational context, dynamically resolved per request) |
| Reference Impl | TBD |
Abstract
agentoperators/v1 specifies the runtime contract for an operator —
a dynamic agent: a single shared shell whose profile, skills,
tools, memory, and governance bindings are resolved per-request from
requestContext (typically operatorId + conversationId). One
runtime class, N operator personas dispatchable per turn.
OPERATOR extends AIP-42 AGENT.md. An AGENT.md is
the static, file-form base primitive — 1 file → 1 agent instance.
An OPERATOR is the dynamic-agent extension — 1 shell → N operator personas resolved per request. The two compose:
- Static agents (utility researcher, code-reviewer, support-bot)
ship as standalone
AGENT.mdfiles, each instantiated once per workspace at boot. - Dynamic operators (creative-director, account-strategist,
pricing-analyst — anyone bound to a company/role/persona) ship as
OPERATOR.mdfiles that extend a base AGENT.md and add organizational context, then run through a single shared shell with per-request persona resolution.
The contract this AIP defines is what the shared shell MUST implement to be considered AIP-9-conforming. The file form OPERATORs author against is described in AIP-42 § OPERATOR.md extends AGENT.md.
Motivation
Agent platforms today multiply agent classes: a "researcher agent", a "writer agent", a "coordinator agent", each implemented separately with diverging conventions. The result: every new role costs new code, and operators built for platform X don't run on platform Y.
The opinionated wager of agentoperators/v1: you don't need multiple agent classes — you need one well-specified shell with pluggable parts. A "researcher" is an operator with research skills + research tools + a researcher persona. A "coordinator" is the same shell, with different attachments. The shape of the agent is fixed; the contents move.
This unification lets:
- Workflows dispatch tasks to any operator without per-class adapters
- Tools target the operator-shell contract instead of N agent vendors
- Governance (AIP-7) attach uniformly — every operator goes through the same approval/audit gates
- File definitions (AIP-6
OPERATOR.md) be portable across runtimes that implement this AIP
The pattern is field-tested: the reference implementation in Guilde runs production agencies built entirely from this single operator class, with persona, skill, and tool attachments doing the role differentiation.
Specification
Full normative text is being authored from the Guilde reference implementation. AIP-9 will absorb the formal contract as part of moving Draft → Review.
Relation to AGENT.md (AIP-42) — fields OPERATOR adds
OPERATOR.md inherits every AGENT.md field. The fields below are what OPERATOR adds on top, formalizing the organizational binding:
| Field | Inherited / added | Description |
|---|---|---|
All AGENT fields (model, tools, actions, skills, workflows, routines, memory, governance, policy, traits, autonomy, boundaries, on) | inherited | Same semantics as AIP-42. Operator MAY override any. |
role | added | Required. Slug identifying the operator's role in the company (e.g. creative-director). Used for triage, routing, mention resolution. |
reports_to | added | Optional. Slug of the operator this one reports to (org chart). |
company | added | Optional. Ref to AIP-6 COMPANY.md — the operator's home company. |
participation | added | Required. See Conversation participation. Static agents don't have this — they don't join shared threads. |
capabilities | added | Optional. Per-action capability flags (autonomous / supervised / gated). |
The runtime instantiates ONE shared shell (Mastra Agent instance in
the reference impl) and resolves all OPERATOR-specific fields
(role, participation, capabilities, persona overlays) per-request
from requestContext.operatorId. This is the dynamic-agent
property — N OPERATOR.md definitions sharing one runtime shell, vs N
AGENT.md files each getting their own instance.
Operator shape
An operator is the tuple:
interface Operator {
/** AIP-6 OPERATOR.md slug — stable identity */
id: string
/** AIP-6 OPERATOR.md content — role, persona, ranking, profile prose */
profile: OperatorProfile
/** AIP-3 SKILL.md ids the operator has loaded */
skills: SkillRef[]
/** Tool bindings the operator can invoke
* (MCP servers, framework tools, AIP-3 skill-attached tools) */
tools: ToolBinding[]
/** Memory / operator-context slot — what the operator carries
* across turns and what it shares with teammates */
memory: MemoryBinding
/** AIP-7 governance binding — which actions require approval,
* which audit log to write to, which policies gate autonomy */
governance: GovernanceBinding
/** Capability flags — autonomous / supervised / gated, plus
* per-action overrides */
capabilities: CapabilityFlags
/** Conversation participation — whether/when this operator
* reads + responds in shared threads */
participation: ParticipationConfig
/** Optional runtime binding — picks the runtime this operator runs
* on. Default `kind: "in-process"` runs in the host's Mastra-style
* in-process loop. `kind: "agent-cli"` dispatches turns to a
* spawned AIP-45 agent CLI subprocess (Hermes, Claude Code, ...). */
runtime?: RuntimeBinding
}Runtime binding
The optional runtime block selects the runtime that owns this
operator's turns. Two kinds today:
# In-process — the host's own agent loop (default).
runtime:
kind: in-process
# Agent CLI — dispatch turns to an AIP-45 manifest's spawned binary.
runtime:
kind: agent-cli
ref: claude-code # AIP-45 AGENT-CLI.md ref
config: # per-runtime configuration (optional)
mode: plan # one manifest-declared mode (mutually exclusive)
options: # manifest-declared option ids → values
model: claude-opus-4-7
max_turns: 50
continuation: pinned-session # one of the manifest's `continuation.supported` ids
session: # session policy override (optional)
mode: persistent
idle_timeout_ms: 1800000config is the contract between the operator and its bound AIP-45
manifest. Hosts MUST validate every entry before spawn:
config.modeMUST appear in the manifest'smodes[].idset.- Each
config.options.<id>MUST match a manifestoptions[]entry byidAND satisfy that entry's declaredtype/enum/ bounds. config.continuationMUST be a member of the manifest'scontinuation.supportedset.
Unknown ids are a hard load-time error; the host MUST refuse to bind the operator. Omitted fields fall back to manifest defaults.
Lifecycle
Every operator goes through these states, observable to the runtime and to peer operators:
idle → invoked → running → ( suspended | completed | interrupted )
↓
resumed → running- invoked — workflow or human dispatched the operator
- running — actively executing (calling tools, generating)
- suspended — paused for governance approval or human input
- resumed — picked back up after suspension
- completed — turn finished cleanly
- interrupted — stopped before completion (user cancelled, error, policy block)
Every state transition writes an audit-event per AIP-7.
Conversation participation
An operator that joins a conversation MUST implement:
- Mention handling — receive
@<slug>mentions and respond - Pass — choose to not respond when the message is not relevant to the operator's role / skills
- Reactions — emit lightweight signals (👍, ✅, 🚧) without generating a full turn
- Visibility — public, private-to-admin, or scoped per the conversation's visibility rules
Capability negotiation
Operators declare what they CAN do. Runtimes declare what they OFFER.
Tools / actions are available iff both sides agree. Gaps surface as
unmet-capability errors during workflow planning, before the
operator runs.
Rationale
To be authored. Defend:
- Why a single shell instead of agent-class subtyping (composition > inheritance, easier portability, cleaner governance attach points)
- Why
participationis first-class (operators in shared threads are the dominant pattern; treating it as an attachment makes multi-operator collaboration tractable) - Why governance is a binding, not a wrapper (gives the operator awareness of what it can and cannot do, instead of the runtime silently rejecting actions)
- Why memory is per-operator, not per-conversation (lets operators develop "personality through history" the way human roles do)
Reference Implementation
A public reference implementation is TBD — pending extraction into
agentproto/ts. The shape any conforming runtime must expose:
- An operator orchestrator that turns an operator configuration into a runnable agent and executes turns.
- A routing module — mention resolution, multi-operator triage, pass logic.
- A generation module — turn-generation strategies (sequential vs think-then-speak, normal vs deep-work mode).
- A typed contract for operator configuration (the shape AIP-9 codifies).
The orchestrator boots from an AIP-6 OPERATOR.md
package + an AIP-3 skill set + tool registry, and
produces a fully-configured operator ready to dispatch to. A working
implementation runs in production inside the agentik-studio monorepo
(private); the open reference will land alongside @agentproto/agencies
and @agentproto/governance once extracted.
Backwards Compatibility
Not applicable — this is the first runtime spec for operators. Pre-existing per-vendor operator classes (LangChain agents, custom runtimes) can adopt agentoperators/v1 by implementing an adapter that maps to the shape above.
Security Considerations
Operators are autonomous actors with tool access. The risk surface:
- Tool-call injection — a malicious user message persuades the operator to invoke a tool the user shouldn't have access to. Mitigation: governance binding (AIP-7) policy gates every privileged tool; the operator MUST consult its governance binding before invoking a gated action.
- Skill-as-prompt-injection — an untrusted skill loaded into a trusted operator could try to subvert the operator's role. Mitigation: AIP-3 skill provenance metadata + runtime-side skill allow-listing.
- Memory poisoning — an attacker controls a conversation and seeds the operator's memory with false facts. Mitigation: memory writes go through a validation step; AIP-7 audit log records every memory update so poisoning is forensically recoverable.
- Participation flooding — an operator with
participation: always-respondin a shared thread could spam. Mitigation: rate limits and thepassprimitive (operators choosing silence is first-class behavior, not failure).
Resources
Supporting artifacts for AIP-9. Links open the file on GitHub — markdown and JSON render natively in GitHub's viewer. Browse the full resource tree →
AIP-8: AGENCY.md — agentagencies/v1 (autonomous agency engine)
A filesystem-first operations format that extends agentcompanies (AIP-6) and agentgovernance (AIP-7) with the doctypes needed to run an autonomous agency — services, procedures, engagements, agreements, deliverables, invoices.
AIP-10: KNOWLEDGE.md — agentknowledge/v1 (LLM-maintained wiki)
A filesystem-first knowledge-base format where an LLM curates, links, and lints a markdown wiki on top of immutable raw sources, turning agent knowledge into a compounding artifact instead of a per-query retrieval miss.