# Agent Builder

> Turn "make me an agent that…" into a folder in the user's own Drive that the harness runs as a workspace, unattended when it has a trigger. Asks for each consent in the conversation. Never edits an agent from inside one of its scheduled runs.

- Skill: `privasys/agent-builder` (Agent Skill)
- Install (CLI): `npx skillmds@latest add privasys/agent-builder`
- Raw SKILL.md: https://api.skillmd.com/api/skills/privasys/agent-builder/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: Privasys (https://skillmd.com/u/privasys)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/privasys/agent-builder

---


# Agent builder

An agent is not code and not a deployment. It is a folder in the user's own
Drive, under the assistant's app folder:

```
AppData/<assistant folder>/agents/<Agent name>/
  agent.md        who the agent is and its standing instructions
  agent.yaml      what a run does, what starts it, how often it may run
  skills/         skills specific to this agent (optional)
  state/          written by runs, never by you
  runs/           written by runs, never by you
```

The harness mirrors that folder into a workspace of its own, beside the
user's other workspaces, within about fifteen seconds of a change. The
user's chat can open the workspace and talk to the agent; when `agent.yaml`
declares a trigger, the harness also starts runs unattended and each run is
a session in that workspace, where the user reads it like any other.

Use this skill when the user asks for an assistant that does something on
its own ("triage my inbox every morning", "every Friday, list what I
committed to this week", "when mail arrives from the board, draft an
acknowledgement"), or when they ask to change an agent they already have.

## 1. Agree on the agent in the conversation first

Ask, briefly, and only what the template below cannot default:

- **Name.** One plain phrase, it becomes the workspace title: "Inbox triage",
  "Weekly commitments". No slashes, no leading dot, sixty characters at most.
- **What a run does**, in one or two sentences. This becomes `prompt`.
- **What starts it.** Exactly one of: `every: 2h` (a Go duration: `30m`,
  `2h`, `24h`), `at: "0 17 * * FRI"` (a cron schedule, five fields or
  `@daily`, `@hourly`; read in UTC, so convert the time of day they name
  and tell them you did), or `on: mail.changes` (a message arrived in the
  connected mailbox). A definition naming two is refused.
- **What it needs.** The resources its runs will use, by kind, from what
  `list_access` reports: `mail.mailbox` for the mailbox, `storage` for
  Drive. This is not written in the folder; it is what you ask consent
  for in section 3. Do not ask for what the run will not use.
- **How careful.** Defaults are right for almost everyone: `debounce: 2m`
  (a burst of arrivals becomes one run), `min_interval: 10m` (never more
  often than this, whatever arrives, and one run at a time).

Read back the agreed definition in prose before writing anything. Keep it to
what was agreed; do not invent behaviour the user did not ask for.

## 2. Write the folder with the harness's own `write_agent` tool

Call `write_agent` with `name`, `agent_md` and `agent_yaml`. The harness
writes `agents/<name>/agent.md` and `agent.yaml` into the assistant's folder
in the user's Drive (`AppData/<label>/agents/<name>/`) and mirrors the
folder back as a workspace. Do not write these files into this workspace,
and do not look for Drive tools to do it: Drive's own tools here are
read-only, and the harness does the writing. `list_agents` shows what the
user already has; writing an existing name updates that agent.

Write exactly these two files. A skill of the agent's own (`skills/`) and
the `state/` and `runs/` folders are not yours to create: the user adds a
skill in Drive if they want one, the harness makes the other two.

`agent.md`:

```markdown
# <Agent name>

You are <the user's first name>'s <what the agent is for>, running in the
Privasys Harness on their behalf.

## What you do

<The agreed job, in the user's words, as instructions.>

## How you work

- Follow the `<skill name>` skill for the steps and the taxonomy.
- Write only through the tools you were granted; never send mail.
- Write nothing outside this workspace's `state/` and `runs/` folders.
- Never change `agent.md`, `agent.yaml` or `skills/` from a run. If the
  definition should change, say so in the run's summary and stop.
- Finish every run with a short summary: what arrived, what you did, what
  needs the user.
```

`agent.yaml`:

```yaml
prompt: <one or two sentences: what a run does>
trigger:
  on: mail.changes        # or: every: 2h, or: at: "0 17 * * FRI" (one of the three)
debounce: 2m
min_interval: 10m
paused: false
```

If `write_agent` says the user's Drive folder for this assistant is not
connected, go to `list_access`: the `storage` resource is what it needs,
and `request_access` asks the user's device for it.

## 3. Ask for each consent, here, now, in the right order

For every resource kind agreed in section 1, look at `list_access`, then
**verify with the service itself before trusting `approved`**: the list is
what the user's device recorded, and the service is the authority (the
user may have withdrawn the service's folder in Drive since). Make one
harmless call to the service's tool that reads its state (for
`mail.mailbox`, the mail tool `account`); if it answers, the resource is
connected and approved.

There is exactly one way a service gets what it needs from the user:
**`request_access`**, after you asked the user. Their device does the rest
on one screen: it verifies the service, and if the service needs something
first (for `mail.mailbox`, their address and an app password), it asks for
it there and sends it straight to the service. Nothing of that enters this
conversation and you never see it. Never ask for a password yourself, and
never look for a tool of the service that would connect, link or set it up:
there is none you may call. Tell the user, before calling, that their
device will ask them to approve and may ask for the service's details on
that same screen.

So:

- The resource is not `approved`: ask the user, then call `request_access`.
- The list says `approved` (or `withdrawn`) and the service refuses: the
  device's record is stale. Ask the user, then call `request_access` with
  `ask_again: true`. A refusal that says `needs_holder` or
  `credential_needed` means exactly this, whatever else it says: the user
  has to act on their device, and `request_access` is what puts it there.
- The resource is `declined`: respect that unless the user says otherwise,
  and only then ask again with `ask_again: true`.

An agent whose consent is missing will not poll a service that refuses it:
the harness asks the user's device once, the same way, and waits for the
approval; better to settle it now, while they are here.

Do not ask for the assistant's spend consent here; that is settled at
sign-in and is not per agent.

## 4. Tell the user what happens next, precisely

- Within about a minute the folder is mirrored and the agent exists.
- With `every`, the first run starts within a minute and then on the
  interval; with `at`, at the next schedule time (UTC); with
  `on: mail.changes`, at the next arrival.
- The workspace named after the agent appears in the sidebar at its first
  run, with that run as its first session. Sessions are named
  `<Agent name> <date time>`.
- To change the agent, they edit the two files in Drive, or ask you in
  the chat; either way the next run follows the edit. To stop it, set
  `paused: true`. The harness sets that itself, on every agent of theirs,
  if their account cannot pay for a run; it says so in the agent's
  `runs/paused.md`, and they ask you here to unpause.
- To remove it, delete the folder in Drive.

## What an agent is NOT

An agent is two files in the user's Drive. It is **not a program**. Never
write a script, a daemon, a scheduler, a poller or any code for it, never
create files in this workspace for it, and never run anything in the
background yourself: the harness reads `agent.yaml` and runs the agent on
its trigger, in a session of its own, with the same tools you have. If you
find yourself checking for Python, Node or an HTTP API, or writing files
into this workspace, stop: you have left this skill. Go back to section 2
and call `write_agent`.

## Rules you do not bend

- **Definition changes happen in conversation, never inside a scheduled
  run.** A run that thinks its definition is wrong reports that and stops.
- **One file per fact.** `agent.md` is prose for the model, `agent.yaml` is
  data for the harness; do not duplicate the prompt in both.
- **No secrets in the folder.** A mailbox password is typed into the
  connector's own form, never into an agent file and never into this
  conversation.
- **No new capabilities by prose.** An agent cannot grant itself a resource
  by mentioning it in `agent.md`; only the user's consent, given through
  `request_access`, counts.
- **Do not create an agent for something the chat can do on the spot.**
  A one-off question is a question, not an agent.

## Example: the inbox agent

User: "Triage my inbox as mail comes in, drafts only, and give me a
digest."

Agreed: name **Inbox triage**; runs on `mail.changes`; prompt "Triage what
arrived since the last run following the inbox-triage skill; label, draft
only where a reply is owed, and end with a digest."; it needs
`mail.mailbox`; defaults for the rest. Then section 3 for `mail.mailbox`
(`request_access`, with `ask_again: true` only if the service refuses an access the list calls approved), and the four sentences of section 4.

