From mosdat
Use when authoring mOSdat scenarios for a new feature. Walks the routines-first workflow: identify atomic interactions, reuse or create routines, compose scenario. Triggers on /mosdat-authoring, 'write tests for X in mOSdat', 'author scenario for X', 'add mOSdat coverage for PR #N'.
How this skill is triggered — by the user, by Claude, or both
Slash command
/mosdat:mosdat-authoringThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Triggers: `/mosdat-authoring`, "write tests for X in mOSdat", "author scenario for X", "add mOSdat coverage for PR #N"
Triggers: /mosdat-authoring, "write tests for X in mOSdat", "author scenario for X", "add mOSdat coverage for PR #N"
Use this skill when:
shared/routines/ and integrate it into a scenario.Do NOT use this skill for:
verify: step to an existing passing scenario./mosdat-insight or mosdat recipes instead).The defining test: is this NEW feature coverage being authored from zero? If yes, invoke this skill.
Before writing anything, learn the library.
mosdat routines list # full inventory + tags
mosdat routines show <name> # inspect any routine's schema, inputs, fallbacks
mosdat routines explain <name> # dry-run preview — shows which fallback fires
mosdat routines report --format md # coverage map — which scenarios use which routines
mosdat routines fixtures # available VM-state fixtures
Then for every atomic interaction your feature needs, run:
mosdat routines list | grep -i <keyword>
Try keywords: feature area (telephony, settings, login, modal), UI surface (dialog, dropdown, sidebar), side-effect category (dispatch, toggle, select).
Run these before touching any file. They prevent authoring against a stale binary or a broken VM.
# I3 — get a clean build of the PR binary, deploy to VM, verify the feature symbol is present
mosdat build --pr <N> --deploy <vm> --verify-symbol <feature>
# I2 — confirm the existing baseline still passes before you change anything
mosdat preflight <toml> --vms <vm> --test <existing-stable-scenario>
# I13 — VM health: SSH, VNC, X11 surface, display reachable
mosdat doctor <toml> --vms <vm>
# F2 — check for known platform constraints related to this feature area before you design steps
mosdat recipes search "<feature keyword>"
# F1 — refresh the capability manifest (accelerator probes, popup behavior)
mosdat trace <toml> --vms <vm>
Stop if mosdat build or mosdat preflight returns non-zero. Do not author against a broken baseline.
Do not start by writing a scenario. Start by listing atomic interactions.
Write down every discrete UI action the feature needs. Examples:
tel: deeplinkmosdat routines list
mosdat routines show <name>
For each atomic interaction, check whether an existing routine covers it. If the match is close but not exact, prefer reusing with an input parameter over writing a new routine.
For EACH atomic interaction, exhaustively check the existing library before authoring. Procedure:
mosdat routines list — scan all 9+ routines by name + tags.mosdat routines show <candidate> and READ THE FULL spec (description, inputs, postcondition). Decide: reuse / extend with new input / fork into new routine.inputs: block with default that preserves existing callers' behavior.Create shared/routines/<slug>.yaml. Schema reference: docs/routines.md.
Before writing any YAML, pick a sibling routine in the same family (same tag) as a template. Open it:
mosdat routines show <sibling-name>
Copy its structure (description shape, input declarations, pre/postcondition wording). Customize for the new interaction. Examples by family:
enable-telephony-toggleselect-telephony-server-from-modalopen-settings (with capability fallback)cleanup-rocketchat / launch-rocketchatverify-app-alivedispatch-tel-linkMinimal structure:
name: <kebab-case-slug>
description: <one sentence — what it does>
schema_version: v1
tags: [<feature-area>, <ui-surface>, <side-effect-category>]
inputs:
- name: <param>
type: string
required: true
preconditions:
- verify: "<expected pre-state before main steps>"
steps:
- shell: ...
postconditions:
- verify: "<guaranteed end-state>"
on_failure:
- shell: |
DISPLAY=:0 scrot /tmp/routine-failure.png
- shell: journalctl --user -n 50 --no-pager
fallbacks:
- when: "capability.accelerators['<key>'] == 'swallowed'"
steps:
- shell: <alternate input method>
mosdat routines test <name> --vms <vm> --fixture <fixture> --config <toml>
List available fixtures:
mosdat routines fixtures
Iterate until exit code 0. A routine that fails in isolation will fail in every scenario that uses it. Fix here, not in the scenario.
Override a specific input for a test run:
mosdat routines test <name> --vms <vm> --fixture <fixture> --with <key>=<value>
Stitch - routine: <name> calls together and add feature-specific verify: steps.
Canonical worked example: shared/scenarios/functional/3325-master-toggle.yaml (76 lines, 4 routine calls).
name: "<App> — <Feature description> (PR #N)"
vars:
workspace_url: "https://..."
phases:
- id: A
name: "baseline: feature off"
from_step: 1
- id: B
name: "feature on"
from_step: <N>
steps:
- routine: cleanup-rocketchat
- routine:
name: launch-rocketchat
with:
servers: [...]
<feature_flag>: false
- routine:
name: <action-routine>
with: { <param>: <value> }
- verify: "<expected negative result>"
verify_timeout: 15
retries: 3
- routine: cleanup-rocketchat
- routine:
name: launch-rocketchat
with:
servers: [...]
<feature_flag>: true
- routine:
name: <action-routine>
with: { <param>: <value> }
- verify: "<expected positive result>"
verify_timeout: 20
retries: 5
- key: Escape
- wait: 2
- routine: verify-app-alive
- routine: cleanup-rocketchat
python3 -c "
from pathlib import Path
from automation.runners.scenario_loader import load_test_yaml
load_test_yaml(Path('shared/scenarios/functional/<scenario-name>.yaml'))
"
Fix any ValidationError before running.
mosdat functional <toml> --vms <vm> --test <scenario-name> --save-screenshots
Resume from a specific step or phase after a failure:
mosdat functional <toml> --vms <vm> --test <scenario-name> --from-step <N>
mosdat functional <toml> --vms <vm> --test <scenario-name> --from-phase <phase-id>
results/functional/<run-timestamp>/<vm>/.mosdat replay <result-dir> (I5) to iterate on verify prompts without re-running the full scenario.mosdat recipes search "<symptom keyword>" (F2) — check if the failure matches a known platform constraint./mosdat-insight to surface relevant lessons. Do not try a third approach before consulting it.Before saving a new routine, verify:
name is kebab-case and matches what the routine doesinputs declared with RoutineInput fields: name / type / required / defaultpreconditions contain only verify: steps asserting the required pre-statepostconditions contain only verify: steps asserting the GUARANTEED end-statefallbacks use when: jinja2 expressions consuming capability.* or vars.*on_failure has at least one diagnostic step (screenshot capture, log dump)description is one sentence stating what the routine doestags include: feature area, UI surface, side-effect categoryschema_version: v1 present (or omitted — defaults to v1)Keep inline (do not routinize):
verify: assertions that will not recur in other testskey: Escape when it is a single stepMove to a routine (routinize):
Decision heuristic: if you would have to copy-paste this block into the next scenario, it is a routine.
Inline 200-line scenario — A scenario with 40+ inline shell blocks is authoring debt. Each block is a point of silent failure. Split into routines. See 3325-master-toggle.yaml: 236 lines → 76 after routines-first.
Hard-coded pixel coordinates — xdotool mousemove 300 280 breaks when resolution or layout changes. Use localize: "<element description>" with click: true for dynamic elements. Use coordinates only for stable, permanently-positioned UI chrome.
Settings nav for persisted state — Do not click through Settings to set a value that lives in config.json. Use --inject-config (I1) or the launch-rocketchat routine's input parameters. Settings nav on Linux Electron is a known failure surface: Ctrl+, has no accelerator, sidebar kebab is transient, alt+w is swallowed by the webview. See docs/skills/state-first-testing.md §3.
config.json for feature flags — Do not write boolean feature flags (isTelephonyEnabled, isMenuBarEnabled, etc.) into config.json. RC's Redux-persist rehydrates from its own namespace and silently ignores those top-level keys. Use overridden-settings.json instead — the launch-rocketchat routine handles this split automatically via the telephony_enabled and related inputs. See docs/runbooks/scenario-state-seeding.md.
Skipping routine isolation tests — Running the full scenario first and debugging composite failures wastes cycles. Test each new routine independently via mosdat routines test before composing.
VLM prompts naming exact values — verify: "version number v6.8.0 visible" will break on the next release. Describe the state type: verify: "version information shown in the status area".
Forgetting to grep the library — every new feature inherits ALL existing routines. Skipping mosdat routines list means you'll re-implement someone else's debugged work. Always run the discovery commands in section 0 first.
One-off "this is special" mindset — if you tell yourself "this interaction is unique, no point making it reusable," you're almost always wrong. Future features rhyme; routines compound.
Before declaring authoring complete, all of the following must be true:
mosdat lint <scenario> (F1a) returns no warnings or errorsmosdat routines test <each-new-routine> exits 0 on the target VMmosdat routines report shows every new routine with test history (not untested)mosdat functional <toml> --vms <vm> --test <scenario-name> passes end-to-endmosdat routines report --format md output# TODO: markers remain in the scenario YAMLWhen writing your scenario, if you find yourself adding:
STOP. Routine-ize it. Procedure:
shared/routines/<slug>.yaml using a sibling as template (step 4 above).mosdat routines test <slug> against a fixture until green.- routine: <slug>.docs/routines.md if the routine introduces a new family.Rule of thumb: if you can describe the interaction in one English sentence ("open settings", "dismiss modal", "type credentials into login form"), it's probably a routine. If it takes a paragraph, it's scenario logic.
docs/routines.md — full routine schema, RoutineInput fields, fallback syntax, fixture reference, CLIdocs/AUTO-AUTHORING.md — routines-first workflow, change-type classification, mosdat draft scaffolddocs/skills/state-first-testing.md — when to use --inject-config vs UI navigationCHANGELOG.md — full feature surface: I1-I15, F1-F5, R1-R7shared/scenarios/functional/3325-master-toggle.yaml — canonical worked example (76 lines)shared/routines/ — existing routine library (reuse before authoring)shared/recipes/ — platform constraint corpus (mosdat recipes search)Provides a checklist for code reviews covering functionality, security, performance, maintainability, tests, and quality. Use for pull requests, audits, team standards, and developer training.
npx claudepluginhub jeanfbrito/mosdat