Imported from safwyls/winnow (
AGENTS.md). Install upstream withnpx skills add safwyls/winnow. Copyright stays with the author.
Winnow — how work is done in this repository
Local-first desktop app that surfaces forgotten games in large Steam/Epic/GOG libraries ("your library has unread mail"). No server, no accounts.
The product, the assembly, the binary and the mascot (a dragon) are all Winnow.
Where to read
Start with README.md for the app and AGENTS.md for working in the repository. Then read
the document for the area you are changing. Each states the current choice and any rationale
needed to use it; there is no document precedence order or required history tour.
| Domain | Document |
|---|---|
| How work is done here: naming, layout, build, run, test, commit, delegation, Backlog | AGENTS.md (this file) |
| Product scope, delivered capabilities, remaining validation and deferred work | ROADMAP.md |
| The build spec: architecture, module boundaries, external services, entity resolution, schema, derived buckets, session detection | game-library-design.md |
| The visual spec: palette, type, layout, dormancy, components, copy, accessibility, themes | design-system.md |
| Token values | src/Winnow.App/Themes/tokens.axaml |
| The scoring model: signals, weights, thresholds, cold start, explainability | docs/recommendation-engine.md |
| Where each filter value comes from | docs/facet-provenance.md |
| Plugin installation and authoring | docs/plugins.md |
| Building and publishing releases | docs/releases.md |
| Orientation for a new reader: what it is, how to install, run and build | README.md |
| Evidence: how something was measured | docs/spikes/ |
| Per-domain agent charters | .codex/agents/ (Codex), .claude/agents/ (Claude Code) |
Update a document in place when behavior changes. Keep a short explanation beside a choice when it helps the reader make the next change. Git records previous wording and decisions; do not copy replaced text into a decision log or add a correction beside a false statement. If documents disagree, verify the implementation and intended scope, then fix the conflicting text together. A newer date, agent charter, plan or experiment does not establish a new rule.
The name, and the word it is not
"hoard" survives as an English word and must not be replaced. Four places use it deliberately and a search-and-replace over them is a regression:
design-system.md§2 "a library about your own hoard", §9 "what a hoard of them looks like", §11.3 "look like the whole hoard"src/Winnow.App/Views/ActionBarView.axaml— the same sentence as the last of those
Anything hyphenated or possessive — Winnow-launched, Winnow's own, Winnow-owned, "a
Winnow theme" — is the product and is already renamed.
Compatibility shims that must not be removed
Each one is load-bearing for an install that predates the 2026-08-28 rename.
WinnowDataLocation(src/Winnow.App/Services/) moves%LOCALAPPDATA%\Hoardto%LOCALAPPDATA%\Winnowonce, sidecars and subdirectories included, and falls back to reading the legacy directory in place if the move cannot be completed. It must never end up pointing at an empty new directory.DatabaseInitializer.RenameLegacyJournalEntriesre-points DbUp'sSchemaVersionsrows fromHoard.Data.Migrations.*toWinnow.Data.Migrations.*.WinnowThemes.LegacyDefaultIdmaps the storedappearance.theme = hoardonto thewinnowtheme, after the catalogue is consulted so an authored theme may still claim the old id.
Layout
src/Winnow.Core— domain records, repository interfaces, ingest contract. No IO, BCL only.src/Winnow.Data— SQLite via Microsoft.Data.Sqlite + Dapper; DbUp migrations as embeddedMigrations/NNNN_*.sql, append-only, never edit shipped ones. Derived buckets are queries, never stored columns.src/Winnow.Ingest.Steam,src/Winnow.Ingest.Epic,src/Winnow.Ingest.Gog— read-only readers over each launcher's local files. Parse VDF with ValveKeyValue, never a hand-rolled parser. EmitCandidateOwnership; never write works or releases.src/Winnow.Resolve— maps candidates to Work and Release. Hard external-id joins auto-merge; fuzzy matches queue for user confirmation and never auto-merge.src/Winnow.Enrich.*— external metadata clients. Rate-limited, cached, soft-failing.src/Winnow.PluginSdk,src/Winnow.Plugins— public provider contracts and plugin hosting.plugins/holds separately packaged providers.src/Winnow.Covers,src/Winnow.Covers.Igdb— cover fetch and disk cache.src/Winnow.Monitor— process watching and session recording.src/Winnow.Recommend— the scoring model. No IO beyond repositories; referencesWinnow.Coreonly.src/Winnow.Auth.WebView— embedded sign-in. References Avalonia andWinnow.Coreonly.src/Winnow.App— Avalonia 11 UI plus the generic-host composition root. Assembly name isWinnow, to matchavares://Winnow/.... The UI reads the database and raises commands; it never calls ingest or enrichment directly.tests/Winnow.Tests— xUnit on temp-file SQLite databases. Parser tests use the sanitized real fixtures intests/fixtures/steam/.tests/Winnow.Ui.Tests— isolated Avalonia headless pointer and keyboard tests with real fonts and templates. Use temporary data and never start the production host. Intermediate animation assertions use controlled frame time; input helpers can pump real render frames before returning. Keep a separate real-frame integration test for scheduling.
Agent instructions and writing
AGENTS.md is the shared entry point. CLAUDE.md imports it. Codex loads the TOML roles in
.codex/agents/; Claude Code uses the matching Markdown roles in .claude/agents/. Keep
paired role instructions equivalent when editing them. Roles inherit the selected model;
do not pin a model unless the user requests it.
Each agent writes the documentation, UI copy and comments required by its work. There is no separate prose author and no prose handoff required to finish a change.
- Write clear, concise sentences with familiar words and active verbs. Lead with the result or fact; add the explanation needed to understand it. Use lists for actual steps or parallel items, and omit filler, sales language and repeated summaries.
- Desktop and fullscreen are separate presentation paths. For each user-facing feature or behavior change, assess both surfaces, keep shared application behavior consistent, and record implementation and verification for each in the same Backlog task. A desktop fix does not establish fullscreen coverage. Deliver both or explicitly document an agreed exception. Architecture owns the sharing boundary; the visual spec owns each surface's interaction and layout.
- Verify behavior in the source before documenting it. State limitations and distinguish measured results from assumptions. Preserve an existing document's structure and voice.
- Keep current behavior and its rationale in the relevant domain document, measurement
methods and dated results in
docs/spikes/, and task status and execution history in Backlog.ROADMAP.mdsummarizes capability and scope; it is not a second task queue. Completed plans, review findings and mockups are evidence for their recorded version, not implementation instructions. - Comments explain constraints or intent that the code cannot show. Avoid narrating the next
line or describing the history of a diff. UI copy follows
design-system.md. - Report what changed, what was checked and any remaining limitation. Scale detail to the work.
The frontend-design skill is available in .agents/skills/ for Codex and .claude/skills/
for Claude Code. Keep both copies aligned. Winnow's visual spec and tokens govern app changes.
Historical plans and decision records provide context, not additional active agent instructions.
The Codex Backlog hook checks direct apply_patch edits; the Claude hook checks direct file
edits. Neither guards every possible shell or tool write. The Backlog CLI rule below applies
to all editing methods. If backlog is missing from PATH, check the installed npm executable
(on Windows, %APPDATA%\npm\backlog.cmd) before installing anything. If it cannot run,
report the limitation and leave Backlog files untouched.
Conventions
- Use domain agents for bounded work that benefits from delegation. Keep small changes local. Give each agent its scope, owned files and relevant charter; concurrent agents must preserve one another's edits. The coordinating agent owns integration and verification.
Directory.Build.propssets nullable, implicit usings andTreatWarningsAsErrors.- Build and test with
dotnet buildanddotnet testfrom the repository root. - CI runs full Windows Release build/test and Linux session checks for pull requests. On
mainand releases, the same required jobs may reuse full-test evidence from the last 24 hours only when checkout provenance, complete source tree, resolved SDK, runner image and restored dependencies match. Missing or invalid evidence runs full tests. Restore/audit and migration checks stay fresh; warnings fail the gate. Seedocs/releases.mdfor the evidence contract. Windows CI and Linux session checks are required bymainbranch protection. Changes reachmainthrough an up-to-date pull request; this also applies to administrators. No additional approving reviewer is required. Force pushes and branch deletion are disabled. Migration integrity usesscripts/Verify-Migrations.ps1. For a new migration, append its SHA-256 tosrc/Winnow.Data/Migrations/hashes.json: UTF-8 text without BOM, CRLF normalized to LF, all other whitespace retained. Never replace an existing entry. Verify with./scripts/Verify-Migrations.ps1 -BaselineRef HEAD; mutation tests are inscripts/Test-MigrationHashes.ps1. - Windows CI prints completed tests and retains TRX plus hang diagnostics. A focused fullscreen Home layout preflight runs first to report layout failures before the longer database suite. Both stages retain results, and reusable evidence still requires the full suite. A five-minute test inactivity timeout captures a mini dump so a stalled host can be investigated. The job summary lists per-assembly timing and the slowest test cases. Feature branches run through the pull-request trigger rather than duplicating the same Windows and Linux jobs on both push and pull request. The job has a 45-minute overall budget to accommodate slower runners while keeping that inactivity check in place.
- A separate Ubuntu CI job runs
tests/Winnow.Monitor.Linux.Testsagainst real native processes and a synthetic Proton environment. A two-minute test inactivity timeout captures a mini dump alongside its TRX results. Those tests explicitly skip on non-Linux hosts. - Release packaging lives in
packaging/;docs/releases.mdowns build and publication instructions. Tag releases must pass the reusable CI gate and both installer smoke checks before creating a draft release. Smoke scripts install only on disposable GitHub runners. - Run with
dotnet run --project src/Winnow.App.-- --seed-sampleseeds demo data. - For any run where you might click something, pass
-- --data-dir <path>to redirect the database, sidecars, covers, themes and WebView2 profile to a throwaway directory. Otherwise clicks write to the real library. An unusable path is refused at startup with exit code 2; it never falls back silently. Setting%LOCALAPPDATA%does not work, becauseEnvironment.GetFolderPathuses the Windows shell API and ignores it. - A startup failure — migrations, hosted services, framework initialization — is caught,
logged and shown to the user (on the console when there is one, otherwise a message box),
and leaves exit code 3, distinct from the
--data-dirrefusal's 2. - If the app is running it holds a lock on the output assemblies. Build to a scratch path
instead:
dotnet test -p:BaseOutputPath=C:\Temp\winnow-verify\. - Commit at milestone boundaries. The database lives at
%LOCALAPPDATA%\Winnow\winnow.db. - Never write to any Steam, Epic or GOG file. Copy before reading anything live.
- Sanitize any new fixture with fake account ids.
<CRITICAL_INSTRUCTION>
Backlog.md Workflow
This project uses Backlog.md for task and project management.
For every user request in this project, run backlog instructions overview before answering or taking action.
Use the overview to decide whether to search, read, create, or update Backlog tasks.
Before task lifecycle actions, read the matching detailed guide:
backlog instructions task-creationbefore creating or splitting tasksbacklog instructions task-executionbefore planning, changing status or assignee, adding a plan or implementation notes, or implementing task workbacklog instructions task-finalizationbefore checking acceptance criteria, writing final summaries, or moving tasks to terminal statuses
Use backlog <command> --help before running unfamiliar commands. Help shows options, fields, and examples.
Do not edit Backlog task, draft, document, decision, or milestone markdown files directly. Use the backlog CLI so metadata, relationships, and history stay consistent.
</CRITICAL_INSTRUCTION>