Agents
Introduction
Section titled “Introduction”An agent is a definition: a prompt, a model profile, and the tools, skills and knowledge it may use. Definitions are data, so adding or editing an agent never needs a deploy. The demo API ships four of them as YAML files.
Defining an agent
Section titled “Defining an agent”Drop a file in .pilotoo/agents/. The file name is the id.
id: researchername: Researcherdescription: "Use to find current, verifiable information on the web. Returns findings with their sources."status: activeruntime: systemPrompt: You are the Researcher. Search before you answer, and cite every source. profileId: default tools: [web_search] builtinTools: [] skills: [] knowledge: []presentation: {}Restart is not needed for an edit to a system agent: the next run uses it. The profileId names a model profile; tools names tools you registered.
Choosing tools
Section titled “Choosing tools”runtime.tools decides which registered tools the agent gets:
tools: null # every registered tool except opt-in onestools: [web_search] # exactly these, opt-in tools includedtools: [] # no registered toolruntime.builtinTools is a separate, closed set: an agent gets exactly the built-ins it lists, chosen from ls, read_file, write_file, edit_file, delete, glob, grep, execute, task.
An orchestrator that delegates to the other demo agents lists task:
runtime: builtinTools: [task] subagents: [researcher, writer, analyst]See Subagents.
Picking the default agent
Section titled “Picking the default agent”A catalog read and a run that names no agent use one rule:
- the agent the
AGENT_DEFAULT_IDenvironment variable names, when it is active (it may be a system agent). When the variable is unset, the built-in seed agent is used; - else the first active agent by name among the tenant’s own;
- else the first among the system agents.
If the configured id matches no active agent, the rule falls through to the next step. A tenant with no active agent has no default: the catalog omits defaultAgentId, so a client must handle its absence.
System agents and templates
Section titled “System agents and templates”Both are YAML files under the configuration folder, with different lifetimes.
| System agents | Templates | |
|---|---|---|
| Location | PILOTOO_CONFIG_DIR/agents/*.yaml (default .pilotoo/agents/) |
PILOTOO_CONFIG_DIR/templates/*.yaml (default .pilotoo/templates/; AGENT_TEMPLATES_DIR moves it alone) |
| Seen by | Every tenant, always | Copied into a tenant on its first access, once |
| Edits | An edit of the file reaches every tenant on its next run. Tenants cannot edit one. | A copy never changes when the template does. A deleted agent is not copied again. |
A missing folder means none, and an invalid file stops the boot. A template whose id a system agent holds also stops the boot. Templates name profile default, never a model, so a host with its own profile source must provide that profile.
To customize a system agent, a manager duplicates it into a new id of the tenant and edits the copy. Creating, updating, importing or duplicating onto a system agent’s id is a 409 with code system-agent.
Storing agents in your own database
Section titled “Storing agents in your own database”By default a tenant’s own agents live in PostgreSQL. To keep them elsewhere, implement one read port:
import type { AgentDefinitionSource } from '@pilotoo/agent-runtime';
const definitions: AgentDefinitionSource = { getDefinition: (identity, id) => db.agents.find(identity.tenant, id), listDefinitions: (identity) => db.agents.all(identity.tenant),};Pass it as agentDefinitionSource. A host without a database can use createDirectoryAgentDefinitionSource(dir), which reads one <id>.yaml per agent for every caller and versions it by modification time.
The kit guarantees:
- Definitions are read by the caller’s tenant, so an id another tenant holds is an unknown agent, in the catalog and in a run.
- What the source returns is validated against
agentDefinitionSchema. A draft or malformed definition never serves a run. - A graph is cached per tenant and id, and rebuilt only when the definition’s
updatedAt, or the profile’s id orupdatedAt, changes.
Letting people edit agents
Section titled “Letting people edit agents”Writing is a separate, optional port. Without it there is no editor, and every /agent-admin route except capabilities answers 501.
import type { AgentDefinitionStore } from '@pilotoo/agent-runtime';
const store: AgentDefinitionStore = { create: (identity, definition) => db.agents.insert(identity.tenant, definition), update: (identity, definition) => db.agents.replace(identity.tenant, definition), delete: (identity, id) => db.agents.remove(identity.tenant, id),};Pass it as agentDefinitionStore. Managing is authorized against the roles in AGENT_MANAGER_ROLES (comma-separated, empty by default, so nobody manages). The roles are the vocabulary of your authentication.
The store owns the refusals that must be atomic with the write: AgentAlreadyExistsError, AgentNotFoundError and LastActiveAgentError (deleting or drafting a tenant’s last active agent). update replaces the whole definition, and the version (updatedAt) is the store’s.
The demo web app’s Settings page, built from SettingsLayout in @pilotoo/ui/settings, is the reference editor, and createAgentAdmin in @pilotoo/chat-core is the typed client.
Options
Section titled “Options”Definition fields
Section titled “Definition fields”| Field | Meaning |
|---|---|
id, name, description |
description also tells an orchestrator when to use this agent as a subagent. |
status |
active, or draft. A draft never serves a run. |
runtime.profileId |
The model profile the agent runs on. |
runtime.tools |
null for every registered tool except opt-in ones; a list for exactly those names. |
runtime.builtinTools |
Required. A closed set of built-in tools. |
runtime.skills |
null enables every available skill; a list enables exactly those names. See Skills. |
runtime.knowledge |
Opaque ids only your knowledge source interprets. |
runtime.subagents |
Ids of other agents this one delegates to. Optional. |
presentation |
Free-form data for your UI. The runtime never reads it. |
The schema is agentDefinitionSchema in packages/agent-runtime/src/agent-definition.ts.
Admin endpoints
Section titled “Admin endpoints”All under /agent-admin, for managers:
| Route | Answer |
|---|---|
GET capabilities |
{ canManageAgents } for any identified caller; false without a store. |
GET agents, GET agents/:id |
Managed agents, drafts included. Malformed rows are listed in invalid. |
POST agents |
201. |
PUT agents/:id |
200, full replace; the URL’s id wins. |
DELETE agents/:id |
204. |
GET agents/:id/export |
text/yaml. |
POST agents/import |
{ yaml }; creates the agent in the caller’s tenant. |
POST agents/:id/duplicate |
{ id, name? }; 201, a copy created in the caller’s tenant. |
GET profiles, GET options |
Profile summaries; and the tools, skills and agents an agent can select. |
| Status | Meaning |
|---|---|
403 |
Not a manager. |
400 |
Validation, with issues of { path, message }. |
404 |
Unknown id. |
409 |
With code: agent-exists, last-active-agent, system-agent or referenced-agent. |
422 |
A stored agent that fails its schema (delete still removes it). |
501 |
No store. |
Next steps
Section titled “Next steps”- Give agents tools and a model.
- Delegate work with subagents.
- Decide who may manage agents in Authentication.