Overview#

Warning

Project Neo is currently in Technical Preview. Features described in this section may change before general availability.

Agent configuration gives you one place to author and one command to deploy. That command produces a configuration snapshot on the Squirro instance: the exact, versioned configuration the platform uses. Despite the name, a snapshot is not a backup. The platform keeps no restorable copies, so rolling back means redeploying your own files, as described in the Roll Back a Deployment section.

Project Directory#

When using Project Neo, an agent configuration project is the unit of deployment, a directory of files that defines, end to end, one agent configuration: which models are available, which agents the user can pick, what those agents prefer, what they are locked to, and how documents and knowledge graphs connect. It targets an existing Squirro project, the same project you already use for search, dashboards, and content.

You author the directory locally, validate it, and deploy it. Every deploy replaces the project configuration completely: the submitted content is validated as a whole and becomes the new snapshot, only if every check passes.

There is no partial deploy and no in-place edit of a live snapshot. Because of that, a Squirro project has a single deployed configuration at any time: keep all of its agents in one agent configuration project, because a second deploy replaces the whole configuration rather than adding to it.

For example, a minimal project looks like this on disk:

my-agent-configuration-project/
├── project.yaml
├── models/
│   └── claude-opus.yaml
└── agents/
    └── assistant.md

project.yaml is the project manifest. Here is an example of one:

kind: Project
schema: v1
title: My first project

prefers:
  inference.model: claude-opus

models/claude-opus.yaml declares a model. Here is an example of one:

kind: Model
schema: v1
metadata:
  id: claude-opus

provider: anthropic
model_name: claude-opus-4-8
auth:
  type: bearer
  secret: anthropic_token

agents/assistant.md declares an agent. Here is an example of one:

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

You are a helpful assistant. Answer questions clearly and concisely.

Note that anthropic_token is a handle: a name bound to an actual API key securely stored on the cluster, not the key itself. For more information, see the Registering a Handle section.

The filesystem layout is a convenience. Where you place a file does not affect how it is interpreted. Each file declares its own type, and the platform dispatches on that declaration, not on the directory name.

For a complete walkthrough of writing project files and deploying them, see the Quick Start page.

Typed Resources#

Configuration is made up of typed resources. Each resource is one of a fixed set of kinds, and each kind has its own fields. The kinds are grouped below by when you first reach for them.

The kinds a minimal project needs:

  • Project

    The project manifest. Sets project-wide defaults and declares the configuration that every agent inherits. Exactly one per project.

  • Model

    A language model the agents can use, including its provider and the credential handle used to reach it.

  • Agent

    An agent the user can select, or a subagent that another agent can call. Carries its instructions and its configuration.

The kinds you add as a project grows:

  • TraitDimension

    A named dimension of reusable prompt fragments, such as a writing style, that agents activate through preferences.

  • KnowledgeGraph

    A knowledge graph endpoint the agents can query.

  • MCP

    An external Model Context Protocol server that exposes additional tools.

  • DocumentSourceSettings

    Document retrieval configuration for the project.

  • CodeInterpreter

    Code execution configuration for the project.

Every file begins with an envelope that declares its kind and schema and, for most kinds, an id in a metadata block, for example:

kind: Model
schema: v1
metadata:
  id: claude-opus
provider: anthropic
model_name: claude-opus-4-8

This is the envelope of the example models/claude-opus.yaml file shown in full above, with the auth block omitted here to focus on the kind/schema/metadata shape common to every resource.

The schema field is the version of the format for a resource kind. It determines which fields are valid for that kind and how the file is checked. Each kind is versioned on its own, so different kinds could sit at different versions over time, although every kind uses v1 today. You can omit the field and it defaults to v1, but writing it explicitly records the format each file targets, and every example here does so.

The platform validates a file from the combination of its kind and its schema, so a file whose kind and schema pair is not recognized, such as a schema version that does not exist for that kind, is rejected at deploy.

Because Project Neo is in Technical Preview, the format for a kind can change between releases, and previously authored files are not migrated for you. Keep your agent configuration project in version control and run genai lint after an upgrade to catch any files that a new schema version requires you to update.

Each resource is identified by the combination of its kind and its id. Within a single kind, every id must be unique: two resources of the same kind with the same id cause the deploy to fail. The same id may be reused across different kinds, so a Model and an MCP server can both use id: claude-opus without conflict.

Note

kind values are case-sensitive and must match the exact spelling shown above.

The Preference Keyspace#

How the agents behave in Chat is shaped through settings addressed by dotted paths, such as inference.model, trait.style, or source.documents.enabled. The preference keyspace is the full, flat set of those paths: the fixed vocabulary of settings you can set a value for, each with its own type and default. It is flat because a path is a single key, not a nested structure, so inference.model is one setting rather than a model field inside an inference object. For the complete catalog of every path, its type, and its default, see the Preference Reference page. The project, every agent, every user, and every individual request all set values in the same form:

prefers:
  inference.model: claude-opus
  trait.style: concise
  capability.code_interpreter.enabled: true

This prefers mapping is not a complete file on its own. It is a section that a project manifest, an agent, or a preferences payload from a user or a request can include, in the same shape as the prefers block in project.yaml shown earlier.

inference.model: claude-opus points at the Model resource with id: claude-opus declared earlier: a preference value references a resource by the same id you gave it.

Each of them can set that value through three primitives, and they compose:

  • Preferences (prefers) set a soft default.

  • Constraints (constrains) restrict which values are allowed.

  • Pins (pins) lock a value so nothing can override it.

For the full definitions, worked examples, and the decision rule for choosing between them, see the Authoring Agents page.

How a Request Resolves#

A request is a single message a user sends to an agent in Chat. Each message is resolved on its own, and each setting within it is resolved independently. For a given setting, the runtime walks four sources in priority order:

  1. The request itself, that is, any setting attached to this one message.

  2. The user preferences.

  3. The selected agent preferences.

  4. The project preferences.

The first allowed value wins. Constraints and pins from the project and the selected agent determine which values are allowed. A value that falls outside what is allowed does not fail the request. Instead, resolution falls through to the next source, and the decision is recorded so you can see what happened.

For example, in the project above, if project.yaml prefers inference.model: claude-opus and neither the user, the agent, nor the request sets that value, every request resolves to claude-opus.

This leniency at runtime is paired with strictness at deploy time. Contradictory pins, unsatisfiable constraints, references to resources that do not exist, and credential handles that cannot be resolved all cause the deploy to be rejected, and the previous snapshot stays in place. To resolve a rejected deploy caused by an unbound handle, register the credential as described in the Registering a Handle section.

Where Checks Run#

Configuration is checked in two places. The genai command line tool runs the offline checks locally, over your files alone, with no network and no credentials: genai lint runs them on their own, and genai deploy runs them first and stops before contacting the cluster if any fail. These catch structural problems early.

The instance is authoritative. Because the command line tool is a thin client that never writes to the cluster directly, the server re-runs every publish check over the submitted configuration on deploy, including the cluster-bound checks that cannot run offline, such as credential handle resolvability and publish policy. Only if every check passes does the configuration become the new snapshot. Otherwise the deploy is rejected and the previous snapshot stays in place.

To run the full instance-level validation without replacing the live configuration, deploy with --dry-run. For the per-command and per-route detail, see the CLI Reference and API Reference pages.

Preferences Versus Policy#

Not everything is a preference. Some settings a request should never influence, such as a model context window or a safety control. When you reach for a new setting, ask whether a user or a request should be able to contribute a value:

  • If yes, it is a preference and lives in the preference keyspace.

  • If no, it is a field on a resource, read directly from what you deployed and never negotiated. A field that governs behavior rather than identity is called policy. Operational and safety controls are normally policy, so a request cannot weaken them.

Both are written in the same project files. The difference is how you write the setting. A preference is a line in a prefers block, addressed by a keyspace path, so the project sets a default while an agent, a user, or a request can set its own value, as long as constraints and pins allow it. A policy is a plain field on a resource, not inside a prefers block, that the runtime reads straight from what you deployed and that nothing at request time can change. Both can sit in the same project.yaml:

kind: Project
schema: v1

prefers:
  inference.model: claude-opus   # preference: negotiable at request time

context_budget:                    # policy: fixed, read straight from the snapshot
  turn_truncation_trigger_fraction: 0.9
  keep_recent_turns: 4

So inference.model is negotiable because it is safe to let a user decide, while context_budget is fixed because letting a request weaken it would defeat a safety control. When you reach for a new setting, that question, whether a request should be able to change it, decides which channel it belongs in.

Whether a setting is a preference or a policy is fixed by the platform, not chosen per file: a keyspace path such as inference.model is always a preference, and a resource field such as context_budget is always policy. To make a preference non-negotiable, do not turn it into policy. Pin it instead, as described under the three primitives above. A pin locks the value of a setting that stays a preference in form, whereas policy is a setting that was never in the keyspace for a request to contribute to.

The two channels have two catalogs. For every preference path, its type, and its default, see the Preference Reference page. For the policy fields, which are documented per resource kind, see the Resource Reference page.

Next Steps#

With the concepts in place, gather what you need on the Prerequisites page, then follow the Quick Start page to learn how to author, validate, and deploy your first configuration.