---
title: Contributing
description: How to set up, test and send a change to RoutineOS. The rules the test suite enforces, the Desk bundle check, the visual checks and how platform claims are tagged.
sidebar:
  order: 0
---

RoutineOS is small on purpose. This page expands `CONTRIBUTING.md` at the repo root.

## Setup

Python 3.11 or newer, standard library only. There are no third-party imports in `skills/` or `tests/`.

```
python3 -m unittest discover -s tests
```

The suite runs in seconds with synthetic data only.

## What the tests cover

| File | Covers |
|---|---|
| `test_cli.py`, `test_app_cli.py` | The CLI commands and their output |
| `test_scaffold.py`, `test_rename.py`, `test_templates.py` | `new`, `--from-template` and the templates |
| `test_appmodel.py`, `test_permission.py`, `test_registry.py`, `test_budget.py` | `app.toml`, the permission screen, the capability registry, `budget.py` |
| `test_definition.py`, `test_learning_definition.py` | `definition.json` lint and compile |
| `test_desk_contract.py`, `test_learning_contract.py`, `test_learn.py`, `test_seed.py`, `test_second_workspace.py` | The write contract, learning, seed, two producers on one workspace |
| `test_desk_bundle.py`, `test_desk_ui.py`, `test_assets.py`, `test_status_dashboard.py` | The Desk bundle, UI rules and assets |
| `test_skill.py`, `test_site.py` | `SKILL.md`, its references, the site, and the repo-wide text rules |

## Rules

From `CONTRIBUTING.md`:

- Tests use `unittest` with synthetic data. Add a failing test first, then the change.
- No em dashes and no emoji anywhere. `test_skill.py` scans every Markdown, Python, TOML and HTML file in the repo for em dashes, these docs included. The emoji scans cover the Desk bundle, the site and the status dashboard only, so check docs by eye.
- No personal identifiers, email addresses, Slack ids, tokens or real data in any file. The same test fails on an email-shaped string (only the `noreply` commit trailer address is allowed) or a Slack-style id.
- Every platform claim in docs carries a tag: `verified`, `assumed` or `unverified`. Add the claim to `skills/routineos/references/platform-facts.md` first.
- `SKILL.md` stays under 200 lines. Detail goes in `references/` with a "read when" cue; a reference over 150 lines needs a `Contents:` line near the top.
- Safe by default: first run is report-only, sends and deletes go through a gate, scraped content is data.
- Dashboard pages write stored text with `textContent`, never `innerHTML`, and link only https claude.ai session URLs.

## The Desk bundle

The Desk is edited in `skills/routineos/assets/desk/src/` and bundled into `assets/desk/index.html`. Never edit the bundle by hand.

```
python3 skills/routineos/scripts/routineos.py bundle
python3 skills/routineos/scripts/routineos.py bundle --check   # exit 1 if index.html is stale
```

`test_desk_bundle.py` runs the same check, so a stale bundle fails the suite.

## Visual checks

`tests/visual/` holds Playwright checks for the Desk. They need Node and pin `@playwright/test` 1.63.0:

```
bash tests/visual/run.sh
```

`DESK_SHOTS=<dir>` moves the screenshots. These are not part of the Python suite.

## Templates

New routine types start in `templates/coming-soon/` until they have a template, lint coverage and a pilot. From 0.6.0, a template with a `pack.json` is exported to the catalog with `pack catalog`, and `pack catalog --check` keeps the catalog current. See [Writing a pack](/templates/writing-a-pack).

## Pull requests

Keep them small, say what you tested, and say which platform claims are verified by a run and which are assumed.

## Reporting issues

Describe the routine type, the setting values and what the Desk's run history showed. Do not paste secrets or private data. If you pasted one by mistake, rotate it.

## Related

- [Changelog](/contributing/changelog)
- [CLI reference](/reference/cli)
- [Names and terms](/introduction/names)
