# An agent

> Every option defineAgent takes, what each one controls, and where an agent's files go.

An agent is one `agent.ts` that calls `defineAgent`, listed in
`chloe.config.ts`. That file is the whole list of what the agent is: a job,
tool or channel exists only because it names it.

```ts
// The one agent this repo ships, and the one its docs quote: a small shop's
// back office, with a job at each level of autonomy. Orders that are late (no
// model at all), the inbox sorted (one model step), buying stock (code decides,
// a model writes the line), a customer's problem looked into (one of each, in
// one job), a customer who went quiet (an agent step), a refund big enough that a
// person decides, one job that is a prompt from end to end, and a customer's
// message answered with their orders at hand.
//
// `services/` stands in for the systems a shop already has. Point those at the real
// thing and nothing in `jobs/` changes.
//
// Copy this folder, rename it, and put your own name in chloe.config.ts.
import { defineAgent, prompt } from "@chloejs/core";

import api from "./channels/api.ts";
import telegram from "./channels/telegram.ts";
import web from "./channels/web.ts";
import whatsapp from "./channels/whatsapp.ts";
import bigRefunds from "./jobs/big-refunds.ts";
import orderIssues from "./jobs/order-issues.ts";
import howItWent from "./jobs/how-it-went.ts";
import restock from "./jobs/restock.ts";
import sortMessages from "./jobs/sort-messages.ts";
import stuckOrders from "./jobs/stuck-orders.ts";
import whyTheyLeft from "./jobs/why-they-left.ts";
import { orderStatus } from "./tools/orderStatus.ts";

export default defineAgent({
  id: "shop",
  label: "Shop",
  // Any model the gateway or the CLI can reach. A job can name a different one
  // for itself, which is the point of choosing here rather than in the runtime.
  model: "anthropic/claude-sonnet-5",
  description: "Watches the orders, the inbox, the shelves and the customers who stopped buying.",
  instructions: prompt("instructions.md"),
  tools: { orderStatus },
  // A channel's job is named on its channel, not here: answer-whatsapp-customer
  // is in channels/whatsapp.ts.
  jobs: [stuckOrders, sortMessages, restock, orderIssues, whyTheyLeft, bigRefunds, howItWent],
  channels: [telegram, whatsapp, api, web],
});
```

## Options

| Option | Default | What it controls |
|---|---|---|
| `id` | required | What its runs and memory are filed under. Do not change it once it has run. |
| `description` | required | One line, shown wherever agents are listed. |
| `instructions` | required | What it is told on every turn: `prompt("instructions.md")` for a file in its folder, or the words themselves. |
| `label` | the `id` | What the dashboard calls it, and the name its emails are sent under. Free to change. |
| `model` | `model.defaultModel` in settings | The model it asks, like `"anthropic/claude-sonnet-5"`. A job or a step can name its own. See [Models](https://chloejs.org/docs/models). |
| `tools` | none | What a model may call, keyed by the name it sees. See [Tools](https://chloejs.org/docs/tools). |
| `jobs` | none | Its jobs: each one imported, or `markdownJob("jobs/<id>.md")` for a prompt. See [A job is a workflow](https://chloejs.org/docs/jobs). |
| `channels` | none | Where people reach it. See [Channels](https://chloejs.org/docs/channels). |
| `connections` | none | MCP servers only this agent reaches. See [Connections](https://chloejs.org/docs/connections). |
| `features` | memory on, the rest off | Built-in tools to switch on. Below. |
| `memory` | its own folder in `data/memory` | Where it keeps notes between runs. Below. |
| `folder` | the folder `agent.ts` is in | Where its skills, scripts, prompts and evals are. |
| `stopWhen` | 40 steps | When a turn has to stop, as the AI SDK's `stopWhen`, like `isStepCount(20)`. |
| `toolApproval` | every call allowed | Asked before each tool call in a turn, as the AI SDK's `toolApproval`. A call that needs a person is refused, because a turn does not wait. |

A turn is one answer to a message, or one run of a job that is a prompt. A
job's code sets its own limits on each step: see
[Step, model, agent](https://chloejs.org/docs/primitives).

## features

Switched on in the definition, with nothing to import:
`features: { memoryPerUser: true, runScripts: true }`.

| Feature | Default | What it adds |
|---|---|---|
| `memory` | on | `memoryListFiles`, `memoryReadFile`, `memorySearchFiles`, `memoryWriteFile` and `memoryEditFile`, inside its memory folder and nowhere else. |
| `memoryPerUser` | off | `memoryWriteUserNotes`: a note per person it talks to, `users/<channel>-<id>.md` in its memory, shown at the top of that person's turns. Whose note it is comes from who sent the message, never from the model. |
| `selfImprovement` | off | `selfListFiles`, `selfReadFile` and `selfWriteFile`, to change the plain text in its own folder: instructions, skills, markdown jobs. `{ files: ["md"] }` narrows it, `{ except: ["PERMISSIONS.md"] }` keeps a file read only. Never code, evals, memory or a new job, and a job it changes must still load and run at most once an hour. Every write is a commit you can undo from the dashboard. |
| `runScripts` | off | `scriptRun`, to run a file in its own `scripts/` folder. The agent is refused as it loads if that folder is empty. |

## memory

Unsaid, an agent's memory is `data/memory/<id>/`, and every run that changes it
is one git commit, under the agent's id. Name a folder only when the agent
shares one with a person:

| Option | Default | What it controls |
|---|---|---|
| `folder` | `data/memory/<id>` | An absolute path. |
| `label` | `"Memory"` | What the dashboard calls it. |
| `commit` | `"each run"`, or `false` for a folder you name | `"each run"`: what a run changed is committed when it ends. `true`: every write is its own commit. `false`: never. |

The memory tools, the dashboard, a job's `work.memory` and a script's
`MEMORY_FOLDER` all read this one setting.

## Its folder

```
agent.ts          the definition
instructions.md   what instructions points at
jobs/             its jobs, code or markdown
tools/            its own tools
channels/         one file per channel
services/         plain functions its jobs and tools call
skills/<name>.md  read by looking: see A prompt with tools
scripts/          what scriptRun may run
evals/            cases that score its prompts
```

Only `skills/` is read by looking. Everything else exists because `agent.ts`
imports it, and a job file that `agent.ts` does not name fails `npm run test`.
An edit to any of it is live within a second, with no restart.

## Running it from a script

`agent.run({ job, input })` runs one of its jobs in this process and waits for
it, and `agent.ask({ prompt })` asks it one thing. Both are written to the run
history. A file with no `chloe.config.ts` above it is a project of its own:
[One file](https://chloejs.org/examples/one-file) is a whole agent run with `node`.
