Contributing
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.
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
unittestwith synthetic data. Add a failing test first, then the change. - No em dashes and no emoji anywhere.
test_skill.pyscans 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
noreplycommit trailer address is allowed) or a Slack-style id. - Every platform claim in docs carries a tag:
verified,assumedorunverified. Add the claim toskills/routineos/references/platform-facts.mdfirst. SKILL.mdstays under 200 lines. Detail goes inreferences/with a “read when” cue; a reference over 150 lines needs aContents: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, neverinnerHTML, 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.
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.