/docs / agents / configuration

Agent Configuration

The complete technical reference for agent.json -- the file that defines an agent's operational structure: which workflows to run, when to run them, what events to listen for, pricing, input fields, memory scoping, tool definitions, and validation rules.

Only AGENT.md (persona) is required. agent.json (operational wiring) is optional, and manifest.json (marketplace identity) is optional too — it's only required for apps. This page covers agent.json. For persona and memory, see Personas & Memory. For tools and delegation, see Tools & Delegation. For an overview, see Agents Overview.

agent.json -- The Job Definition

The agent.json carries the operational structure: which workflows to run, when to run them, and what events to listen for. This is the file that makes an Agent more than a folder of workflows -- it's what makes it an employee who already knows the job.

{
  "workflows": {
    "morning-briefing": {
      "trigger": {
        "type": "schedule",
        "cron": "0 7 * * *"
      },
      "description": "Daily morning briefing before the user wakes up",
      "activities": [
        { "id": "gather", "prompt": "Gather today's calendar, unread emails, and open tasks" },
        { "id": "write", "prompt": "Write a concise morning briefing from the gathered data" }
      ]
    },
    "day-monitor": {
      "trigger": {
        "type": "heartbeat",
        "interval": "30m",
        "window": "08:00-18:00"
      },
      "description": "Monitors for changes and interrupts only when something matters"
    },
    "evening-wrap": {
      "trigger": {
        "type": "schedule",
        "cron": "0 18 * * *"
      },
      "description": "End of day summary -- what happened, what's unresolved, what's tomorrow"
    },
    "interrupt": {
      "trigger": {
        "type": "event",
        "sources": ["calendar.changed", "email.urgent"]
      },
      "description": "Fires when something urgent surfaces that needs immediate attention"
    }
  },
  "requires": {
    "plugins": ["PLUG-PJ3Z-ECFV"]
  },
  "skills": [
    "@nebo/skills/briefing-writer@^1.0.0"
  ],
  "pricing": {
    "model": "monthly_fixed",
    "cost": 47.0
  },
  "inputs": [
    {
      "key": "timezone",
      "label": "Your Timezone",
      "type": "select",
      "required": true,
      "default": "US/Eastern",
      "options": [
        { "value": "US/Eastern", "label": "Eastern" },
        { "value": "US/Pacific", "label": "Pacific" }
      ]
    },
    {
      "key": "briefing_focus",
      "label": "What should briefings focus on?",
      "type": "textarea",
      "placeholder": "e.g., sales pipeline, client deadlines, market news"
    }
  ],
  "defaults": {
    "timezone": "user_local",
    "configurable": [
      "workflows.morning-briefing.trigger.cron",
      "workflows.evening-wrap.trigger.cron",
      "workflows.day-monitor.trigger.interval"
    ]
  }
}

agent.json Fields

Top-Level

FieldTypeRequiredDefaultDescription
workflowsmapno{}Workflow bindings with triggers (keyed by binding name)
requiresobjectno{}Hard dependencies. requires.plugins is an array of plugin install codes (e.g., ["PLUG-PJ3Z-ECFV"]) that are auto-installed before skills during agent install.
skillsstring[]no[]Additional skill qualified names (beyond what workflows declare)
inputsarrayno[]Input field definitions for the agent's Configure tab (see Input Fields below)
pricingobjectno--Pricing configuration (see Pricing below)
defaultsobjectno{}Default settings and user-configurable fields (see Defaults below)
memoryobjectno{}Memory scoping configuration (see Personas & Memory)
toolsAgentToolDef[]no[]Sidecar HTTP endpoints exposed as native LLM tools (see Tools & Delegation)
scopesmapno{}Named tool restriction sets (see Tools & Delegation)
soulstringno--Agent personality/voice (DB-only via agents.soul column). Not parsed from agent.json -- set via Settings UI or API.

Pricing

FieldTypeRequiredDescription
modelstringyesPricing model: monthly_fixed or per_run
costfloatyesPrice in USD. For monthly_fixed, the monthly subscription price. For per_run, the cost per workflow execution.

Defaults

FieldTypeDescription
timezonestringTimezone for schedule triggers. user_local resolves to the user's system timezone at install time. Also accepts IANA timezone names (e.g., America/New_York).
configurablestring[]JSON paths within agent.json that the user can override after installation.

Input Fields

Input fields define a dynamic form rendered in the agent's Configure tab. Users fill in values after installation; the agent uses them at runtime.

FieldTypeRequiredDescription
keystringyesUnique reference key (used in {{}key{}'} template substitution and system prompt injection)
labelstringyesDisplay label shown to the user
typestringyesField type: text, textarea, number, select, checkbox, radio
descriptionstringnoHelp text displayed below the field
requiredbooleannoWhether the field must be filled before the agent can activate
defaultanynoDefault value pre-filled in the form
placeholderstringnoPlaceholder text for text/textarea fields
optionsarraynoFor select/radio fields: [{ "value": "...", "label": "..." }]

How input values are used

1. System prompt injection -- All filled input values are appended to the agent's system prompt as a "Configured Inputs" section. The LLM sees them and uses them without asking the user again.

2. Watch trigger template substitution -- {{}key{}'} placeholders in watch trigger commands are replaced with the corresponding input value at runtime. Example:

gmail +watch --project {{gcp_project}}
The placeholder name must exactly match an input key. If the command uses {{gcp_project}}, there must be an input with "key": "gcp_project". Unmatched placeholders are left as literal text (e.g., --project {{gcp_project}}), which will cause the watch command to fail or behave unexpectedly.

3. Stored separately from schema -- The input field schema lives in agent.json. The user-supplied values are stored in the input_values DB column and updated via PUT /agents/{id}/inputs.

Memory

Controls how the agent's memories are scoped and inherited. By default, each agent gets its own isolated memory pool (user_id:agent:{agent_id}). These fields extend that behavior.

FieldTypeDefaultDescription
inherit_userbooleanfalseWhen true, the agent can read the user's main Nebo preferences (timezone, language, communication style). Read-only -- the agent never writes to the user's memory scope.
context_isolatedbooleanfalseWhen true, memories are isolated per contextId from SDK embed sessions. Each document/project/record gets its own memory pool.

Example memory configuration:

{
  "memory": {
    "inherit_user": true,
    "context_isolated": true
  }
}

When to use context_isolated

Use this when your agent handles multiple independent contexts -- legal clients, project documents, patient records -- where facts from one context must never leak into another. The contextId comes from the SDK embed:

nebo.chat.mount(container, { contextId: document.id });

Each context maintains its own memory pool. Agent-wide memories (stored without a contextId) are still visible to all contexts.

When to use inherit_user

Use this when your agent needs user preferences without asking for them -- timezone for scheduling, language for communication, name for personalization. The agent reads from the main Nebo companion's tacit/preferences memories (read-only).

Three-tier user_id convention

Memory scoping follows a layered naming convention:

Layeruser_id formatDescription
Layer 1 (User)"user123"Nebo companion preferences (timezone, language, style)
Layer 2 (Agent)"user123:agent:brief"Agent-wide memories
Layer 3 (Context)"user123:agent:brief:ctx:doc-123"Per-document/project memories

How the config flags interact:

  • Default (both false) -- reads/writes Layer 2 only
  • inherit_user: true -- reads Layer 1 (read-only) + reads/writes Layer 2
  • context_isolated: true -- reads/writes Layer 3 instead of Layer 2
  • Both enabled -- reads all 3 layers, writes Layer 3

Workflows Overview

The workflows map pairs triggers (when to run) with activities (what to do). Each binding connects a trigger to either inline activities or an external workflow reference.

For the full reference -- trigger types, activities, event system, watch triggers, budget math, and examples -- see Workflows & Automation.

Trigger Types (Summary)

TypeDescription
scheduleFires on a cron schedule
heartbeatFires at a recurring interval (with optional time window)
eventFires when a matching event occurs
watchLong-running plugin process emitting NDJSON
folderFires when files change in a watched directory
manualOnly fires by explicit user request or API call

Tool Scoping

Agents can declare named scopes that restrict which tools, skills, and plugins are available in a given context. This lets the same agent operate with different capabilities depending on where it runs.

{
  "scopes": {
    "write": { "tools": ["file_write", "email_send"], "skills": [], "plugins": [] },
    "read": { "tools": ["file_read", "email_search"], "skills": [], "plugins": [] }
  }
}

Each scope is a ToolScope struct with three fields:

  • tools -- tool names to allow
  • skills -- skill qualified names to allow
  • plugins -- plugin install codes to allow

SDK embeds pass a scope parameter, and the runner restricts tool access to that named scope's allowlist:

nebo.chat.mount(container, { scope: "read" });

Use case: A public-facing embed uses the read scope (search and view only), while the main Nebo UI uses the write scope (full access). Same agent, different capabilities per context.

Sidecar Tool Definitions

Tools can be declared directly in agent.json, turning sidecar HTTP endpoints into native LLM tools (not proxied through a wrapper):

{
  "tools": [
    {
      "name": "get_document",
      "description": "Fetch a document by ID",
      "method": "GET",
      "path": "/documents/{id}",
      "input_schema": { "type": "object", "properties": { "id": { "type": "string" } } }
    }
  ]
}

Behavior:

  • Each entry becomes a tool the LLM can call directly
  • Path parameters are resolved from input: /documents/{id} with {"id": "abc"} becomes /documents/abc
  • HTTP method determines body vs query handling (GET uses query params, POST/PUT/PATCH send a JSON body)
  • Discovery is also available via a GET /_tools endpoint on the sidecar, returning the same format

Agent Soul

The soul field is separate from AGENT.md. Where AGENT.md defines capabilities, communication style, and the job description, soul captures voice, personality quirks, tone, ethical boundaries, and values -- the character behind the role.

  • Stored in the agents.soul DB column
  • Injected into prompt assembly as agent_soul context
  • Editable in Settings > Soul section
# Core Truths
- Be genuinely helpful, not performatively helpful
- Have opinions and share them when relevant

# Vibe
- Conversational and warm, not corporate
- Direct and honest -- skip filler words

# Boundaries
- Private things stay private. Period.
- When in doubt, ask before acting externally

When to use soul vs AGENT.md

AGENT.mdsoul
PurposeJob descriptionPersonality
ContainsCapabilities, priorities, judgment rulesVoice, tone, quirks, values, ethical lines
AnalogyWhat the agent doesWho the agent is

Multi-Agent Delegation

An agent can delegate tasks to other installed agents using the agents domain tool. The delegating agent pauses while the target agent runs with its full identity -- persona, plugins, skills, and memory scoping.

Tool Call

agents(action: "delegate", name: "Deal Tracker", prompt: "List all open deals closing this month")
ParameterTypeRequiredDescription
namestringyes*Target agent's display name
idstringyes*Target agent's ID (alternative to name)
promptstringyesTask description for the delegated agent
waitbooleannoWait for result before continuing (default: true). Set false for background delegation.
max_iterationsintegernoMaximum agentic loop iterations for the delegated agent (0 = default)

* One of name or id is required.

Session Isolation

Each delegation creates a separate session keyed as subagent:<parent_id>:<child_id>. The delegated agent:

  • Loads its own AGENT.md persona and skills
  • Runs with its own plugin set (from requires.plugins in its agent.json)
  • Gets its own memory scope -- it does not read the parent's conversation history
  • Returns a text result to the parent when complete

When to Use Delegation

ScenarioApproach
Agent needs a capability it doesn't have (e.g., calendar access)Delegate to an agent that has the required plugins
Task requires a different persona or expertiseDelegate to a specialist agent
Background processing while continuing the conversationDelegate with wait: false
Sequential pipeline across multiple agentsChain delegations in workflow activities

Constraints

  • The target agent must be installed (appears in agents(action: "list"))
  • If not already active, delegation auto-activates the target agent
  • Delegation inherits the parent's cancellation token -- cancelling the parent cancels the child
  • There is no built-in depth limit, but deep delegation chains consume more tokens and time

Followup Suggestions

After each chat turn, the agent generates 2-3 contextual follow-up suggestions displayed as clickable chips below the response. This helps users continue the conversation without typing.

Constraints:

  • 2-8 words each
  • Not phrased as questions
  • No "Tell me" / "Can you" patterns
  • Uses the cheapest available provider (avoids Janus credits for background operations)

Followup generation happens asynchronously after the main response completes. The chips are delivered to the frontend via WebSocket.

Auto-Install Cascade

When a user installs an Agent:

  1. Parse agent.json for requires.plugins and skill references
  2. Install required plugins from requires.plugins (install codes like PLUG-XXXX-XXXX)
  3. For each workflow binding: install its declared skill dependencies
  4. Install any additional skills listed in top-level skills array
  5. Skills cascade to their own plugin dependencies (via plugins: in SKILL.md frontmatter)
  6. Register all trigger bindings from agent.json
  7. Load the AGENT.md persona into the agent's context

The user installs a job. Everything else cascades -- plugins first, then skills.

Filesystem Watcher (Development)

During development, agents placed in the Nebo data directory's user/agents/ folder are detected automatically by the filesystem watcher. The data directory is platform-native -- ~/Library/Application Support/Nebo/ on macOS, %APPDATA%\Nebo\ on Windows, ~/.local/share/nebo/ on Linux (override with NEBO_HOME):

  • Added: New agent directory or symlink with AGENT.md -- appears in sidebar and Apps page
  • Changed: Edits to AGENT.md, agent.json, or manifest.json -- metadata updated in DB, worker restarted if active
  • Removed: Deleted directory -- agent soft-deactivated (DB record preserved with is_enabled=0)

Changes are debounced at 1 second. No restart needed. Symlinks are fully supported -- you can symlink an entire app directory from your source repo into the data directory's user/agents/ folder and changes take effect immediately.

Validation Rules

The following rules are enforced when parsing agent.json:

  • Each workflow binding must have a trigger
  • Trigger type must be one of: schedule, heartbeat, event, watch, folder, manual
  • Workflow bindings with invalid triggers are skipped with a warning -- they do not prevent the agent from loading
  • Schedule triggers must have a valid cron expression
  • Heartbeat triggers must have a valid interval (e.g., "30m", "1h")
  • Event triggers should have at least one entry in sources -- an empty array is accepted but the trigger will never fire
  • Skill refs must be qualified names (@org/skills/name)
  • Watch triggers must have a plugin and either event or command (both recommended -- command as fallback for when event resolution fails)
  • Activity IDs must be unique within each binding
  • If budget.total_per_run > 0, the sum of all activity token_budget.max values must not exceed it
  • All {{}key{}'} placeholders in watch trigger commands must match an input key exactly
  • An Agent with no workflows is valid -- it provides only a persona and skill declarations