Skip to content
cccskills
FreePublished on GitHub

new-setting

Guided workflow for adding a new user setting or global setting to JellyRock. Walks the recipe in docs/dev/new-user-setting.md (pick the kind, add the settings/settings.json entry, add its strings, add the JellyfinUserSettings field, read it in code, test it). Stops at each step to verify and gives the user the relevant file paths. Use when adding a toggle, a choice, a number or a text setting that the user can change in the JellyRock Settings screen.

The English summary is being prepared. Showing the original description.

jellyrock/jellyrock46 stars(GitHub 46 + cccskills 0)

Run score Not tested

See how to install

Files included (1)

  • SKILL.md7.2 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

/new-setting: a guided workflow

Wraps docs/dev/new-user-setting.md as a step-by-step. The guide is the source of truth; this skill makes sure no step is skipped. Read the guide's section for each step before doing it.

Step 0: Confirm a setting is the right answer

There are three kinds of settings-shaped state (the guide's table):

  1. User setting: saved in the user's registry section, for one user. Named by area: playback*, ui*, itemGrid*.
  2. Global setting: saved in the JellyRock registry section, for everyone on the device. Named global* (Remember Me? is globalRememberMe). The prefix is what decides where the value is saved: isGlobalSetting() in source/utils/config.bs checks it.
  3. User configuration: owned by the Jellyfin server. JellyRock never stores it; read it from m.global.user.

Search settings/settings.json for a setting that already covers the behavior (a new "Show clock on the player" would overlap uiDesignHideClock). If one does, ask whether to extend it instead. If the server already tracks the value per user, stop: don't add a setting, read it from m.global.user. Don't add one for state that lasts one session, or for something the app can detect on the device either. If unsure between the first two, pick a user setting; it is the common case.

Step 1: Add the entry to settings/settings.json

This is the one source of truth for defaults. user.settings.SaveDefaults() fills every field from it at start-up and at sign-in, and a default is never written to the registry: only a value the user changed is.

Follow the guide's step 1: put the entry in its category's children, in order of title. settingName is lowerCamelCase with its area's prefix, and specific (playbackPlayDefaultAudioTrack, not playbackAudio). Pick the type from the guide's table, which also gives the field type it needs. Read settings/settings.json for the shape before editing.

The Settings screen (components/settings/settings.bs) builds its menu from this file, so a setting of an existing type needs no UI code. visibleWhen and presetValues cover showing an entry conditionally and setting several values at once.

Step 2: Add the strings

Add each new titleKey and descriptionKey (and each option's titleKey) to locale/custom/en_US.json through /translation-add. The Step 1 entry is what uses these keys, so update-translations won't remove them as unused (the warning in /translation-add is about keys only code uses). npm run lint:translations checks the keys settings.json uses.

Step 3: Add the field to JellyfinUserSettings

Add a field to components/data/jellyfin/JellyfinUserSettings.xml, in its area's section, as the guide's step 3 shows:

  • the id matches settingName exactly, because the value is saved and loaded under it;
  • the type comes from the guide's table (a radio setting is a string);
  • give it no value: the default comes from settings.json.

No .bs change is needed. JellyfinUserSettings.bs observes every field and saves a change once auto-sync is on, and user.Login() (source/utils/session.bs) loads every registry key that names a field through user.settings.Save(), which converts it to the field's type.

Step 4: Read it in code

Read m.global.user into a local once, then localUser.settings.<settingName>. When the setting overrides a server value, write one function that decides between them and call it everywhere; the guide's step 4 shows resolvePlayDefaultAudioTrack(). Search for every place the behavior lives (git grep -n "<related term>" -- source components) so the setting changes all of them.

Step 5: A registry migration, only when changing an existing setting

Renaming or removing a setting, or changing the shape of its stored value, needs a registry migration: use /new-migration. A new setting needs none: a user who never set it gets the default from settings.json.

Step 6: Test it

A plain on/off setting read in one place may need no unit test, only the on-device checks in Step 7. Otherwise follow the guide's step 5: unit-test a resolving function in tests/source/unit/<area>/ (cover each option, the server's value, invalid nodes and an unexpected value). A suite that touches the registry uses test- section names and sets m.needsRegistrySetup = true before super.setup(), so its sections are cleared after each test (unit-tests.md).

Step 7: Verify

npm run validate
npm run lint:translations

Then on hardware: npm run device:check, and when a device answers, npm run test:tdd with your spec listed, then the guide's on-device checks (the setting shows, survives a restart, changes the behavior, and the default applies to a user who never changed it). If the probe fails, say the probe failed; never claim "tested" without a green run.

docs/user/app-settings.md is generated from settings.json. The jellyrock-bot workflow regenerates it after the change merges, and npm run docs:settings does the same locally. Never edit it by hand.

Common pitfalls

  • No default in settings.json. The field then reads its type's default (an empty string, 0, false), and code that reads it may misbehave.
  • Writing the default to the registry. Defaults belong only in settings.json, so that changing a default reaches every user who never changed the setting.
  • A field id that differs from settingName. The value is saved under one name and loaded under the other, so it never comes back.
  • A global setting without the global prefix, or a user setting with it: the value is saved in the wrong section.
  • A registry test without m.needsRegistrySetup = true. Sections leak into the next suite and fail it.

When not to use

  • The value is owned by the server: read it from m.global.user.
  • You're renaming or removing an existing setting: use /new-migration.
  • You're adding a developer-only debug flag: see docs/dev/debug-flags.md; flags are different machinery.

Sub-agent invocation

To run it from a sub-agent, the parent passes Read .claude/skills/new-setting/SKILL.md and follow the steps for adding the setting <setting-name>; surface each step's file paths and the diffs to apply but do not commit in the Agent prompt.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Session-start briefing: where did I leave off, what is in flight, what needs attention. One tested script reads git, the journal (followups, running work, cadences) and tracked projects and prints every fixed-threshold check that fires; JellyRock's own aggregator adds open PRs, high-engagement bugs, recent bug reports, current-branch CI, pending handoffs, open upstream-watch issues (Jellyfin releases and release candidates, Roku OS), recent ADRs, tech debt and architecture-doc staleness. Ends with one Suggested next move that hands off to /log, /done, /issue-triage, /runtime-triage, /ci-triage or /server-upgrade. Mandated by AGENTS.md's catchup-discipline rule: run at the start of any genuine new session, after a multi-day gap, or whenever you ask what the state of the world is.

The English summary is being prepared. Showing the original description.

jellyrock/jellyrock46Updated Oct 26, 2026

Diagnose a failed CI workflow run and fix it the /snag way. A tested read-only script fetches the run, reports every failed job and step with the log region around its errors (not the post-job cleanup), and classifies each against this repo's gates.tsv, printing the banner a gate carries when its obvious fix is the wrong one. Then: re-run only what is transient, reproduce locally, find the root cause, and show one decision screen; the chosen fix is built test-first and committed on a fix branch, never pushed. Use when a CI run failed on a pull request or on the default branch.

The English summary is being prepared. Showing the original description.

jellyrock/jellyrock46Updated Oct 26, 2026

DEPRECATED, replaced by the `enrich` phase built into /crash-report. The old flow filed crash issues first and enriched them one by one afterward. The new flow (stage, then enrich, then file) pulls the dashboard backtrace before filing, so issues are born complete and architectural-class crashes go to their epic instead of becoming standalone issues. Do not invoke it for new work: run /crash-report and paste the backtraces during its enrich step. It stays only as a redirect; the `enrich-issue` script subcommand still exists as a legacy escape hatch for a crash issue filed before the change.

The English summary is being prepared. Showing the original description.

jellyrock/jellyrock46Updated Oct 26, 2026

Process a Roku weekly crash-report CSV (or a zip holding one or more CSVs) into tracked GitHub issues and architectural-epic evidence, enriching before filing (stage, then enrich, then file). STAGE parses and filters the CSV, groups by pkg-path signature, builds each cited app version in a temporary git worktree, maps the transpiled `.brs` line back to the source `.bs` line, runs the GitHub dedup search, and writes a local worksheet where every crash starts pending; a mechanism hint (task-launch, network, other) orders which to pull first but never authorizes a file. ENRICH folds in the per-crash backtraces you paste from Roku's dashboard (a 7-day window, one click per crash, no bulk export), extracts each `&hNN` exception code, and routes every crash to a disposition (nothing files or aggregates without a backtrace): `file` (a scoped bug becomes a new per-signature [crash] issue, born enriched), `aggregate` (a known architectural class: `&h29` big-library too-many-task-threads, `&h23` render-thread execution timeouts, the `&hec` init `m.global.constants` race; upserted as one flat record comment per `file·function·line·version` onto the class epic, never a standalone issue), or `watch` (accepted noise, a spike comment only). FILE performs the GitHub writes (create, comment or reopen for scoped bugs; the epic record upsert for architectural classes) and writes a run-summary handoff. Dedup-aware and idempotent. Use when a fresh Roku crash CSV arrives (weekly). A deep dive on one crash goes to `/issue-triage <N>` after filing.

The English summary is being prepared. Showing the original description.

jellyrock/jellyrock46Updated Oct 26, 2026

Draft a GitHub issue body for the JellyRock repo from a Reddit/Discord post or free-form bug report and submit it via forge.sh. Reads the YAML form templates under .github/ISSUE_TEMPLATE/ to know which fields are required, fills them by extracting from the input, asks for any missing required fields, validates the body matches the chosen template's schema, then runs forge.sh issue create with the auto-labels the template defines. Use when you have a user report (paste from anywhere) and want to formalize it into a properly-structured GitHub issue.

The English summary is being prepared. Showing the original description.

jellyrock/jellyrock46Updated Oct 26, 2026

Walk a major dependency-version bump (a Renovate major PR, possibly a grouped one carrying several deps, or a package you name) through JellyRock's major-bump SOP so the judgment steps run the same way every time. Resolves each package and its from and to versions, fetches the upstream changelog/migration guide for that range, classifies the breaking changes, greps the codebase for the call sites those breaks actually hit, runs the mechanical gate that fits the dependency's type (a runtime BrightScript lib: validate, build, lint:bs, then test:unit and test:rta on a device; JS or Node tooling: test:scripts, then run the affected script; GitHub Actions: the PR's own CI plus a trace of the conditional paths CI doesn't exercise), and returns a go/no-go with any required migration surfaced (and applied on request). Majors never automerge (the org Renovate config), so this is the human-review path. Use when a Renovate major PR appears, or before bumping a dependency's major version by hand. Not for patch or minor bumps (those automerge after a soak) or for Jellyfin server releases (use /server-upgrade).

The English summary is being prepared. Showing the original description.

jellyrock/jellyrock46Updated Oct 26, 2026

See all skills by jellyrock

Report a problem with this skill