Subagents - Z-M-Huang/openhive GitHub Wiki

Subagent Definitions

Subagents are the execution layer within a team. The orchestrator ALWAYS delegates tasks to subagents — it never invokes skills directly (ADR-40). Each subagent brings a different perspective and follows its own set of skills.

This page covers subagent definition files, the subagent-only invariant, and wiring. For the overall rule system, see Rules-Architecture. For reusable procedures that subagents follow, see Skills. For learning and reflection cycles, see Self-Evolution.


Architecture Hierarchy

graph TD
    orch["Team Orchestrator<br/>(manages subagents, never invokes skills directly)"]

    subgraph agents["Subagents (perspectives)"]
        a1["loggly-monitor<br/>Skills: get-loggly-log, alert-check"]
        a2["incident-responder<br/>Skills: incident-response"]
    end

    subgraph skills["Skills (procedures)"]
        s1["get-loggly-log.md"]
        s2["alert-check.md"]
        s3["incident-response.md"]
    end

    subgraph plugins["Plugins (executable tools)"]
        p1["loggly_fetch.ts"]
        p2["classify_entries.ts"]
        p3["pagerduty_notify.ts"]
    end

    orch -->|"invokes"| a1
    orch -->|"invokes"| a2
    a1 -->|"follows"| s1
    a1 -->|"follows"| s2
    a2 -->|"follows"| s3
    s1 -->|"Required Tools"| p1
    s2 -->|"Required Tools"| p1
    s2 -->|"Required Tools"| p2
    s3 -->|"Required Tools"| p3
Loading

Subagent-Only Invariant (ADR-40)

Orchestrators ALWAYS delegate to subagents. No direct skill invocation by orchestrators. A {subagent}.md is always loaded into context for task execution.

This means:

  • Every task that enters a team is routed by the orchestrator to a specific subagent
  • The orchestrator reads subagent definitions to decide which subagent handles a given task
  • If no existing subagent fits, the orchestrator can create a new one or escalate

Main Agent Exception

The main agent is NOT a team orchestrator. It routes user requests to child teams and delegates. It has:

  • No subagents
  • No skills
  • No learning or reflection triggers
  • No direct task execution

The main agent's only tools are: channel adapters, organization tools (spawn_team, delegate_task, escalate, etc.), and list_teams for routing decisions.


Subagent Responsibilities

Responsibility Description
Task execution Follow skills, use plugins to perform work
Learning cycles Own nightly learning triggers (see Self-Evolution#Autonomous Learning)
Reflection cycles Own nightly reflection triggers (see Self-Evolution#Self-Reflection)
Self-evolution proposals Identify issues in own files, propose changes, escalate to orchestrator for confirmation
Notification decisions Decide whether results warrant user notification (actionable findings only)

Responsibility Chain

Layer Responsible for If stuck
Main agent Identifying which team owns the problem Asks user for clarification
Orchestrator Choosing the right subagent, confirming proposed changes Escalates to main if no subagent fits
Subagent Diagnosing issue, proposing fix, executing within boundaries Escalates to orchestrator if out of scope
Skill Step-by-step procedure Subagent adapts or proposes skill revision
Plugin Single API call execution Skill handles errors per its steps

User → Fix Flow

For a complete walkthrough of how user requests flow through the full hierarchy (Main → Orchestrator → Subagent → Skill → Plugin), see Scenarios#User → Fix Flow.


File Layout

Subagent definitions live in .run/teams/{name}/subagents/, one markdown file per agent.

Example ops-team directory:

.run/teams/ops-team/
├── config.yaml
├── org-rules/
├── team-rules/
├── subagents/
│   ├── loggly-monitor.md
│   └── incident-responder.md
├── skills/
│   ├── get-loggly-log.md
│   ├── alert-check.md
│   └── incident-response.md
└── plugins/
    ├── loggly_fetch.ts
    ├── classify_entries.ts
    └── pagerduty_notify.ts

Subagent Definition Format

Each subagent definition file contains four sections:

Section Purpose
Role What the agent specializes in
Skills Which skills this agent follows, each with its purpose
Boundaries Scope limits and escalation conditions
Communication Style (optional) How the agent reports progress and findings

The file heading names the agent (e.g., # DevOps Agent).

Runtime Mechanics

Subagent definitions are loaded by skill-loader.ts from .run/teams/{name}/subagents/ and converted into AI SDK tool() definitions by subagent-factory.ts. Each subagent tool wraps a generateText() call, giving the orchestrator a way to delegate focused subtasks with isolated context. The orchestrator sees only the final result text, not intermediate tool calls.


Notification Behavior

Subagents only notify the user on actionable findings (errors, warnings, fatals). Clean checks and routine results are stored in the task queue but not pushed to any channel. This prevents noise from routine operations.

For early-exit monitoring behavior when a clean check completes, see Skills#Early-Exit Monitoring.


Self-Evolution Authority

Subagents can identify issues in their own files (subagent.md, skills/*.md, plugins/*.ts) and draft proposals for changes. However, subagents do NOT apply changes directly. They escalate to the orchestrator for confirmation via the propose+confirm model.

See Self-Evolution#Evolution Flow for the full propose+confirm sequence.


Window-Trigger Subagents

When a subagent is targeted by a window trigger (ADR-42; see Triggers#window Trigger Type), its Responsibilities section MUST declare three items explicitly — these are enforced invariants, not conventions:

Required Declaration What It States
Cursor keys Exactly which memory keys the subagent reads at tick start and writes at tick end. Keys MUST be namespaced as <subagent_name>:<cursor_name> (e.g., news-scanner:last_event_id) to prevent collision when multiple subagents share a team.
No-op return contract Commitment to return { action: "noop", reason: string } when the tick's scan finds nothing actionable. The trigger engine treats any other shape as a real result. See Tool-Guidelines#No-op Tick Contract.
Idempotency invariant One-sentence statement of why repeat ticks over the same data produce no duplicate work (typically "cursor advances monotonically and external side effects are gated by cursor").

Responsibilities Template (window-tick subagent)

Copy this block into the subagent's Responsibilities section and fill in the blanks:

## Responsibilities

### Cursor keys
- Reads: `<subagent_name>:last_scan_cursor` at tick start.
- Writes: `<subagent_name>:last_scan_cursor`, `<subagent_name>:last_event_id` at tick end.
- Namespace: all cursor keys prefixed with `<subagent_name>:` per [[Tool-Guidelines#Cursor Discipline]].

### No-op return contract
If the scan finds no new items beyond `last_scan_cursor`, this subagent returns:
`{ "action": "noop", "reason": "no new items since <cursor value>" }`
Any other structure is treated by the engine as a real result. See [[Tool-Guidelines#No-op Tick Contract]].

### Idempotency invariant
Cursor `<subagent_name>:last_scan_cursor` advances only when new items have been durably processed; external side effects (e.g., `enqueue_parent_task`) are gated by cursor advancement, so replay of a tick produces no duplicate work.

Teams whose subagents are NOT targeted by a window trigger do not need these declarations.

⚠️ **GitHub.com Fallback** ⚠️