Skip to content
RoutineOS
Esc
↑↓navigate↵open⌘Jpreview
On this page

Add a Desk to a routine

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.

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:

[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:

<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.

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.

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.
  • 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.
  • 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.

Was this page helpful?