# Configuration reference

> Every key in install.yaml, workspace.yaml, agent front matter and skills.yaml, with its type, default and an example, plus environment variables.

Wheems is configured with YAML and Markdown files in your install folder. This page lists every key Wheems 0.0.3 accepts, taken from its schemas, with its type, default and an example. Keys that are accepted but not used yet are marked **Planned**.

## Rules for every file

- **Keys are `snake_case`.**
- **Names** of workspaces, agents, accounts, connections, channels, skills and workflows are lowercase letters, digits and dashes, starting with a letter or digit, at most 64 characters: `acme`, `chief-of-staff`, `weekly-report`.
- **Unknown keys are errors**, so a typo never passes silently.
- **Links between files are checked**: a workspace may only use the install's accounts and connections, an agent only its workspace's accounts and skills, and pinned skill versions must exist in the library.

Check everything, with line numbers:

```bash title="Terminal"
wheems validate                                   # the whole install
wheems validate workspaces/acme/workspace.yaml    # one file
```

```text title="Output"
Valid
```

A problem is reported with its file and line:

```text title="Output"
workspaces/acme/workspace.yaml:3: error Unrecognized key: "chanels"
1 error
```

The service refuses to start while there are errors. Restart it after any change: `wheems service restart`.

### Completion in your editor

Every format has a JSON Schema, shipped in the package's `schemas/` folder: `install.schema.json`, `workspace.schema.json`, `agent.schema.json`, `skills.schema.json` and `workflow.schema.json`. Point an editor with the YAML language server at one for completion and hover help:

```yaml title="~/wheems/workspaces/acme/workspace.yaml"
# yaml-language-server: $schema=/opt/homebrew/lib/node_modules/wheems/schemas/workspace.schema.json
name: Acme
```

`npm root -g` prints where global packages live, if yours differs.

## On disk

```text
~/wheems/                       your install: a git folder
├── install.yaml                accounts, connections, machines, knowledge settings
├── about-you.md                every agent in every workspace reads it
├── library/skills/             every version of every skill
├── workspaces/<id>/
│   ├── workspace.yaml
│   ├── agents/<name>.md
│   ├── skills.yaml
│   ├── knowledge/
│   ├── CLAUDE.md, AGENTS.md    written at each launch; ignored by git
│   └── workflows/<name>.yaml   planned
└── .wheems/                    running state, never committed
    ├── conversations.json      which thread is which session
    ├── wheems.sock             the control socket
    ├── slack-app-manifest.yaml
    ├── logs/service.log
    ├── bin/wheems              the command agents run
    ├── index/                  search indexes
    ├── filing/, tidy/          the filer's working copies
    ├── review/                 skill proposals and about-you suggestions
    └── quarantine/             notes that looked like they held a credential
~/.config/wheems/secrets.json   tokens, readable only by you
```

## install.yaml

What every workspace shares. One per install. `wheems setup` creates it.

```yaml title="~/wheems/install.yaml"
herdr:
  version: 0.1.20

machines:
  this-mac:
    local: true

accounts:
  claude-subscription: { driver: claude }
  chatgpt-subscription: { driver: chatgpt }

connections:
  slack:
    driver: slack
    secret: slack
    allowed_users: [U012ABCDEF]

knowledge:
  embeddings:
    driver: ollama
    model: nomic-embed-text
```

### herdr

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| `herdr.version` | version string, such as `0.1.20` | Wheems's own minimum, 0.1.20 | The minimum Herdr core version this install runs on. It can raise Wheems's minimum, never lower it; doctor warns if it's lower. |
| `herdr.binary` | path | `hc` on `PATH` | Where `hc` is, when it isn't on `PATH`. |

### machines

A map of machine names to machines. Today only the local one is used.

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| `machines.<name>.local` | boolean | | `true` for the machine the install lives on. At most one. |
| `machines.<name>.herdr` | name | | **Planned · milestone 10.** The machine's name in `hc machine ls`. A machine has either `local: true` or `herdr`. |
| `machines.<name>.always_on` | boolean | `false` | **Planned · milestone 10.** Agents run on always-on machines by default. |
| `machines.<name>.reach` | `inbound` or `outbound` | `inbound` | **Planned · milestone 10.** `outbound`: it connects out to collect its work, like a laptop. |

### accounts

A map of account names to accounts: what pays for models. See [Engines and accounts](https://wheems.dev/docs/engines/#accounts).

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| `accounts.<name>.driver` | name | required | The account driver: `claude`, `chatgpt` or `opencode` today. |
| `accounts.<name>.secret` | name | | **Planned · milestone 5.** The credential's name in the secrets file, for API-key accounts. |
| `accounts.<name>.description` | string | | A note for you. |

### connections

A map of connection names to connections: chat apps and services, connected once and shared by every workspace. Setup creates one named `slack`.

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| `connections.<name>.driver` | name | required | The channel or integration driver. `slack` today. |
| `connections.<name>.secret` | name | the connection's name | Its entry in the secrets file. |
| `connections.<name>.allowed_users` | list of strings | `[]` | For chat: member IDs allowed to talk to agents, such as `U012ABCDEF`. Everyone else is ignored. |
| `connections.<name>.description` | string | | A note for you. |

See [Connecting Slack](https://wheems.dev/docs/slack/#allowing-people).

### knowledge

How every workspace's knowledge base is searched. See [Knowledge base and search](https://wheems.dev/docs/knowledge-base/#turning-on-search-by-meaning).

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| `knowledge.embeddings` | map | none: keyword search only | Turns on search by meaning. |
| `knowledge.embeddings.driver` | name | required | The embeddings driver: `ollama`. |
| `knowledge.embeddings.model` | string | the driver's usual one: `nomic-embed-text` | The model. |
| `knowledge.embeddings.url` | URL | `http://127.0.0.1:11434` | Ollama's address. Other keys are passed to the driver as its own options. |
| `knowledge.vector_store` | map | SQLite files in `.wheems/index/` | Where vectors are kept. |
| `knowledge.vector_store.driver` | name | `sqlite` | The vector store driver. |

Changing the embeddings driver or model rebuilds every index the next time the service syncs it.

## workspace.yaml

One per workspace, in `workspaces/<id>/`. The folder name is the workspace's id. `wheems init` creates it.

```yaml title="~/wheems/workspaces/acme/workspace.yaml"
name: Acme
description: A small design studio.
accounts: [claude-subscription]
chief_of_staff: chief-of-staff

channels:
  chat: { connection: slack, channel: acme-chat }

identity: { name: Acme chief of staff, icon: ':office:' }
skill_budget: 20

knowledge:
  note_after_idle: 30
  tidy_at: '03:00'
  filer:
    engine: claude-code
    model: claude-sonnet-5-5
    account: claude-subscription
```

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| `name` | string | required | Display name. |
| `description` | string | | A note for you. |
| `accounts` | list of names | required, at least one | Install accounts this workspace may use. Each agent picks from these. |
| `chief_of_staff` | name | `chief-of-staff` | The agent file in `agents/` you talk to. |
| `channels` | map of names to bindings | `{}` | Where the workspace talks. `chat` is used today. |
| `identity.name` | string | | The name its posts appear under in Slack. `wheems init` sets "*Name* chief of staff". |
| `identity.icon` | string | | An emoji such as `:house:`, or an image URL. |
| `skill_budget` | positive integer | `20` | Doctor and validate warn when the workspace pins, or one agent lists, more skills than this. |
| `knowledge.note_after_idle` | integer, minutes | `30` | How long a conversation stays quiet, after new work, before its agent is asked for a note. `0` turns it off. |
| `knowledge.tidy_at` | `"HH:MM"` or `false` | `'03:00'` | When the nightly tidy runs, in local time. `false` turns it off. Quote the time. |
| `knowledge.filer.engine` | name | the chief of staff's engine | The engine the filer runs in. |
| `knowledge.filer.model` | string | `claude-sonnet-5-5` on Claude Code, else the chief of staff's model | The filer's model. |
| `knowledge.filer.account` | name | the chief of staff's account | The account the filer uses. |
| `integrations` | map | `{}` | **Planned · milestone 9.** Install connections this workspace may use, each with `access: read` (default) or `full`. |
| `isolation` | `enforced` or `hard` | `enforced` | **Planned · milestone 6.** How strictly it's kept apart from other workspaces. |
| `machine` | name | | **Planned · milestone 10.** The machine agents run on by default. |
| `rules` | list | `[]` | **Planned · milestone 9.** Rules written once and enforced everywhere they can be. See below. |

### channels

Each channel binding is one of:

| Form | Meaning |
| --- | --- |
| `{ connection: slack, direct: true }` | The Slack app's direct messages. Only one workspace per connection. |
| `{ connection: slack, channel: acme-chat }` | A channel, by name (with or without `#`) or id (`C…`, `G…`). Invite the bot to it. |

| Channel | Status |
| --- | --- |
| `chat` | Built: where you talk to the chief of staff. Validate warns if a workspace has none. |
| `approvals` | **Planned · milestone 3.** Approval buttons. |
| `updates` | **Planned · milestone 3.** Progress from agents. |
| any other name, such as `briefs` | **Planned · milestone 7.** For workflows to post to. |

### rules

**Planned · milestone 9.** Validated today; nothing enforces them yet. A rule needs at least one of `deny`, `require` or `approval`, and `approval` goes with `action`.

```yaml title="~/wheems/workspaces/acme/workspace.yaml"
rules:
  - name: release-hold
    deny: { push: [main], deploy: [production] }
  - name: review-before-merge
    require: { review: reviewer, before: merge }
  - name: deploys-need-approval
    action: deploy
    approval: approvals
```

| Key | Type | Meaning |
| --- | --- | --- |
| `name` | name | Required. |
| `description` | string | A note for you. |
| `project` | name | Limit the rule to one project. |
| `deny` | map of actions to lists of targets | Actions it refuses, for the targets listed. |
| `require.review`, `require.before` | names | An agent's review that must happen before an action. The agent must have a file in `agents/`. |
| `action`, `approval` | names | An action that needs approval in the named channel, which must be one of the workspace's channels. |

## Agent files: agents/&lt;name&gt;.md

YAML front matter, then the agent's instructions in Markdown. The file name is the agent's name.

```markdown title="~/wheems/workspaces/acme/agents/chief-of-staff.md"
---
description: The one entry point for Acme, aware of everything going on in it.
engine: claude-code
model: claude-opus-5-5
account: claude-subscription
permissions: auto
skills: [weekly-report]
---

# Acme: chief of staff

You are the chief of staff for Acme. Be brief. Lead with the answer.
```

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| `name` | name | the file name | Must match the file name if given. |
| `description` | string | | What the agent is for. |
| `engine` | name | required | `claude-code`, `codex` or `opencode`. Validate warns about any other. |
| `model` | string | required | The engine's model id, such as `claude-opus-5-5`. |
| `account` | name | required | One of the workspace's `accounts`. |
| `permissions` | `ask`, `auto` or `skip` | `ask` | How much it may do without asking. See [permission levels](https://wheems.dev/docs/engines/#permission-levels). `wheems init` writes `auto`. |
| `skills` | list of names | `[]` | Skills from the workspace's `skills.yaml`. |
| `integrations` | list of names | `[]` | **Planned · milestone 9.** Integrations from the workspace's `integrations`. |

Today the service starts only the chief of staff. Other agent files are validated and can be given skills; teams of agents arrive in milestone 5.

## skills.yaml

The skills a workspace uses, each pinned to a library version.

```yaml title="~/wheems/workspaces/acme/skills.yaml"
skills:
  weekly-report: 2
```

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| `skills.<name>` | positive integer | | The library version this workspace uses. It must exist in `library/skills/<name>/<version>/`. |

See [Skills](https://wheems.dev/docs/skills/).

## workflows/&lt;name&gt;.yaml

> **Planned · milestone 7:** Workflow files are validated today, so what you write keeps working, but nothing runs them. In milestone 7 they become DAGs, with step ids, `needs`, timeouts and checked outputs, so this format will grow.

```yaml title="~/wheems/workspaces/acme/workflows/weekly-report.yaml"
description: The weekly report, every Friday afternoon.
trigger: { schedule: '0 16 * * 5' }
steps:
  - agent: chief-of-staff
    task: Write the weekly report.
  - ask: { question: Send it?, channel: chat }
  - post: { channel: chat }
```

| Key | Meaning |
| --- | --- |
| `name` | Defaults to the file name. |
| `description` | A note for you. |
| `trigger` | One of `{ schedule: '<five-field cron>' }`, `{ message: { channel, contains } }` or `{ file: { path: '<glob>' } }`. |
| `steps` | At least one of: `{ agent, task }` to run an agent; `{ ask: { question, channel } }` to ask for approval (in `approvals` unless `channel` is given; the channel must be one of the workspace's); `{ post: { channel, text } }` to post, the previous step's result when there's no `text`. |

## The secrets file

`~/.config/wheems/secrets.json` holds credentials by name, outside the install folder and out of git, readable only by your user (mode 600). Agents run as your user, so that keeps it from other users, not from agents. `wheems setup` writes it; you shouldn't need to.

```json title="~/.config/wheems/secrets.json"
{
  "slack": { "bot_token": "xoxb-…", "app_token": "xapp-…" }
}
```

> **Planned · milestone 9:** The vault, keeping secrets in the macOS Keychain and logging every use, replaces this file in milestone 9.

## Environment variables

| Variable | Meaning |
| --- | --- |
| `WHEEMS_HOME` | The install folder. Default `~/wheems`. `--home <dir>` overrides it per command. |
| `WHEEMS_SECRETS` | The secrets file. Default `~/.config/wheems/secrets.json`, or `$XDG_CONFIG_HOME/wheems/secrets.json`. |
| `WHEEMS_WORKSPACE` | The workspace `wheems kb search` searches. Wheems sets it in every agent session. |
| `WHEEMS_CONVERSATION` | The conversation an agent's commands belong to. Wheems sets it in every agent session. |
| `WHEEMS_NO_ANIMATION` | Set to anything to stop the cloud winking on the welcome screen and in `wheems setup`. |
| `XDG_CONFIG_HOME` | Where the secrets folder goes, if set. |

## A complete example

The Wheems repository has a complete example install, including the planned formats, in [`examples/install/`](https://github.com/wheems-dev/wheems/tree/main/examples/install). Check it with `wheems validate examples/install`.
