Developers

Agents

Agent Reference

This is the authoritative reference for the agent format. An agent consists of two files: AGENT.md (persona) and agent.json (operational config).

AGENT.md

AGENT.md is pure prose markdown. No frontmatter is required. Its entire content replaces the agent's default identity in the system prompt when the agent is active.

Guidelines

  • Write in second person ("You are a...")
  • Define the agent's job, communication style, and boundaries
  • Be specific about what the agent should and should not do
  • Structure with headings for readability
  • There is no schema -- write whatever makes the persona clear

agent.json Schema

{
  "skills": ["@org/skills/name", "@org/skills/name@version"],
  "defaults": {
    "timezone": "user_local",
    "configurable": ["workflows.morning-briefing.trigger.cron"]
  },
  "pricing": {
    "model": "monthly_fixed",
    "cost": 47.0
  },
  "workflows": {
    "binding-name": {
      "trigger": {},
      "description": "string",
      "inputs": {},
      "activities": [],
      "budget": {},
      "emit": "string"
    }
  }
}

Top-Level Fields

Field Type Required Default Description
skills string[] No [] Qualified skill references this agent depends on. Auto-installed when the agent is installed.
defaults object No {} Default settings applied to the agent.
defaults.timezone string No "user_local" Timezone used for schedule triggers.
defaults.configurable string[] No [] Dot-path list of fields the owner may override at install time.
pricing object No {} Marketplace pricing configuration.
pricing.model string No -- Pricing model (e.g. "monthly_fixed", "per_run").
pricing.cost number No -- Dollar amount charged per pricing period or run.
workflows map No {} Map of binding name to WorkflowBinding. Keys are the binding names used in logs and debugging.

Skill References

Skills are referenced by qualified name, not plain name:

  • @org/skills/name -- latest version
  • @org/skills/name@version -- pinned version

At install time, skills can also be installed via code: SKIL-XXXX-XXXX.

WorkflowBinding

Each value in the workflows map is a binding that defines what to run and when. The key is the binding name.

Field Type Required Description
trigger Trigger Yes When this binding fires.
description string Yes Human-readable description of what this binding does.
inputs object No Arbitrary key-value inputs passed to the binding at runtime.
activities AgentActivity[] Yes Inline activities executed in order.
budget AgentBudget Yes Cost budget for the entire binding run.
emit string No Named event emitted on successful completion of all activities.

AgentBudget

Field Type Required Description
total_per_run integer Yes Maximum token spend per single run of this binding.
cost_estimate string Yes Human-readable cost estimate (e.g. "~$0.03").

Trigger Types

Schedule

Fires on a schedule defined by a standard cron expression (5-field).

{
  "type": "schedule",
  "cron": "0 8 * * 1-5"
}
Field Type Required Description
type "schedule" Yes --
cron string Yes 5-field cron expression.

Cron field reference: minute hour day-of-month month day-of-week

Expression Meaning
0 8 * * 1-5 Weekdays at 08:00
*/15 * * * * Every 15 minutes
0 0 1 * * First day of every month at midnight
0 9,17 * * * 09:00 and 17:00 daily

Heartbeat

Fires at a fixed interval. The first execution happens one interval after the agent activates. An optional window restricts execution to certain hours.

{
  "type": "heartbeat",
  "interval": "30m",
  "window": "08:00-18:00"
}
Field Type Required Description
type "heartbeat" Yes --
interval string Yes Duration string: "30s", "5m", "1h", "2h30m".
window string No Time-of-day window restricting when the heartbeat fires (e.g. "08:00-18:00").

Event

Fires when one or more named events are emitted by another binding's emit field.

{
  "type": "event",
  "sources": ["calendar.changed", "email.urgent"]
}
Field Type Required Description
type "event" Yes --
sources string[] Yes List of event names to subscribe to. Each must match an emit field in another binding.

Event namespacing: At runtime, events are namespaced by the agent's slug. For example, if the agent slug is chief-of-staff, an emitted event briefing.ready becomes chief-of-staff.briefing.ready.

Manual

Only fires when explicitly invoked by the user or another system component.

{
  "type": "manual"
}
Field Type Required Description
type "manual" Yes --

AgentActivity

Each activity is a discrete unit of work within a binding.

Field Type Required Default Description
id string Yes -- Unique identifier within the binding.
intent string Yes -- Natural language description of the goal. This is the prompt given to the LLM.
skills string[] No [] Skills loaded into context for this activity. Must be a subset of the agent's top-level skills.
mcps string[] No [] MCP server names made available to this activity.
cmds string[] No [] System commands the activity is allowed to execute.
model string Yes -- LLM model for this activity.
steps string[] No [] Ordered sub-steps for decomposing complex activities.
token_budget object Yes -- Token budget for this activity.
token_budget.max integer Yes -- Maximum tokens (input + output) allocated for this activity.
on_error object Yes -- Error handling policy for this activity.
on_error.retry integer Yes -- Number of retries before falling back.
on_error.fallback string Yes -- Fallback action: "NotifyOwner", "Skip", or "Abort".

Error Handling

Fallback Behavior
"NotifyOwner" Notify the owner of the error after retries are exhausted.
"Skip" Log the error and continue to the next activity. The binding can still emit on completion.
"Abort" Halt the entire binding. No further activities execute. The emit event is not fired.

Token Budgets

Token budgets prevent runaway costs. The budget applies to the total tokens (input + output) consumed by the activity's LLM calls.

  • If an activity exceeds its budget, execution stops for that activity.
  • The on_error policy determines whether the binding continues.
  • Set conservative budgets for simple tasks (notifications: 512) and larger budgets for research work (4096+).

Emit Chains

The emit field on a binding fires a named event after all activities complete successfully. Other bindings with matching event triggers will fire in response.

Chain Example

{
  "workflows": {
    "collect-data": {
      "trigger": { "type": "schedule", "cron": "0 */6 * * *" },
      "description": "Scrape latest data from configured sources",
      "inputs": {},
      "activities": [
        {
          "id": "scrape",
          "intent": "Scrape latest data from configured sources",
          "skills": ["@nebo/skills/web-scraper"],
          "mcps": [],
          "cmds": [],
          "model": "claude-sonnet",
          "steps": [],
          "token_budget": { "max": 4096 },
          "on_error": { "retry": 1, "fallback": "Abort" }
        }
      ],
      "budget": { "total_per_run": 5000, "cost_estimate": "~$0.04" },
      "emit": "data-collected"
    },
    "analyze-data": {
      "trigger": { "type": "event", "sources": ["data-collected"] },
      "description": "Analyze collected data for trends and anomalies",
      "inputs": {},
      "activities": [
        {
          "id": "analyze",
          "intent": "Analyze collected data for trends and anomalies",
          "skills": ["@nebo/skills/data-analyzer"],
          "mcps": [],
          "cmds": [],
          "model": "claude-sonnet",
          "steps": [],
          "token_budget": { "max": 4096 },
          "on_error": { "retry": 1, "fallback": "Abort" }
        }
      ],
      "budget": { "total_per_run": 5000, "cost_estimate": "~$0.04" },
      "emit": "analysis-complete"
    },
    "report": {
      "trigger": { "type": "event", "sources": ["analysis-complete"] },
      "description": "Generate a summary report and notify the user",
      "inputs": {},
      "activities": [
        {
          "id": "generate-report",
          "intent": "Generate a summary report and notify the user",
          "skills": ["@nebo/skills/report-writer"],
          "mcps": ["slack-notifier"],
          "cmds": [],
          "model": "claude-sonnet",
          "steps": [],
          "token_budget": { "max": 2048 },
          "on_error": { "retry": 1, "fallback": "Skip" }
        }
      ],
      "budget": { "total_per_run": 3000, "cost_estimate": "~$0.02" }
    }
  }
}

This creates a three-stage pipeline: schedule -> collect -> analyze -> report, where each stage is independently testable and has its own error handling.

Cycle Prevention

Emit chains must be acyclic. If binding A emits event X and binding B subscribes to X and emits Y, binding A must not subscribe to Y. Cycles are detected at agent load time and rejected with an error.

Installation Lifecycle

  1. Install: User enters AGNT-XXXX-XXXX code or installs from the marketplace.
  2. Cascade: All skills in the agent's skills array are auto-installed. If those skills have their own dependencies, those are installed too.
  3. Activate: The AgentWorker starts. AGENT.md is injected into the system prompt.
  4. Runtime: The AgentWorker parses agent.json, starts heartbeat loops, registers cron schedules, and subscribes to events.
  5. Execution: When a trigger fires, activities execute in order. On completion, emit events propagate to downstream bindings.
  6. Deactivate: Switching agents or uninstalling stops the AgentWorker, cancels all schedules and subscriptions.

AgentWorker Runtime

The AgentWorker is a per-agent runtime that manages the lifecycle of all bindings:

Responsibility Detail
Schedule scheduling Registers cron expressions with the system scheduler.
Heartbeat loops Spawns a timer loop for each heartbeat binding. Respects window constraints.
Event subscriptions Subscribes to named events from the internal event bus.
Activity execution Executes activities sequentially within a binding. Loads skills, connects MCPs, enforces token budgets.
Error handling Applies on_error policy per activity. Retries, then falls back. Logs all errors.
Emit propagation Fires named events on binding completion. Events are namespaced by agent slug.
Lifecycle management Starts on agent activation, stops on deactivation. Cleans up all timers and subscriptions.

Install Codes

AGNT-XXXX-XXXX
  • Prefix: AGNT-
  • Encoding: Crockford Base32 (excludes I, L, O, U for readability)
  • Two groups of 4 characters separated by a hyphen

Complete agent.json Example: Chief of Staff

{
  "skills": [
    "@nebo/skills/quick-research",
    "@nebo/skills/web-scraper",
    "@nebo/skills/note-taker",
    "@nebo/skills/report-writer"
  ],
  "defaults": {
    "timezone": "user_local",
    "configurable": [
      "workflows.morning-briefing.trigger.cron"
    ]
  },
  "pricing": {
    "model": "monthly_fixed",
    "cost": 47.0
  },
  "workflows": {
    "morning-briefing": {
      "trigger": {
        "type": "schedule",
        "cron": "0 7 * * 1-5"
      },
      "description": "Gather overnight updates and deliver a morning briefing",
      "inputs": {
        "sources": ["calendar", "email", "slack"]
      },
      "activities": [
        {
          "id": "gather-updates",
          "intent": "Collect overnight calendar changes, unread emails, and Slack highlights",
          "skills": ["@nebo/skills/quick-research", "@nebo/skills/web-scraper"],
          "mcps": ["google-calendar", "gmail"],
          "cmds": [],
          "model": "claude-sonnet",
          "steps": [
            "Fetch calendar events for today",
            "Scan unread emails for action items",
            "Pull Slack highlights from key channels"
          ],
          "token_budget": { "max": 4096 },
          "on_error": { "retry": 1, "fallback": "NotifyOwner" }
        },
        {
          "id": "write-briefing",
          "intent": "Synthesize gathered updates into a structured morning briefing and save it",
          "skills": ["@nebo/skills/note-taker", "@nebo/skills/report-writer"],
          "mcps": [],
          "cmds": [],
          "model": "claude-sonnet",
          "steps": [
            "Summarize top priorities",
            "List schedule conflicts",
            "Draft briefing note"
          ],
          "token_budget": { "max": 2048 },
          "on_error": { "retry": 1, "fallback": "Abort" }
        }
      ],
      "budget": {
        "total_per_run": 7000,
        "cost_estimate": "~$0.05"
      },
      "emit": "briefing.ready"
    },
    "notify-owner": {
      "trigger": {
        "type": "event",
        "sources": ["briefing.ready"]
      },
      "description": "Send a Slack DM when the briefing is ready",
      "inputs": {},
      "activities": [
        {
          "id": "send-slack",
          "intent": "Send a Slack DM notifying the owner their morning briefing is ready",
          "skills": [],
          "mcps": ["slack"],
          "cmds": [],
          "model": "claude-haiku",
          "steps": [],
          "token_budget": { "max": 512 },
          "on_error": { "retry": 2, "fallback": "Skip" }
        }
      ],
      "budget": {
        "total_per_run": 1000,
        "cost_estimate": "~$0.01"
      }
    },
    "health-check": {
      "trigger": {
        "type": "heartbeat",
        "interval": "30m",
        "window": "08:00-18:00"
      },
      "description": "Verify that all configured data sources are reachable",
      "inputs": {},
      "activities": [
        {
          "id": "check-sources",
          "intent": "Verify that all configured data sources are reachable and responding",
          "skills": ["@nebo/skills/web-scraper"],
          "mcps": [],
          "cmds": [],
          "model": "claude-haiku",
          "steps": [],
          "token_budget": { "max": 256 },
          "on_error": { "retry": 2, "fallback": "NotifyOwner" }
        }
      ],
      "budget": {
        "total_per_run": 500,
        "cost_estimate": "~$0.003"
      }
    },
    "deep-dive": {
      "trigger": {
        "type": "manual"
      },
      "description": "On-demand deep-dive research session on a user-specified topic",
      "inputs": {},
      "activities": [
        {
          "id": "research",
          "intent": "Perform a deep-dive research session on the user's specified topic",
          "skills": ["@nebo/skills/quick-research", "@nebo/skills/web-scraper", "@nebo/skills/note-taker"],
          "mcps": [],
          "cmds": [],
          "model": "claude-sonnet",
          "steps": [],
          "token_budget": { "max": 8192 },
          "on_error": { "retry": 1, "fallback": "Abort" }
        },
        {
          "id": "report",
          "intent": "Generate a comprehensive report from the deep-dive findings",
          "skills": ["@nebo/skills/report-writer"],
          "mcps": [],
          "cmds": [],
          "model": "claude-sonnet",
          "steps": [],
          "token_budget": { "max": 4096 },
          "on_error": { "retry": 1, "fallback": "Abort" }
        }
      ],
      "budget": {
        "total_per_run": 15000,
        "cost_estimate": "~$0.10"
      }
    }
  }
}