<!-- Source: https://docs.squirro.com/en/latest/technical/neo/admin-guide/agent-config/authoring-agents.html -->
# Authoring Agents

> **Warning**
>
> Project Neo is currently in [Technical Preview](../../../../a-z/squirro-glossary.md#term-Technical-Preview). Features described in this section may change before general availability.

This page covers what you can change about an agent and when: how to write its instructions, and the full definitions of preferences, constraints, and pins. For the broader configuration model, typed resources, and how a request resolves across the project, agent, user, and request layers, see the [Overview](overview.md#neo-agent-config-overview) page.

An agent is defined by:

- **Instructions**

  What it does. The prose the model runs as its system prompt, authored as the markdown body of a `.md` agent.
- **Preferences**

  Soft defaults for the model, the reasoning effort, the active traits, and the retrieval profile. A user can override a preference.
- **Constraints**

  Hard restrictions. Values outside the allowed set cannot be used for the agent. A user cannot override a constraint.
- **Pins**

  Absolute locks. Identity-level decisions that nothing can override.
- **Extends**

  Inherit configuration from another agent.

For the complete catalog of preference paths you can set, with the type and allowed values for each, see the [Preference Reference](preference-reference.md#neo-agent-config-preference-reference) page.

## Write the Instructions

The instructions are the markdown body of the `.md` agent, everything below the block enclosed by the `---` lines at the top of the file. The Squirro instance passes that body to the model as its system prompt, essentially as written. Nothing strips or reformats it, so the structure you author is the structure the model receives.

The one exception is the `<when>` tag. The character sequences `<when ...>` and `</when>` are reserved for the model-specific macro described in the [Model-Specific Text](#neo-agent-config-model-specific-text) section. The platform interprets them instead of passing them through, and a sequence that is not a valid tag fails `genai lint`. Do not write `<when` or `</when>` in your instructions unless you mean the macro.

Because the model receives the raw content, use markdown to make the instructions clear and to emphasize what matters:

- **Bold** for the rules that must not be missed.
- Bulleted or numbered lists for steps, checks, and output formats.
- Headings to separate concerns, such as tone, scope, and what to refuse.
- Inline `code` for exact tool names, field names, or literal values.

A short, well-structured prompt usually outperforms a long, unstructured one. Lead with the role and the task, then the rules, then the output format.

```text
---
kind: Agent
schema: v1
metadata:
  id: research
entrypoint: true
---

You are a research analyst for the compliance team.

**Always:**

- Cite every claim with its source.
- Flag anything you cannot verify rather than guessing.

## Output

Return a one-paragraph summary, then a bulleted list of findings.
```

### Model-Specific Text

To include a fragment of the prompt only for certain models, wrap it in a `<when>` tag. The `<when>` tag matches on the resolved model and includes its body only when the pattern matches:

```text
Answer concisely.

<when model="claude-opus-*">
For this model, show your reasoning step by step before the final answer.
</when>
```

The tag accepts one of two keys, `model` or `provider`, and the pattern is a glob, so `claude-opus-*` matches every Opus version. A tag whose pattern does not match contributes nothing to the rendered prompt.

Several sibling tags are allowed, and the bodies of the ones that match are included in the order they appear. The same key and pattern can appear more than once, and each matching tag contributes its body at its own position, so repeated tags accumulate rather than override one another. For a request resolved to an Opus model, the following renders both extra lines, the reasoning line first and the citation line second:

```text
Answer concisely.

<when model="claude-opus-*">
Show your reasoning step by step before the final answer.
</when>

<when provider="anthropic">
Cite the source for every claim.
</when>
```

Tags cannot be nested. A `<when>` tag inside another `<when>` tag fails `genai lint`:

```text
<when provider="anthropic">
Cite your sources.
<when model="claude-opus-*">
Show your reasoning.
</when>
</when>
```

Each `<when>` tag takes a single key, either `model` or `provider`, with one pattern. You cannot put both keys in one tag, and because tags cannot be nested, there is no way to require a model and a provider at once. Sibling tags match independently, so use a `model` pattern when you need a specific model and a `provider` pattern when you need a whole provider family.

To share prose across several agents rather than conditioning it on the model, use a trait, described in the [Compose Prose With Traits](#neo-agent-config-traits) section.

## Set a Default Model

Use `prefers` to set the default model for the agent:

```text
---
kind: Agent
schema: v1
metadata:
  id: research
prefers:
  inference.model: claude-sonnet
---

You are a careful research analyst...
```

If the user does not choose a model, the agent uses Sonnet. If the user picks a different published model, that choice wins.

`prefers` is the least restrictive primitive: it sets the starting value but leaves every choice open to the user. Constraints and pins, covered next, restrict what the user can select.

## Restrict the Model Set

Use `constrains` to restrict which values are allowed:

```text
constrains:
  inference.model:
    in:
      - claude-sonnet
      - claude-opus
```

A user can switch between Sonnet and Opus but cannot pick any other model for the agent. An attempt to pick a model outside the allowed set falls through to a value the constraint allows.

For the full predicate syntax, such as `in`, `not_in`, and `matches`, see the [Predicate Syntax for Constraints](resource-reference.md#neo-agent-config-predicates) section. For the resolution model behind it, see the [Overview](overview.md#neo-agent-config-overview) page.

## Lock a Value with a Pin

Use `pins` when a value is part of what the agent is and must never change:

```text
pins:
  source.documents.enabled: false
```

A pin fixes the value. Nothing can change it, and nothing else needs to set it.

The decision rule:

- **prefers**

  Sets a default value that the user can still override. The least restrictive primitive. Use it whenever the user should be free to choose. For example, set `inference.model` to a default model the user can swap, or `trait.style: concise` as a starting tone the user can change.
- **constrains**

  Limits which values are allowed. An agent can narrow the set further than the project, but can never widen it beyond what a parent allows. Use it to keep choices within a safe or supported range. For example, limit `inference.model` to the two models you have vetted, so a user cannot select an unsupported one.
- **pins**

  Locks the value so nothing can change it, not a user, an agent, or a request. Use it only for a value that is part of what the agent is, rather than a setting the user should be able to touch. For example, pin `source.documents.enabled: false` on an agent that must never read from documents.

## Share Configuration with Extends

When several agents should share the same model constraints, capability set, and retrieval defaults, factor the shared configuration into a `.yaml` template:

```text
# agents/research_template.yaml
kind: Agent
schema: v1
metadata:
  id: research_template

constrains:
  inference.model:
    in:
      - claude-sonnet
      - claude-opus

prefers:
  capability.code_interpreter.enabled: true
  source.documents.enabled: true
```

The template is a `.yaml` file rather than a `.md` file because it holds configuration only. A `.yaml` agent has no markdown body, so it carries no instructions, which is exactly why instructions are never inherited through `extends`.

The name `research_template` is only an example. You are free to name the template anything, and the platform gives the name no special meaning. The `id` and the file name are yours to choose, as long as the `id` follows the identifier rules, and a child references the template by that same `id` in its `extends` list.

Then use `extends` from each agent that needs it:

```text
---
# agents/deep_research.md
kind: Agent
schema: v1
metadata:
  id: deep_research
extends: [research_template]
prefers:
  inference.model: claude-sonnet
  inference.reasoning_effort: high
---

You are a deep research analyst. Take your time. Cite your sources.
```

`extends` inherits configuration only, meaning the preferences, constraints, and pins of the parent. It never inherits instructions: a child agent does not pick up the parent prose, so each runnable `.md` agent writes its own instructions. To share prose across agents instead, use a trait, described in the [Compose Prose With Traits](#neo-agent-config-traits) section.

A preference that falls outside a constraint inherited through `extends` does not fail the deploy. At runtime, resolution records the value as invalid and falls through to the next source. Use `genai explain` to spot a preference that never takes effect, then either pick a value the parent allows or relax the parent constraint.

## Compose Prose With Traits

A `TraitDimension` is a named dimension where each entry contributes a prompt fragment when active. Use it to reuse the same prose across several agents:

```text
# trait-dimensions/style.yaml
kind: TraitDimension
schema: v1
metadata:
  id: style

traits:
  concise:
    prompt_fragment: |
      Keep your responses tight. No preamble, no recap.
  detailed:
    prompt_fragment: |
      Be exhaustive. Walk through your reasoning and cite each step.
```

An agent activates a trait through preferences. Here, the `research` agent, a `.md` file, selects the `concise` entry of the `style` dimension:

```text
---
kind: Agent
schema: v1
metadata:
  id: research
entrypoint: true
prefers:
  trait.style: concise
---

You are a research analyst for the compliance team.
```

When the agent instructions are rendered, the fragment for the active trait is appended. Multiple dimensions compose freely. Your configuration can also set a baseline trait on the `Project` resource, which applies to every agent that does not set its own value. The `Project` resource is the project manifest, a YAML file named `project.yaml`:

```text
# project.yaml
kind: Project
schema: v1
title: Compliance workspace

prefers:
  inference.model: claude-sonnet
  trait.style: detailed
```

With this manifest in place, every agent uses the `detailed` style by default. An agent that sets its own `trait.style` overrides that baseline. The `research` agent above sets `trait.style: concise`, so it stays `concise` rather than falling back to the project `detailed`.

## Entrypoints and Delegates

An agent can be user-selectable, a subagent target, both, or neither:

- **Entrypoint**

  An agent the user picks in the conversation interface. Set `entrypoint: true`.

  ```text
  ---
  kind: Agent
  schema: v1
  metadata:
    id: assistant
  entrypoint: true
  ---

  You are a helpful assistant.
  ```
- **Delegate**

  A subagent that another agent can call, not user-selectable. Set `delegate: true` and provide a `description` that a calling agent reads to decide whether to call it. A calling agent needs `capability.subagents.enabled: true` to invoke a delegate at runtime.

  ```text
  ---
  kind: Agent
  schema: v1
  metadata:
    id: citation_checker
  delegate: true
  description: Verifies that quoted passages match their cited sources. Returns a list of mismatches.
  ---

  You verify citations. Given a document and a list of quotes, check each quote against the source...
  ```
- **Both**

  An agent that is both user-selectable and callable as a subagent. Set both flags.

  ```text
  ---
  kind: Agent
  schema: v1
  metadata:
    id: research
  entrypoint: true
  delegate: true
  description: Researches a question and returns a sourced summary.
  ---

  You are a research analyst for the compliance team.
  ```
- **Neither**

  There is no `neither` flag. When the envelope mentions neither `entrypoint` nor `delegate`, both fields take their default of `false`, and the agent is neither user-selectable nor callable as a subagent, so it is never invoked directly. This is therefore the default state of any agent that does not opt in. Its only role is to be an `extends` parent: a shared template, such as the `research_template` above, that other agents inherit configuration from. Because it is never invoked, it needs no instructions and is typically a configuration-only `.yaml` file. To make an agent reachable, set `entrypoint: true`, `delegate: true`, or both.

  ```text
  kind: Agent
  schema: v1
  metadata:
    id: research_template

  constrains:
    inference.model:
      in:
        - claude-sonnet
        - claude-opus
  ```

## How an Agent Appears in Chat

When you deploy a configuration, the entrypoint agents become the assistants a user can select in the Chat dashboard. What you author determines what the user sees and how the conversation starts.

In the picker:

- Only entrypoint agents are offered, in the order set by `entrypoint_order` and then by id. An agent that is not an entrypoint, such as a delegate, is never shown.
- Each assistant shows a title and, when set, a short summary. The title is the agent `title` when you set one, otherwise a readable label derived from the agent id, so `deep_research` appears as `Deep Research`.

The settings a user can change for the selected agent follow from what you authored: a preference appears as the default, a constraint narrows the choices to the allowed set, and a pin appears as a fixed value the user cannot change. A capability whose backing resource kind your configuration does not publish is shown but cannot be turned on.

Once an agent is selected:

- When the agent defines an `opening` message, the assistant shows it as the first message of the conversation, before the user has typed anything. Use it to greet the user or explain what the agent can help with.
- When the agent sets `pin_to_conversation`, choosing it locks the conversation to this agent. Every later turn stays with it, and any attempt to switch to a different agent is ignored for the rest of that conversation. Without this flag, a user can switch agents mid-conversation.

For the agent fields behind this, see the `Agent` resource on the [Resource Reference](resource-reference.md#neo-agent-config-resource-reference) page.

## Lock the Model Set Project-Wide

To restrict the models for every agent in the project, set the constraint on the `Project` resource:

```text
# project.yaml
constrains:
  inference.model:
    in:
      - claude-sonnet
      - claude-opus
```

Agents can narrow further, for example constraining to just Sonnet, but they cannot widen. The active set is the intersection of the project restriction and the selected agent restriction.

## Keep Long Sessions in Budget

A long, tool-heavy conversation can grow past what a model accepts in a single turn. The `context_budget` on the `Project` resource keeps each turn within the model window by trimming what is sent to the model. Because it is project policy rather than a preference, neither a user nor a request can turn it off:

```text
# project.yaml
context_budget:
  tool_output_pruning: true
  tool_output_pruning_trigger_tokens: 100000
  turn_truncation: true
```

The two behaviors are independent and can be used together or on their own:

- **Tool-output pruning** clears older tool results once they cross `tool_output_pruning_trigger_tokens`, an absolute token count. Set it to match the models you run: a higher value for large-window models, a lower one for small ones.
- **Turn truncation** is a safety fallback. It drops the oldest whole turns as the input approaches the model context window. For a smaller-window model, set `context_window` on its `Model` resource so that truncation engages before the provider rejects the request.

For the complete `context_budget` field set, with the type and default of each field, see the [Resource Reference](resource-reference.md#neo-agent-config-resource-reference) page.

## Common Pitfalls

- **No shared retrieval master switch**

  There is no single setting that turns all retrieval on or off. Each retrieval family has its own switch, and you set each one independently: `source.documents.enabled` for document retrieval and `source.knowledge_graph.enabled` for knowledge graph retrieval. Turning one off has no effect on the other, so to turn off retrieval entirely you must set every family switch to `false`.
- **A capability exposes every published resource of its kind**

  Turning a capability on does not let you pick which resources it reaches. It exposes every resource of that capability’s backing kind that your configuration publishes. For example, turning on the knowledge graph capability gives the agent access to every `KnowledgeGraph` resource you have published, not a chosen subset. The only way to narrow what an agent can reach is to publish fewer resources of that kind, so keep the ones an agent should not use out of the configuration it runs under.
- **inference.model has no default**

  Most settings fall back to a built-in default when nothing sets them, but `inference.model` does not: there is no default model, so every configuration must choose one. Set it on the `Project` resource, under `prefers` for a default the user can change or under `pins` for a fixed value. If neither is set, `genai lint` fails and the configuration cannot deploy.
- **Pins on the same setting must agree**

  A pin is an absolute lock, so two pins on the same setting cannot both hold unless they name the same value. The `Project` resource and an agent may both pin a setting, but only if they pin it to the same value. If they pin it to different values, the conflict cannot be reconciled and the deploy fails. When you pin a setting in more than one place, make sure every pin uses the same value, or pin it in only one place.

## Next Steps

- For the complete catalog of preference paths, with the type and default of each, see the [Preference Reference](preference-reference.md#neo-agent-config-preference-reference) page.
- For the field-by-field reference of every resource kind, see the [Resource Reference](resource-reference.md#neo-agent-config-resource-reference) page.
- For every `genai` command and flag, see the [CLI Reference](cli-reference.md#neo-agent-config-cli) page.
- For the configuration model and how a request resolves across sources, see the [Overview](overview.md#neo-agent-config-overview) page.
