# The six decisions — what you say about an agent, and what holds if you say nothing

> Every app with an agent in it decides six things: who the agent acts as and for whom; what it may do alone, proposes, and never does; what it costs and who pays; who answers its questions and where; who supervises, teaches and audits; what is kept and what is erased. Each has a default that is the careful one, so an app that says nothing gets an agent that only looks things up, for the person who asked, within fifty cents.

<!-- id: agent-guide-decisions · area: agent · stability: preview · html: https://osysharp.com/reference/agent/guide-decisions/ -->

> **You are here:** [Building with agents](https://osysharp.com/reference/agent/guide/) › [Deciding what to build](https://osysharp.com/reference/agent/guide-deciding/) › The six decisions

## Summary        {#summary}
Read this page once before you write an agent, and again when you review one. Each decision is a question, the
answer you get if you say nothing, and the line you write to say otherwise.

| # | The question | If you say nothing | You say otherwise with |
|---|---|---|---|
| 1 | Who does it act as, and for whom? | its own account, for whoever is signed in | `[Actor(Roles = […])]`, `.For(person)` |
| 2 | What may it do alone? | only what reads; everything else is proposed | `May`, a skill's `DecidedBy` |
| 3 | What may it spend? | fifty cents for one piece of work | `TaskBudget`, `Limits`, `Budget`, `SetBudget` |
| 4 | Who answers its questions? | it asks nobody | `People`, `Consults` |
| 5 | Who is in charge of it? | nobody: it does not run until somebody answers for it | the policies, `AgentSeat` |
| 6 | What is kept, and for how long? | what it said for a month, that it happened for seven | the Privacy kits |

## Description    {#description}

### 1. Who does it act as, and for whom?   {#who}
```osy syntax
[Actor(Roles = [OfficeRole.Vetting])]            // the account it acts as holds exactly these roles
public class Vetter : Agent { … }

await Agents.Of<Vetter>().Do(skill, input);                    // for whoever is signed in
await Agents.Of<Vetter>().For(buyer).Do(skill, input);         // for somebody else — a process step, a batch
```
- The agent is an account of the app's, with the roles its class names and no others.
- Working for a person, it reads what **both** may read and changes what **both** may change. It can never do for
  somebody what that person may not do themselves.
- In a process, where nobody is signed in, it works with its own roles alone, unless the step says `.For(person)`.
- Giving work *for somebody else* while signed in yourself needs the policy `DirectsAgentsForOthers`.

More: [[agent-agents#rights]], [[agent-ask#for]], [[Actor] — a principal that code may run as](https://osysharp.com/reference/security/declared-actor/).

### 2. What may it do alone, what does it propose, what does it never do?   {#alone}
```osy syntax
public override Permits May => new Permits {
  Alone = [Actions.Of(NoteRisk)],                 // by itself
  ProposeEveryTime = [Actions.Of(ApproveSupplier)],   // a person, every time: no standing rule
  Never = [Actions.Of(DeleteSupplier)],           // not offered to the model at all
};
```
- Said nothing, a tool that only reads runs alone, and **every tool that changes, sends or spends is proposed**.
- What a tool does is what the compiler worked out from its body, so nothing is declared safer than it is. See
  [[Action] — what an app offers to be done, by name](https://osysharp.com/reference/function/action/).
- `Permits.ChangesAlone()` is the common middle: the app's own data alone; anything that leaves the app proposed.
- A proposal goes to the person the work is for. A skill's `DecidedBy` sends it to a queue or to one person
  instead, and then the person the work is for cannot approve it.
- "From now on, do this alone" is a [[agent-guide-glossary#standing-rule|standing rule]]. Only whoever
  `WidensAgentAutonomy` admits may give one, and it never covers a tool the agent never runs.

More: [What an agent does alone, what it proposes, what it never does — the gate and proposals (Agents kit)](https://osysharp.com/reference/agent/autonomy/), [Guards and trying again — the app's own checks on an agent's work, and what happens when work fails (Agents kit)](https://osysharp.com/reference/agent/guards/) for the app's own checks. Choosing between the three:
[[agent-guide-choosing#alone-or-propose]].

### 3. What does it cost, and who pays?   {#cost}
```osy syntax
app.Agents = new AgentsSetup { Agents = […], TaskBudget = 0.25m };          // every piece of work, at most
public override AgentLimits Limits => new AgentLimits { PerTask = 0.10m, Daily = 5 };   // this agent
public override decimal? Budget => 0.02m;                                    // this skill
SetProcessBudget("Qualification", 2.00m);                                    // each run of this process
```
- Every piece of work has a hard limit: the skill's `Budget`, else the agent's `Limits.PerTask`, else the app's
  `TaskBudget`. Room is reserved before each model call leaves.
- Work whose money runs out is **stopped**, and keeps what it did.
- A day's limit for an agent, a limit for each run of a process, a limit for an assignment and a limit for anything
  of your own (`.On("customer:acme", 10)`) bind the same calls.
- Nobody reads the meter or sets a budget until the app says who: `ReadsModelUsage`, `ManagesModelSpend`.

More: [What an agent may spend — a hard limit on every piece of work (Agents kit)](https://osysharp.com/reference/agent/budgets/), [Model spend — budgets, the meter and the price book (Llm kit)](https://osysharp.com/reference/agent/llm-spend/), [[agent-processes#cost]].

### 4. Who answers its questions, and where?   {#questions}
```osy syntax
public override AsksPeople People => new AsksPeople { MayChoose = true, About = "A payment term over 30 days." };
public override string Consults => "Careful";            // a stronger model, asked first
```
- An agent asks a person only when its class says it may.
- It asks the person the work is for; its [[agent-guide-glossary#sponsor|sponsor]] when the work is for nobody.
- The work stops where it stands and costs nothing while it waits. It goes on from the same point when the answer
  comes, a minute or a week later.
- With [HumanRequests](https://osysharp.com/reference/agent/kit-human-requests/) in the app, questions and proposals are requests in that person's
  inbox, with a deadline and reminders. Without it, your app shows them wherever it likes.
- Before a person, an agent can consult a more capable model, charged to the same piece of work.

More: [An agent asks a person, and waits — the person rung of the ladder of help (Agents kit)](https://osysharp.com/reference/agent/people/), [Asking for help — an agent that consults a more capable model (Agents kit)](https://osysharp.com/reference/agent/help/), [An agent's proposals and questions in a person's inbox, and an inbox item in an agent's hands (Agents.HumanRequests kit)](https://osysharp.com/reference/agent/requests/).

### 5. Who supervises, who teaches, who audits?   {#in-charge}
```osy syntax
policy UsesAgents       => IsOffice;          // gives agents work, reads the work they asked for
policy SupervisesAgents => IsLead;            // sponsors, pauses, calls work off, decides others' proposals
policy AuditsAgents     => IsRiskOfficer;     // reads everything, with what it said
policy TeachesAgents    => IsRiskOfficer;     // makes an instruction active, retires one, rolls back
new AgentSeat { Agent = "Vetter", Sponsor = lead };      // somebody answers for it
```
- Each of these is nobody's until the app answers it. An agent with no sponsor does not run.
- Supervising brings four things with it — naming a sponsor, pausing, reading every receipt, deciding other people's
  proposals — and each can be handed to somebody else in one line.
- A supervisor reads **that** each step happened. Only an auditor, a teacher, and the people the work was for or
  given by read **what it said**.
- A person corrects a piece of work; an instruction drawn from corrections reaches the agent only after a person
  who teaches has made it active. The agent cannot activate its own.

More: [Who is in charge of an app's agents — every policy in one table, pausing, sponsoring, and trying work again](https://osysharp.com/reference/agent/roles/) has every policy in one table. [Correcting an agent, and what it is told from then on — corrections, instructions, instruction sets and rollback (Agents kit)](https://osysharp.com/reference/agent/teaching/), [The management screens — where a person runs an app's agents (Agents.Management kit)](https://osysharp.com/reference/agent/management/).

### 6. What is kept, and what is erased?   {#kept}
```osy syntax
MarkAgentWorkAbout(outcome.Task, new DataSubject { Emails = [loan.BorrowerEmail] });    // whose data it is
```
- Every piece of work leaves a receipt and a record. The record is chained, so a changed line is found.
- With [Privacy](https://osysharp.com/reference/agent/kit-privacy/) in the app, what the work **said** is kept a month and **that it happened**
  seven months, by default. The tenant can change both.
- A person can ask for their copy, or to be erased. After an erasure the record still checks.
- Work done *for* a signed-in person is found by itself. Work *about* somebody needs the one line above.

More: [The receipt and the record — what every piece of an agent's work leaves (Agents kit)](https://osysharp.com/reference/agent/task-log/), [Privacy for the agent family — agents, the model meter, assignments and work repositories under a person's request](https://osysharp.com/reference/agent/privacy/). When to add each Privacy kit: [[agent-guide-choosing#privacy]].

### What does an agent do when its class says nothing?   {#nothing}
The careful thing, each time. This app decides as little as an app can: one agent with a purpose, a skill and two
tools. The tests show what that gets you.

```osy title="say nothing: it does not run until somebody answers for it, proposes every change, and may spend fifty cents" run app=agent-guide-decisions
app Bureau {
  use Osysharp.Agents;
  use Osysharp.Agents.Testing;
  use Osysharp.Llm;
  use Osysharp.Identity;
  use Osysharp.Observability;
  use Osysharp.Workflow;
  model "model/**/*.osy";
}

using Osysharp.Agents;
using Osysharp.Agents.Testing;
using Osysharp.Identity;
using Osysharp.Llm;
using Osysharp.Workflow;

app.Llm = new LlmSetup {
  Models = [ new LlmModel { Name = "Everyday", Client = new ScriptedModel { Name = "Everyday" }, Model = "scripted-everyday",
                            Price = new LlmPrice { Input = 1, Output = 5 }, MaxOutputTokens = 1000 } ],
  Default = "Everyday",
};
app.Agents = new AgentsSetup { Agents = [new Filer()] };          // no TaskBudget: fifty cents

[Role] enum BureauRole { Authenticator, Translator, Manager, Assistant }
partial entity RoleGrant { security { allow read when IsAuthenticated; } }
policy IsTranslator => RoleGrant.Any(g => g.Member == user && g.Role == BureauRole.Translator);
policy IsManager    => RoleGrant.Any(g => g.Member == user && g.Role == BureauRole.Manager);
policy IsAssistant  => RoleGrant.Any(g => g.Member == user && g.Role == BureauRole.Assistant);

// The two an app cannot leave out: who may give agents work, and who is in charge of them.
policy UsesAgents       => IsTranslator || IsManager;
policy SupervisesAgents => IsManager;

entity Person : Principal {
  security { allow read when IsAuthenticated || IsAuthenticator; allow create when IsAuthenticator; }
}

entity Commission {
  [Required, Unique, MaxLength(40)] string Reference;
  [MaxLength(400)] string Note = "";
  security { allow read, create, update when IsTranslator || IsManager || IsAssistant; }
}

public class Filing { public bool Filed; }

[Action("Look up the house terms for a language", Query)]
public List<string> HouseTerms(string language) { return ["sopimus: agreement"]; }

[Action("Write a note on the commission")]
public string NoteCommission(Commission commission, string note) { commission.Note = note; return "Noted."; }

public class FileCommission : Skill<Commission, Filing> {
  public override string Description => "File one commission.";
  public override List<ActionInfo> Tools => [Actions.Of(HouseTerms), Actions.Of(NoteCommission)];
  public override string Brief(Commission c) => $"Commission {c.Reference}. Its id is {c.Id}.";
}

/// It says who it is and what it can do, and nothing else.
[Actor(Roles = [BureauRole.Assistant])]
public class Filer : Agent {
  public static Person Principal => new Person { Email = "filer@bureau.example", DisplayName = "Filer" };
  public override string Purpose => "You file the commissions of a small translation bureau.";
  public override List<SkillBase> Skills => [new FileCommission()];
}

[TestFixture]
void Office() {
  var ines = new Person { Email = "ines@bureau.example", DisplayName = "Ines Varga" };
  var otto = new Person { Email = "otto@bureau.example", DisplayName = "Otto Reyes" };
  new RoleGrant { Member = ines, Role = BureauRole.Translator };
  new RoleGrant { Member = otto, Role = BureauRole.Manager };
  new Commission { Reference = "C-31" };
}
principal Ines => Person.Single(p => p.Email == "ines@bureau.example");
principal Otto => Person.Single(p => p.Email == "otto@bureau.example");

[Test(Office)]
void Said_nothing_it_is_careful() {
  // Decision 5: nobody answers for it yet, so it does not run.
  runas (Ines) {
    var commission = Commission.Single();
    Assert.Throws<AgentNotSponsored>(() => await Agents.Of<Filer>().Do(new FileCommission(), commission));
  }
  runas (Otto) { SponsorAgent("Filer", Otto); UnitOfWork.Commit(); }

  runas (Ines) {
    var commission = Commission.Single();
    var script = AgentScript.Of(
      Says.Tool(Actions.Of(HouseTerms), "{\"language\":\"Finnish\"}"),
      Says.Tool("One house term applies.", Actions.Of(NoteCommission), "{\"commission\":\"" + commission.Id.ToString() + "\",\"note\":\"sopimus: agreement\"}"),
      Says.HandBack(new Filing { Filed = true }));
    ScriptedAnswer.Stub((model, request) => script.Answer(model, request));

    var outcome = await Agents.Of<Filer>().Do(new FileCommission(), commission);

    // Decision 2: it looked the terms up alone. The note changes data, so it is proposed, to her, and the work waits.
    Assert.True(outcome.Waiting);
    Assert.Equal(["HouseTerms"], Trajectory.Of(outcome.Task));
    Assert.Equal("", Commission.Single().Note);
    Assert.Equal("Write a note on the commission", ProposalsForMe().Single().Label);
    // Decision 3: fifty cents for one piece of work, in millionths of a dollar.
    Assert.Equal(500000, AgentTask.Single().LimitMicros);
  }
}
```

## What to read next   {#read-next}
- [Shape 1 — an assistant for one person](https://osysharp.com/reference/agent/guide-assistant/) — the smallest app, where five of the six are one line each
- [Choosing — I want X, so use Y, not Z, because](https://osysharp.com/reference/agent/guide-choosing/) — decision tables for the choices that come up most
- [What stays under people's control — ten promises, and where each is shown](https://osysharp.com/reference/agent/overview-control/) — the same six, as a person who is not a developer would ask them

## Go deeper   {#see-also}
- [Who is in charge of an app's agents — every policy in one table, pausing, sponsoring, and trying work again](https://osysharp.com/reference/agent/roles/) — every policy, what it admits, and its default
- [What an agent does alone, what it proposes, what it never does — the gate and proposals (Agents kit)](https://osysharp.com/reference/agent/autonomy/) — the gate and proposals
- [What an agent may spend — a hard limit on every piece of work (Agents kit)](https://osysharp.com/reference/agent/budgets/) — limits on every piece of work
- [Privacy for the agent family — agents, the model meter, assignments and work repositories under a person's request](https://osysharp.com/reference/agent/privacy/) — what is held, for how long, and what an erasure leaves
