# The agent manifest — `.agent.yaml`

> The three definition verbs that take a manifest (`create` / `apply` / `update`) read the same **friendly manifest**: a YAML mapping (`-f <file>`, `-f -` for stdin, or a piped file) or `--flag` overrides. The CLI validates it client-side, then POSTs to `/agents:apply`. (`delete` just takes an id.) Grounded in the wiki's **Building Agents with the CLI** → *The full manifest*. Treat the CLI as source of truth — `ixora agents create --help`.

## The full manifest

```yaml
kind: Agent                          # optional; only "Agent" today
id: active-jobs-monitor              # stable id (slug); optional → defaults to a slug of the name
name: Active Jobs Monitor
description: Monitors active jobs and long-running SQL on IBM i
model: anthropic:claude-sonnet-4-6   # ALWAYS "provider:id" — never a bare name
db: agentos-db                       # optional; defaults to the primary database
stage: published                     # published (served) or draft (saved, not served). default: published
instructions: |
  You are an IBM i operations assistant. Prefer named SQL tools; fall back to
  validate_and_run_sql only when no named tool fits.
toolsets: [daily_health, db_performance]   # curated bundles — `ixora agents toolsets list`
ibmiTools:                           # optional custom SQL tools (see tool-yaml.md)
  - long_running_sql:
      source: default
      description: SQL running longer than :seconds seconds
      statement: |
        SELECT JOB_NAME, ELAPSED_TIME FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) X
        WHERE ELAPSED_TIME > :seconds FETCH FIRST :limit ROWS ONLY
      parameters:
        - { name: seconds, type: integer, default: 5,  min: 1 }
        - { name: limit,   type: integer, default: 25, min: 1, max: 200 }
      security: { readOnly: true }
knowledge: "User Documents"          # optional; attach a knowledge base by DISPLAY name (`ixora knowledge bases`)
options:                             # optional agno Agent settings, passed straight through (see below)
  num_history_runs: 3
  add_history_to_context: true
metadata: { owner: ops-team }        # optional free-form
```

Valid top-level keys: **`kind, id, name, description, model, db, stage, instructions, toolsets, ibmiTools, knowledge, options, metadata`**. Any other key is **rejected** (a typo like `instructionz` errors with the valid list — not silently dropped).

## Canonical schema

There is no standalone JSON-schema *file* for the whole manifest (the only `*.schema.json` shipped, `../assets/sql-tools-config.schema.json`, covers just the `ibmiTools` entries). The authoritative definition is the **`ApplyAgentRequest` Pydantic model** the platform validates `POST /agents:apply` against — `extra="forbid"`, so an unknown key is a 422. This page mirrors it; the `ixora` CLI mirrors it client-side too. For the machine-readable schema, run `ixora docs` against a running stack — `ApplyAgentRequest` appears under `components.schemas` in `/openapi.json`.

## `options` — agno knobs (history / memory / session)

`options` is an object passed through to the agno `Agent`. Set only the keys you need; omit to inherit defaults. Common ones:

| Concern | Keys |
|---|---|
| History | `num_history_runs`, `add_history_to_context` |
| Session state | `session_state` (object), `add_session_state_to_context`, `enable_agentic_state` |
| Memory | `enable_agentic_memory` **XOR** `update_memory_on_run` (mutually exclusive — set at most one) |
| Output | `markdown`, `cache_session` |

From flags, pass `--options '{"num_history_runs":5,"add_history_to_context":true}'` (a JSON object). **Never** put `tools` / `dependencies` / a `db` config-object in `options` — those are server-managed and get stripped (reported as `Ignored protected override key(s): …`). The manifest's top-level `db:` (a database name) is the supported way to pick the registry database.

## Flags vs. file

Every manifest field has a flag (`--name`, `--id`, `--model`, `--instructions`, `--description`, `--toolsets a,b`, `--db`, `--knowledge`, `--stage`, `--options <json>`); custom tools attach via the repeatable `--ibmi-tools <file>`. Flags **win** over file fields, so a file + a flag override is a clean way to tweak one value. `update` is a **sparse** merge — only the fields you pass change; it requires at least one.

## Mistakes the CLI / server catch

- `model` must be `provider:id` with both halves non-empty → `Invalid --model …`.
- A bad toolset name → `Unknown toolsets: … Available: …`.
- `update` on a missing id → `not found` (create it first); `create` on an existing id → `already exists. Use apply/update.`
- An unknown `knowledge` name → rejected with the list of available bases (`ixora knowledge bases`).
- **Stage:** default `published` (served immediately). `--stage draft` saves without serving — a draft is absent from `ixora agents list` (served only) though present in `ixora components list`; re-apply `--stage published` to serve it.

## See also
- [`tool-yaml.md`](tool-yaml.md) — author the custom SQL tools
- [`introspection.md`](introspection.md) — introspect the schema first, with the container `ibmi`
- [`hardening.md`](hardening.md) — probe-test after creating
