# Design an effective agent

> Turn Raw into your own agent. Balance the system prompt, tools, skills and output limits against the context window, and choose what to enforce with rules instead of instructions.

Raw gives you a working agent loop. What makes it your agent is what you put in it: the model, the system prompt, the tools, the skills and the rules. This page explains the trade-offs, so you can make those choices on purpose.

The short version: every word you add to an agent is paid for in context on every step. A prompt that is too long leaves the model less room to work. A prompt that is too short makes the model guess. Aim for the smallest setup that still tells the model everything it cannot work out on its own.

## What one request contains

Before every model call, Raw sends:

1. the system prompt,
2. the definitions of the selected tools, including MCP tools,
3. the conversation so far: your messages, the model’s answers, and every tool result that has not been cleared or compacted.

Parts 1 and 2 are a fixed cost. They are sent again on every step of every turn, and a turn often has many steps, one per tool call. Part 3 grows as the agent works.

Measured with an OpenAI tokenizer, Raw’s own pieces cost about this much. Other tokenizers, including those of most local models, give somewhat different counts.

| Piece                                | Approximate tokens |
| ------------------------------------ | ------------------ |
| Raw’s default system prompt          | 41                 |
| The starter agent’s eight tools      | 1,300              |
| All fourteen built-in tools          | 3,500              |
| `ask_user` alone                     | 600                |
| `process` alone                      | 480                |
| One bundled setup skill, once loaded | 1,300 to 2,200     |

Open the **Details** tab of the dashboard side panel, or read the end of a one-shot run in the terminal, to see the estimated size of the current context.

### A worked budget

Take a local model with a 32,768-token window and no output cap configured. Raw reserves an eighth of the window for the answer (4,096 tokens) and keeps a 5 % safety margin, which leaves an input budget of about 27,000 tokens. By default, old tool results start to be cleared at 60 % of that budget (about 16,200 tokens), and compaction starts at 80 % (about 21,600 tokens).

With the starter tools and the default prompt, the fixed cost is about 1,300 tokens, or 5 % of the budget. With all fourteen tools and a 4,000-token system prompt it is about 7,500 tokens, or more than a quarter of the budget, before the task has started. Every step after that has a quarter less room, and compaction runs sooner.

With a 200,000-token hosted model, the same 7,500 tokens are under 4 % of the window. The right size of an agent depends on the model you run it on.

## The system prompt

Raw’s default prompt is two sentences. That is a starting point for a general coding agent, not a target. A short prompt is not automatically better.

**Too long** costs context on every step, as shown above. Long prompts also tend to repeat what the tool descriptions already say, and models follow a few clear rules better than many competing ones.

**Too short** makes the model guess. It does not know your conventions, your definition of done, which commands are safe, or what a good answer looks like. Smaller models suffer most, because they are worse at inferring what you meant. A missing instruction then costs more than the tokens it would have used: a wrong edit, a retry, or a long detour.

Put in the system prompt what the agent needs on every turn:

- its role and scope, including what it should not do,
- how to know the task is done, for example “run `npm test` and report the result”,
- the output format you expect,
- the conventions that apply to almost every task.

Leave out of the system prompt:

- procedures used only sometimes. Make them [skills](https://raw.tlelabs.com/docs/extend/skills/).
- reference material such as API details, style guides or schemas. Keep them in files the agent reads when it needs them, or in a skill’s `references/` folder.
- restatements of tool descriptions. If a tool needs a better description, [fork the tool](https://raw.tlelabs.com/docs/extend/tools/#fork-a-shipped-tool) and change it there.
- safety rules you need enforced. Use [rules and hooks](#enforce-with-rules-not-with-words).

Be concrete. “Run `pnpm lint` before you finish” works better than “make sure the code is clean”. One short example of the expected output often does more than a paragraph that describes it.

As a rough guide, keep the fixed cost (prompt plus tool definitions) under about 10 to 15 % of the input budget on small local models. On large hosted models a prompt of a few thousand tokens is fine. Hosted providers also cache the unchanged start of each request, and Raw keeps the prompt and tool definitions in a stable order so the cache can apply. Caching lowers cost and latency. It does not give the context back.

Set the prompt with `system_prompt`, or keep it in a Markdown file with `system_prompt_file` so you can edit it like any other document. See [Models and agents](https://raw.tlelabs.com/docs/guides/models-and-agents/).

## Tools

Every selected tool is sent on every step, whether the model uses it or not.

- **Select only what the agent needs.** A read-only reviewer does not need `write_file`, `edit_file` or `bash`. An agent that never asks questions does not need `ask_user`, which is one of the larger definitions.
- **Prefer a few general tools.** One `bash` tool with rules usually costs less context than many narrow tools, and models are trained on that shape. Add a dedicated tool when you need a safer, typed action, for example one that calls an internal API with fixed arguments.
- **Fewer tools also mean fewer wrong choices.** Smaller models pick the wrong tool more often when several look alike.
- **Tune descriptions for your model.** The built-in descriptions include an example call, because models follow examples well. If your model keeps misusing a tool, fork it and adjust the description rather than adding a rule to the system prompt.
- **MCP servers can be large.** Select only the MCP tools you use, not every tool a server offers.

### Keep tool parameters simple

The more complex a tool’s arguments, the more often a weaker model calls it wrong: a missing field, a value of the wrong type, an object nested at the wrong level. Each failed call costs a step and its error result costs context. Raw’s own built-in tools were reshaped for this reason: `read_file` reads one file, `bash` runs one command and `process` takes flat arguments, because models call those shapes reliably and often got batch shapes wrong.

When you write or fork a tool:

- **One action per call.** Prefer `{"path": "a.txt"}` called twice over `{"files": [{"path": "a.txt"}, {"path": "b.txt"}]}`. If you need several actions, use one `action` field with a short list of values instead of a nested object for each.
- **Flat, primitive fields.** Strings, numbers and booleans at the top level. Avoid nested objects, arrays of objects, and fields that accept several types.
- **Few required fields, with sensible defaults.** Every required field is one more thing the model must get right. Make the rest optional and document the default.
- **Familiar names.** Use the names models already know, such as `path`, `command`, `query`, `content` or `limit`, rather than inventing new ones.
- **Small enums.** A few clearly named values are easier than many similar ones.
- **One example in the description.** Show a complete, valid call, as the built-in descriptions do.
- **Errors the model can fix.** When validation fails, return a short message that names the field and the expected value, so the next call can succeed.

Raw already accepts common variants for its built-in tools, for example `file_path` for `path`, and reports cut-off arguments back to the model as an invalid call to retry. For your own tools, the simplest schema is the best protection.

## Skills

A skill costs almost nothing until it is used. The model sees only the skill names and descriptions, and only after it calls `list_skills`. The body enters the context when the model calls `load_skill`, and it stays there: clearing old tool results never removes a loaded skill.

- **Write the description for the decision.** The model decides from the description alone whether to load a skill. Say when to use it: “Review a pull request for correctness. Use when asked for a review.”
- **Keep one procedure per skill.** A focused 1,500-token skill is cheaper than a 10,000-token handbook loaded for one section.
- **Move long reference material out of the body** into `references/` files the agent reads only when a step needs them.
- **Use a skill instead of the system prompt** for any procedure that is not needed on most turns.

An agent that selects skills must also select `builtin/list_skills` and `builtin/load_skill`. See [Skills](https://raw.tlelabs.com/docs/extend/skills/) and [Skill authoring](https://raw.tlelabs.com/docs/extend/skill-authoring/).

## Tool output

A single tool result can be larger than everything else in the request. By default, Raw sends up to 64 KiB of each result to the model. That is roughly 16,000 tokens of English text or code, more than half the input budget of a 32k model. Longer output is cut, and the full copy is saved to a file the agent can read in parts.

On a small context window, lower `max_output_bytes` on the agent, for example to 8,192 or 16,384 bytes. The model then reads long output in pages, with `read_file` offsets or the `process` output cursor, instead of filling the context in one step. On a large window, the default is usually fine.

Skill bodies, the skill catalog and `list_vars` and `read_var` results are not limited by `max_output_bytes`.

## Context and compaction

- **Declare the context window.** Set `context_window_tokens` on the model. Without it, Raw cannot know when the context is full, and automatic clearing and compaction stay off.
- **Keep the defaults first.** Clearing old tool results at 60 % and compacting at 80 % of the input budget works for most agents. Change `compact.trigger_tokens` or `compact.clear_tokens` only when you see a reason in real sessions.
- **Tell the summary what matters.** `compact.instructions` adds your own guidance to the summary, for example “keep every file path the user mentioned and the exact failing test names”.
- **Watch for thrashing.** If an agent compacts again and again within one task, its fixed cost or its tool output is too large for the window. Trim tools, lower `max_output_bytes`, or use a model with a larger window.

See [Context and compaction](https://raw.tlelabs.com/docs/guides/context-and-compaction/).

## Enforce with rules, not with words

A sentence in the system prompt is advice. The model can ignore it, especially a small model late in a long context. When something must not happen, enforce it:

- **Tool rules** run before every call and decide `allow`, `ask` or `deny` from the tool and its arguments. For example, a rule can deny `bash` commands whose text matches `git push` and ask before commands that match `deploy`. A text pattern matches the command text, not its effect, so keep rules as guardrails.
- **Hooks** run your own scripts on session, prompt and tool events. They can log every call, or deny a prompt or a tool call with a reason.

This also keeps the prompt short: a rule costs no context at all. See [Permissions](https://raw.tlelabs.com/docs/guides/permissions/) and [Hooks](https://raw.tlelabs.com/docs/extend/hooks/).

> **Caution:**
>
> Rules and hooks control what Raw runs. They are not a sandbox: an allowed command runs with your account’s full permissions.

## Choose the model before you grow the prompt

When an agent keeps failing, the model is often the limit, not the wording. Before you add more instructions, run the same task on a larger model. If the larger model succeeds with the same setup, decide whether the task needs that model or whether a clearer, more concrete prompt helps the smaller one. A longer prompt rarely makes up for a model that is too small for the task.

Different agents can use different models. A cheap local model can handle routine tasks while a hosted model takes the hard ones, each with its own tools and prompt.

## Iterate with real tasks

1. Start from the starter agent or a copy of it.
2. Run five to ten real tasks of the kind the agent will see.
3. Read the sessions in the dashboard. Note where the model guessed wrong, chose the wrong tool, or ran out of room.
4. Fix one thing at a time: an instruction for a wrong guess, a tool description for a wrong call, a rule for an unsafe action, a smaller output limit or fewer tools for a full context.
5. Run the same tasks again. Changes to an agent apply from the next turn, so you can keep testing in the same session.

When the agent works, [package it](https://raw.tlelabs.com/docs/extend/packages/) so your team can install the same setup.

## Checklist

- The model declares `context_window_tokens`.
- The agent selects only the tools it uses.
- The system prompt states the role, the scope, the definition of done and the output format, and nothing that a tool description, a skill or a rule already covers.
- Occasional procedures are skills with descriptions that say when to use them.
- `max_output_bytes` fits the context window.
- Anything that must never happen is a rule or a hook, not a sentence.
- You tested with real tasks and read the sessions.
