Houndarr Changelog
Documentshoundarr-changelogHoundarr Changelog is an Agent Skill for documents published in the av1155/houndarr repository on GitHub: a SKILL.md instruction file an AI agent can load to do this task.
Houndarr's CHANGELOG.md style guide and entry rules. Loads when reading or editing CHANGELOG.md or VERSION. Covers the noun-led present-tense voice, the 80-160 character length target, vocabulary the operator can act on, banned phrasings, what does not belong in a changelog, separator rules, and the bullet-justification protocol that prevents drafting from PR titles or memory.
How to use this skill
Bring this guide into your coding agent with a prompt tailored to the tool you use.
- Open your project in Codex.
- Copy and paste the prompt below.
- Review files and risks before approving any action.
Inspect the Agent Skill at https://github.com/av1155/houndarr/blob/HEAD/.agents/skills/houndarr-changelog/SKILL.md and all supporting files. Report provenance, permissions, scripts, dependencies, and security risks. Propose an exact installation into .agents/skills/houndarr-changelog, but wait for my approval before writing files or running scripts.
Copying this prompt does not install or run the skill. Review third-party files before use.
Houndarr changelog conventions
The audience is self-hosters and homelab operators running Houndarr in Docker or Kubernetes alongside the *arr stack. They read config files, env vars, log lines, and SQLite schemas; they do not read the Python source. Tune every bullet for that reader.
Voice (noun-led, present tense)
The category heading carries the verb (### Added, ### Fixed,
### Changed). Bullets describe the post-change state from the
reader's vantage point, not the maintainer's action:
- Good:
Logs page distinguishes a fresh install (No log entries yet) from a filter that matches nothing (No entries match those filters.). (#566) - Avoid:
We added a fresh-install vs filter-empty distinction to the logs page.(narrator voice) - Avoid:
Distinguish fresh-install from filter-empty on the logs page.(imperative; reserved for SDK changelogs)
This matches the convention used by Authelia, AdGuard Home, Plausible, Caddy, and other self-hosted tools targeting the same audience.
Length
- Target: 80 to 160 characters per bullet.
- Hard ceiling: 250 characters. A bullet longer than that must split into two unrelated bullets, or the second clause moves to the PR body.
- One sentence per bullet. A second sentence is permitted only when a migration or upgrade-affecting consequence must ride with the change (rare).
Vocabulary the operator can act on, only
- Use: env var names (
HOUNDARR_COOKIE_SAMESITE), config keys, schema version numbers (Schema v16), database column names that survive in the SQLite file (monitored_total,whisparr_episode), HTTP routes (/api/status), log strings the operator can grep (hourly limit reached (N/hr)), CVE IDs, dependency versions when a security or behaviour change ties to the bump. - Avoid: internal Python class names (
InstanceValidationError,AuthMiddleware._dispatch_proxy), private helpers (_redirect_guard,_run_search_pass), file paths undersrc/, module attribute names that have no user surface. Describe the user-visible behaviour instead. - Borderline: public library types that surface in tracebacks
(
httpx.TransportError). Allowed when the user actually sees the type name in their logs, otherwise paraphrase to "transport-level error".
Banned phrasings (drift signals; rewrite or drop)
- Vague: "Various bug fixes", "Minor improvements", "Misc updates", "Bug fixes and stability improvements".
- Marketing: "We are thrilled to...", "delightful new experience", "groundbreaking", "exciting".
- Magic adverbs without measurement: "seamlessly", "robustly", "significantly", "dramatically". Either quantify ("reduces idle CPU by 60%") or omit.
- Empty verbs: "leverages", "utilizes", "harnesses", "facilitates". Pick the concrete verb.
- Vague comparatives: "Improved error handling", "Enhanced UX", "Better performance". Name the change: "Connection errors now log at WARNING with the instance name."
- Bold lead-ins:
**Performance:** faster X. Plain bullet. - Marketing trail clauses: "for a smoother experience". Stop at the technical fact.
- Past-tense narration: "We added...", "We fixed...". Drop the pronoun.
- Em dashes anywhere (project-wide rule; use a colon, semicolon, comma, period, or parentheses).
What does NOT belong in the changelog
- Pure refactors with no user-visible behaviour change (Common Changelog explicitly excludes these; they live in PR bodies).
- Test-only changes.
- Docs-only changes (the docs site has its own deploy log).
- CI / workflow changes that do not affect deployers.
- Dependency bumps with no security or behaviour impact.
Schema version bumps
When a release ships a SQLite schema migration, name the schema number, what the migration touches, and any rollback constraint. An AdGuard-Home-style "to roll back, downgrade to " line helps operators who restore from a backup.
Examples (verbatim from the repo, judged)
- Exemplary:
Helm chart `appVersion` is now prefixed with `v` so it matches the published Docker image tags. (#364)(102 chars; named user-visible attribute; one causal clause). - Exemplary:
Hourly rate-limit skip rows now read `hourly limit reached (N/hr)` across missing, cutoff, and upgrade passes. (#491)(names the exact log string the operator greps for). - Over-technical (rewrite before merging):
Curated `InstanceValidationError.public_message` text replaces the raw exception in instance validation bannersshould readInstance validation banner shows a curated message instead of the raw Python exception. - Over-technical (rewrite):
Random search order now uses a stratified-shuffle page deck plus partial-page sentinel paddingshould readRandom search order spreads dispatch probability uniformly across the backlog so no page is over- or under-selected.
CHANGELOG entry rules
CHANGELOG.md always carries a ## [Unreleased] section above every
versioned block:
## [Unreleased]
### Added
- One sentence per bullet. (#N)
### Fixed
- One sentence. User-facing impact first. Issue/PR ref at end (#N).
---
## [X.Y.Z] - YYYY-MM-DD
### Added
- One sentence per bullet. (#N)
### Changed
- One sentence per bullet. (#N)
### Fixed
- One sentence per bullet. (#N)
### Removed
- One sentence per bullet. (#N)
---
Allowed ### headers (Keep a Changelog 1.1.0): Added, Changed,
Deprecated, Removed, Fixed, Security. Level-4 #### subheadings
may group items within ### sections for major releases. Omit any
section that has no entries.
Bullet rules
- Add the bullet to
## [Unreleased]as part of the same PR that ships the change. /bump promotes the accumulated Unreleased block to a versioned heading at release time. - Every bullet must be justified by a PR-body sentence, a diff fragment,
or a source
file:line. Do not draft from PR titles, commit messages, or memory alone. The verification protocol lives in.claude/commands/bump.md§3b; skipping it is what shipped the inaccurate v1.9.0 bullets that had to be corrected in #420. - Adopt the PR author's vocabulary for nuance. If the PR body says "new default for fresh installs; existing instances keep their prior behaviour," the bullet says "new default for newly added instances," not "new default."
- One sentence per bullet; no multi-line prose.
- Lead with user-facing impact, not implementation details.
- End with
(#N)issue/PR reference. - Use backticks for identifiers, file names, env vars, UI elements.
- Use markdown
[text](url)syntax for links; bare URLs do not auto-link in the in-appWhat's Newmodal (GitHub's CHANGELOG view autolinks both, but the modal's_render_changelog_bulletfilter only accepts the[text](url)form). - Be specific:
Connection errors now log at WARNING with instance namenotImproved error handling.
Separators
Both ## [Unreleased] and every versioned block end with a --- line
(blank line before and after). The fresh Unreleased block reseeded by
/bump carries only the heading and the trailing ---.
Non-user-facing PRs
CI-only, refactor-only, test-only, docs-only, and chore/infrastructure changes do not get a Changelog bullet. The /ship workflow filters these out automatically.
CI-enforced validation
- PR-time (
version-check.yml): Runs on PRs touchingVERSIONorCHANGELOG.md. Validates VERSION format, requires## [Unreleased]as the topmost## [...]block, validates the Unreleased block's###headers + trailing---separator, and validates the## [VERSION] - YYYY-MM-DDblock matches VERSION with valid###headers + trailing---. - Tag-time (
release.yml): Validates VERSION == tag, extracts the## [X.Y.Z]block viaawk, creates GitHub Release using--notes-file(avoids backtick shell substitution).
The in-app What's New modal parser (src/houndarr/services/changelog.py)
silently skips ## [Unreleased] because the heading lacks the X.Y.Z
plus ISO-date suffix that _VERSION_HEADING requires; users only see
versioned blocks until /bump promotes Unreleased.