# Local development and timetable maintenance The installed widget reads the bundled `data/.json` file and calculates its display locally. Its adaptive timer updates hourly beyond two hours, every minute inside two hours, and every second for the final two minutes. It makes no automatic network requests. The only installed-runtime network action is the Settings **Sync calendar now** button, which the user must click. That action fetches the current year's JSON from the fixed Jolpica HTTPS URL, validates and converts it in QML, then atomically writes `$XDG_DATA_HOME/omarchy-f1-schedule/data/.json` (falling back to `~/.local/share`). The display prefers that user-owned override over bundled data. Never add timers, panel-open fetches, configurable URLs, shell command strings, downloaded-code execution, or credentials to this path. The separate user-configured `watchLink` setting may only be opened by an explicit hero click through the system URL handler; it must never be fetched or executed by the plugin. All plugin-owned labels must use `PlainText`, never a raw QML `Text` item. QML `Text` defaults to `Text.AutoText`, so an API value such as `` could otherwise be interpreted as rich text and trigger a resource request instead of being displayed literally. Dynamic strings passed into Omarchy-owned components that still use AutoText must first use `Model.autoTextSafe`; it inserts an invisible character after each `<` so the visible value is preserved but no valid markup tag remains. Keep the invariant checks in `tests/test-view-model.sh` when adding UI text. ## Test a change locally Do not push a UI change just to inspect it. The source checkout is authoritative. Mirror it explicitly into the installed plugin directory, preserving that directory's `.git` metadata, then ask Omarchy to rescan it and restart the shell. The restart guarantees a full QML recreation, including newly added imports and assets. ```sh plugin_target="${XDG_CONFIG_HOME:-"$HOME/.config"}/omarchy/plugins/io.github.anthonyposchen.f1-schedule" mkdir -p "$plugin_target" rsync -a --delete --exclude='.git' ./ "$plugin_target/" omarchy-shell shell rescanPlugins omarchy restart shell ``` Run these commands from the repository root. The target's working files are replaced, so do not keep uncommitted edits there. Make edits in this repository, then mirror them. To test another installed copy, replace `plugin_target` with its explicit path. ```sh plugin_target="/path/to/io.github.anthonyposchen.f1-schedule" rsync -a --delete --exclude='.git' ./ "$plugin_target/" omarchy-shell shell rescanPlugins omarchy restart shell ``` Before handoff or commit, run: ```sh go test ./... tests/test-view-model.sh omarchy plugin validate . qmllint BarWidget.qml Panel.qml PlainText.qml Model.js tests/test-model.qml git diff --check ``` ## Maintain a season timetable `cmd/update-season/main.go` is a Go-only maintainer tool. It fetches the published Jolpica schedule and writes `data/.json`; it is never run by an installed widget. At the start of a new season, or once a published calendar is available, use a clean worktree: ```sh scripts/update-season --year 2027 go test ./... tests/test-view-model.sh git diff -- data/2027.json ``` Review the diff before committing. Verify the meeting count, meeting names, session order, UTC timestamps, sprint weekends, and any late calendar changes against the source. Then commit the generated data with a timetable-specific commit, for example: ```sh git add data/2027.json git commit -m "chore(timetable): add 2027 schedule" ``` For an offline/reproducible conversion test, pass a saved Jolpica response instead of downloading: ```sh scripts/update-season --year 2027 --input tests/fixtures/jolpica.json --output /tmp/2027.json ``` The GitHub workflow runs on 15 January and can be dispatched manually with a season year. It commits only a reviewed upstream conversion result; do not add API keys, background fetches, configurable URLs, shell command strings, or downloaded-code execution to QML or the installed plugin. The only permitted installed-runtime network path is the fixed, user-triggered manual sync described above. ## Release versions Use Calendar Versioning for public releases. A release is incomplete unless `CHANGELOG.md`, `manifest.json`, its Git tag, and the GitHub Release are updated together and point at the same committed `HEAD`. For every user-visible change, add a concise entry under **Unreleased** in `CHANGELOG.md`. When releasing, move those entries into a dated section named for the exact manifest version. Commit the changelog and manifest version together before tagging. After pushing the branch and annotated tag, publish a GitHub Release for that tag using the same user-facing notes. Do not consider a release complete until all four are present. The Go code is an internal maintainer tool, not a published dependency. Use these paired values for a release on 22 August 2026: ```text manifest.json version: 2026.8.22 Git tag: v2026.8.22 ``` Do not zero-pad the manifest month or day. For a second release on the same day, use SemVer build metadata in both values: manifest `2026.8.22+2` and tag `v2026.8.22+2`. Before tagging, update and commit `manifest.json`, verify the worktree is clean, inspect existing same-day tags, and create an annotated tag. Push it only when the user explicitly asks to publish the release.