---
title: Add a Desk to a routine
description: Give a routine that was scaffolded without a Desk its definition and page, then put two producers on one shared Desk. Every step was run and the outputs are shown.
sidebar:
  order: 3
---

Watch and interactive routines get a Desk when they are scaffolded. Serverless and approval-gated routines do not, unless you add one. This guide adds a Desk to an approval-gated routine, then puts it beside Hiring Signals on one shared Desk.

```
RO=skills/routineos/scripts/routineos.py
```

## What a Desk needs

A routine has a Desk when its folder holds:

| File | Made by | Role |
|---|---|---|
| `definition.json` | `new --type watch` or `interactive` | Record types, identity rules, setting filters, views, learning |
| `dashboard/index.html` | the same | The bundled Desk page, with a `desk-config` block naming the store and workspace |
| `[workspace] enabled = true` in `routine.toml` | you | Marks the routine as writing to a workspace |

`compile` and `seed` need `definition.json`. The page is the same bundle for every routine; only its config block differs.

## 1. A routine without a Desk

Hiring Signals drafts intro notes for strong matches, and a second routine sends them after approval. Scaffold it as approval-gated:

```
python3 $RO new intro-notes --type approval-gated
```

```
created intro-notes
```

The folder holds `README.md`, `prompt.md` and `routine.toml`, and `routine.toml` has:

```toml
[workspace]
enabled = false
```

There is no definition, so nothing compiles:

```
python3 $RO compile intro-notes
```

```
error: no definition.json found in intro-notes
```

Exit code 2.

## 2. Turning the workspace on is not enough

Set `enabled = true`. `lint` passes, but `compile` still fails:

```
python3 $RO lint intro-notes
```

```
ok: no problems
```

```
python3 $RO compile intro-notes
```

```
error: no definition.json found in intro-notes
```

`lint` does not require `definition.json` when `[workspace] enabled = true`. Do not read a clean lint as "this routine has a Desk".

## 3. Borrow the Desk files from a watch scaffold

Scaffold a watch routine with the same name into a scratch folder, and copy its two Desk files across:

```
python3 $RO new intro-notes --type watch --dir parts
cp parts/definition.json intro-notes/
cp -R parts/dashboard intro-notes/
```

```
created parts
```

The name you pass to `new` is what goes into the page's config block, so the copied page already names this workspace:

```html
<script type="application/json" id="desk-config">{"store": "db", "workspace": "intro-notes"}</script>
```

The generic definition from a watch scaffold has one record type, `item`, with identity `field:url`, merge policy `merge`, fields `title`, `url` and `why`, one view called `latest`, and learning on. Edit it to describe what the routine records. See [Definition schema](/reference/definition-schema).

Now it compiles and seeds:

```
python3 $RO lint intro-notes
python3 $RO compile intro-notes
python3 $RO seed intro-notes --out intro-notes/seed
```

```
ok: no problems
ok: 1 producer(s), version 04077bc1a259, wrote intro-notes/meta-definition.json
ok: wrote 1 batch file(s) to intro-notes/seed; lint passed. Apply them in order with ArtifactData batch.
```

Delete the scratch `parts/` folder. Publish `intro-notes/dashboard/index.html` as a private artifact with `{"db": {}, "user": {}, "downloads": true}` and apply the seed batch, as in [Build your first routine](/guides/first-routine#5-publish-the-desk-and-seed-it).

## 4. Two producers on one Desk

A workspace can hold several producers. Each keeps its own settings, records and runs; the Desk shows them together. Put both routine folders under one parent:

```
desk/
  hiring-signals/   (routine.toml, definition.json, prompt.md, dashboard/)
  intro-notes/      (routine.toml, definition.json, prompt.md, dashboard/)
```

`compile` treats every subfolder that has both `routine.toml` and `definition.json` as a producer:

```
python3 $RO compile desk
```

```
ok: 2 producer(s), version 4b4b5c66bb5d, wrote desk/meta-definition.json
```

Seed the parent, naming the workspace:

```
python3 $RO seed desk --out seed --name "Hiring Signals"
```

```
ok: wrote 1 batch file(s) to seed; lint passed. Apply them in order with ArtifactData batch.
```

`seed/batch-001.json` writes five documents:

| Document | Holds |
|---|---|
| `meta/workspace` | `name: "Hiring Signals"`, `producers: ["hiring-signals", "intro-notes"]`, the template, and the lint result |
| `meta/definition` | Both producers' types and views, compiled together |
| `settings/hiring-signals` | Hiring Signals' defaults |
| `settings/intro-notes` | Intro notes' defaults |
| `settings/workspace` | Merge policy per type, notifications, quiet hours |

Publish one page for the workspace. The `desk-config` workspace name is only shown until `meta/workspace` loads; after that the Desk uses the name stored there. Point both routines' prompts at the same artifact URL.

Run `lint` on each routine folder, not the parent. The parent has no `routine.toml`:

```
python3 $RO lint desk
```

```
error: file not found: desk/routine.toml
```

## How producers share the Desk

- Each producer writes only its own `bySource` slice of a shared record, and its own runs and Inbox messages. See [Ownership](/concepts/ownership).
- A record type declared by both producers merges by its identity rule unless the workspace's merge policy for that type is `separate`. See [Merges](/concepts/merges).
- Recompile and reseed when either definition changes. Seed writes settings only when they are absent, so values people saved are kept.

## Common pitfalls

- **Trusting lint for a Desk.** It passes with `enabled = true` and no definition.
- **Copying a page scaffolded under another name.** Its config block names the wrong workspace until `meta/workspace` loads. Scaffold the parts with the routine's own name.
- **Linting the parent folder.** Lint each routine.
- **Two artifacts for one workspace.** Each artifact has its own database. Two producers share a Desk only if both write to the same artifact.

## Related

- [The Desk](/desk)
- [Definition](/concepts/definition)
- [Routine kinds](/routine-kinds)
- [CLI reference](/reference/cli)
