From 748921dc9003aebe63d91d99fd811b9ed9a9abfa Mon Sep 17 00:00:00 2001 From: Gustavo Hariel Date: Sun, 31 May 2026 18:49:05 -0300 Subject: [PATCH] feat(agent): friction-ladder plan steering + install gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorients the propose skills toward "default to nothing, climb a friction ladder reluctantly" — Linux gaming is stable now and most games, even old ones, run on stock Proton. Changes are skill-only (plus two CLI wrinkles found while dogfooding AC Revelations on Deck). Skills: - funfa/SKILL.md: add the friction ladder (rung 0 nothing/stock Proton -> 1 env var -> 2 in-Steam Proton version -> 3 GE/installs) and a categorize-the-issue step where category predicts the expected rung; tighten PHASE 0 to require a same-game (appid/slug) match so an unrelated prior plan no longer mislabels the new one as "revisiting". - game-research/SKILL.md: add umu-protonfixes as the maintained anchor source; prune obsolete vars (PROTON_NO_ESYNC/FSYNC, DXVK_ASYNC, PROTON_USE_WINED3D); prefer official Valve Proton over GE; add the install gate (GE is rare-but-legitimate, must justify which Valve versions were checked and why they fail) plus native-dead->workaround and Deck-as-fixed-hardware weighting. - plan/SKILL.md: inline provenance (confirmed-date/Proton/Deck) on high-tier recs, order by friction, demote the GE example to a last-resort and require a Notes line clearing the install gate. CLI fixes (found dogfooding): - core/review-plan.ts: under --bypass-confirms, skip the framed review copy and footer so the plan renders once (the caller prints the clean pasteable markdown); interactive review/paste-back unchanged. Verified end-to-end via the codex path with FUNFA_FAKE_HARDWARE against AC Revelations (201870): fresh-plan labelling correct, single render, and GE recommendations now carry an explicit Valve-ladder justification. Co-Authored-By: Claude Opus 4.8 --- apps/cli/src/__tests__/review-plan.test.ts | 12 +++ apps/cli/src/core/review-plan.ts | 10 ++- apps/cli/src/skills/funfa/SKILL.md | 98 ++++++++++++++++++---- apps/cli/src/skills/game-research/SKILL.md | 84 ++++++++++++++++++- apps/cli/src/skills/plan/SKILL.md | 51 +++++++++-- 5 files changed, 224 insertions(+), 31 deletions(-) diff --git a/apps/cli/src/__tests__/review-plan.test.ts b/apps/cli/src/__tests__/review-plan.test.ts index 6307e66..562e6e6 100644 --- a/apps/cli/src/__tests__/review-plan.test.ts +++ b/apps/cli/src/__tests__/review-plan.test.ts @@ -97,6 +97,18 @@ describe("runReviewFlow", () => { expect(outcome).toBe("accepted"); expect(calls).toEqual([]); }); + + test("bypassConfirms prints nothing — the caller renders the plan", async () => { + const { prompts } = makePrompts(true); + const out: string[] = []; + await runReviewFlow( + { appid: "289070", markdown: samplePlanMarkdown }, + (s) => out.push(s), + prompts, + { bypassConfirms: true } + ); + expect(out).toEqual([]); + }); }); describe("isUserAbort", () => { diff --git a/apps/cli/src/core/review-plan.ts b/apps/cli/src/core/review-plan.ts index b2f3a31..315010b 100644 --- a/apps/cli/src/core/review-plan.ts +++ b/apps/cli/src/core/review-plan.ts @@ -34,13 +34,17 @@ export const runReviewFlow = async ( prompts: ReviewPrompts = defaultPrompts, opts: ReviewOptions = {} ): Promise => { + // With confirms bypassed there is no review to render — the framed copy + // and the "accept… or decline" footer would be noise, and the caller + // prints the clean pasteable markdown anyway. Skip straight to accepted. + if (opts.bypassConfirms) { + return "accepted"; + } + out(renderHeader(input.appid)); out(input.markdown.endsWith("\n") ? input.markdown : `${input.markdown}\n`); out(renderFooter()); - if (opts.bypassConfirms) { - return "accepted"; - } const accepted = await prompts.confirm({ default: false, message: "Accept this plan?", diff --git a/apps/cli/src/skills/funfa/SKILL.md b/apps/cli/src/skills/funfa/SKILL.md index f2096ea..84e08da 100644 --- a/apps/cli/src/skills/funfa/SKILL.md +++ b/apps/cli/src/skills/funfa/SKILL.md @@ -22,20 +22,35 @@ from the name. ### PHASE 0 — check for an existing plan -If the user prompt has an `Existing plans on disk` block, scan it for -an entry whose `appid` or `summary` matches the requested game. +The user prompt may include an `Existing plans on disk` block listing +prior plans by `appid` and `summary`. Decide whether any is for THIS +game before doing anything else: -- **Match → reuse path.** +1. Identify the requested game's identifier — its Steam appid (use your + catalogue knowledge; e.g. Assassin's Creed Revelations is `201870`) + or, for a non-Steam game, its slug. +2. A prior plan **matches only when it is the same game** — its `appid` + equals the requested game's appid/slug. A shared franchise, series, + or title substring is NOT a match: a prior `48190` (Assassin's Creed + Brotherhood) plan does not match a request for Assassin's Creed + Revelations (`201870`). When in doubt, treat it as no match. + +- **Same-game match → reuse path.** 1. Load the "hardware" skill and re-run each probe command. If GPU vendor/model/VRAM, driver, kernel, or distro changed since - the prior plan was written, jump to the re-analyse path. + the prior plan was written, take the re-analyse path below. 2. Otherwise: skip `/game-research`, proceed to PHASE 2 with the - prior plan's body as your starting point. The new plan's - `summary` should mention reuse: `reused prior plan : ...`. - The `/plan` skill describes how to render the reuse case. -- **Match but hardware drifted, or no match → re-analyse path.** - Continue to PHASE 1 normally. If a prior plan existed, mention it - in the new plan's `summary` (`revisiting prior plan : ...`). + prior plan's body as your starting point, and prefix the new + plan's `summary` with `reused prior plan : ...`. The + `/plan` skill describes how to render the reuse case. +- **Same-game match but hardware drifted → re-analyse path.** Continue + to PHASE 1 normally and prefix the new `summary` with + `revisiting prior plan : ...`. +- **No same-game match → fresh plan.** When no prior plan is for this + game (none on disk, or only plans for other games), continue to + PHASE 1 normally with an ordinary `summary`. Do NOT add a `reused`/ + `revisiting` prefix and do NOT reference another game's appid — those + labels are only for a prior plan of the *same* game. ### PHASE 1 — investigate @@ -70,18 +85,63 @@ an entry whose `appid` or `summary` matches the requested game. 5. Compose the plan as a markdown string per the `/plan` skill: - Frontmatter with `appid` and a one-line `summary`. - The launch-options line (env vars first, sorted by KEY, then - `%command%`, then launch args). Prefer LOW-tier reversible - fixes (env vars, launch args) over HIGH-tier (downloaded - binaries, registry edits, Proton-GE installs). + `%command%`, then launch args). Climb the **friction ladder** + (below) only as far as a documented issue forces you, and stop at + the lowest rung that fixes it. - High-tier recommendations as bullets, each with a source URL and a step-by-step instruction paragraph the user can follow without further context. Prefer trusted sources from the - `/game-research` skill (PCGamingWiki, doitsujin/dxvk, - HansKristian-Work/vkd3d-proton, GloriousEggroll/proton-ge-custom) - when one is available — the user has no post-hoc trust UI - anymore, so the source URL itself does the signalling. + `/game-research` skill (PCGamingWiki, umu-protonfixes, + doitsujin/dxvk, HansKristian-Work/vkd3d-proton, + GloriousEggroll/proton-ge-custom) when one is available — the user + has no post-hoc trust UI anymore, so the source URL itself does + the signalling. - Notes for hardware constraints, reuse rationale, or ProtonDB-flagged caveats. + +## The friction ladder + +Linux gaming is stable now — most games, even old ones, run on the +**stock Proton** Steam already ships. Your default assumption is that +the game works as-is. Climb this ladder only as far as a documented +issue forces you, and stop at the lowest rung that fixes it: + +0. **Nothing — stock Proton.** The common, *correct* outcome. If no + source documents a real issue on current Proton, the launch-options + block is the "paste nothing" line and you say plainly that the game + works as-is. That is a finished plan, not a failure. +1. **A launch-options env var or arg.** Zero install, reversible, + paste-and-go — funfa's sweet spot for the rare nitpick. One + well-justified var, not five collected ones. +2. **A different in-Steam Proton version.** Selecting Proton + Experimental, the Hotfix build, or an older Steam-provided Proton is + a zero-install in-client toggle. Exhaust these before any download. +3. **Proton-GE or other installed binaries.** A genuine but rare last + resort — not forbidden. Warranted only when recent, high-confidence + evidence shows that *only* a GE build fixes the issue and no official + Valve Proton (stock, Experimental, Hotfix, a specific older version) + does. The bar is evidence, not prohibition. Clear the `/game-research` + install gate first: name which Valve versions you checked and why + they fail, in the plan's Notes. + +Never recommend a higher rung when a lower one is documented to work. A +controller or performance issue that resolves into a Proton-GE install +should look suspicious — re-check rungs 0–2 first. + +## Categorize the issue first + +Before proposing anything, name what (if anything) is actually broken. +The category predicts how far up the ladder you should expect to climb; +a category landing higher than expected is a signal to re-examine. + +- **Works on stock** → rung 0. Most games. Finish here. +- **Controller / input** (especially Steam Deck) → rung 0–1: an + in-game setting, a Steam Input layout, or a single env var. Almost + never GE. +- **Performance** → rung 0–1: an env var, or "it's the engine — nothing + to do." Be honest when there is no fix. +- **Crash / launch failure** → the one category that may legitimately + reach rung 2–3. 6. Submit the plan for the user's consent, carrying the `appid` and the `plan_markdown`. Then stop — emit no further text and take no further action. The CLI owns every user-facing output from here, @@ -91,6 +151,10 @@ an entry whose `appid` or `summary` matches the requested game. ## Rules - Do not invent settings. If no source documents a fix, omit it. +- A plan that recommends nothing is the common, correct outcome on + current Proton — "this game works on stock Proton, paste nothing" is + a finished plan. Do not climb the ladder or add env vars to look + busy; an unnecessary var can break a game that already worked. - Use hardware facts to disqualify mismatched advice. - System-wide changes (kernel parameters, user systemd units, packages outside the prefix) are out of MVP scope. diff --git a/apps/cli/src/skills/game-research/SKILL.md b/apps/cli/src/skills/game-research/SKILL.md index 34362c4..d30c3f5 100644 --- a/apps/cli/src/skills/game-research/SKILL.md +++ b/apps/cli/src/skills/game-research/SKILL.md @@ -14,6 +14,15 @@ internet searches for the sources and query templates below. ## Trusted sources +- `https://github.com/Open-Wine-Components/umu-protonfixes` — the + maintained, code-level per-game fix database (look under + `gamefixes-steam/.py` and the sibling store folders). Because + it is actively maintained and keyed by appid, it is a higher-signal + **anchor** than any forum upvote: check it first, then use the + sources below to corroborate or extend it. It covers the env/launch + class of fix (it can set `PROTON_PREFER_SDL=1`, DLL overrides, etc.); + it does NOT cover Steam Input controller layouts — those are + client-side, so a forum/community-layout source still owns that case. - `https://www.protondb.com/app/` — community tier reports. Includes user reports with launch-options strings, env vars, and Proton version pinning. The aggregate tier (Native / Platinum / @@ -116,6 +125,62 @@ Use the facts from the `/hardware` skill to drop mismatched advice: If a fix is GPU-agnostic (most DXVK and WINE env vars), keep it. +## Prune obsolete fixes — do not accumulate + +Linux gaming is stable now; most games run on the stock Proton Steam +ships. So every env var must earn its place against the do-nothing +baseline: *would current stock Proton already handle this without the +var?* Many of the most-repeated fixes from old threads are now useless +or actively harmful. Drop these unless a **recent** source documents +them as still necessary for this specific game: + +- `PROTON_NO_ESYNC` / `PROTON_NO_FSYNC` — old workarounds; usually just + cost performance on current Proton. +- `DXVK_ASYNC=1` — superseded by DXVK's GPL pipeline-cache path; not in + mainline DXVK anymore. +- `PROTON_USE_WINED3D=1` — forces the slow OpenGL path; almost always + wrong today. + +A single env var you can defend beats five you merely collected. An +unnecessary var can break a game that already worked on stock Proton. + +## Proton version: prefer what Steam already ships + +When research points to a Proton-version change, prefer the lowest- +friction option that the reports confirm: + +1. Stay on the game's current stock Proton if it works — no action. +2. A different **official Valve** Proton (Proton Experimental, the + Hotfix build, or a specific older Steam-provided Proton version) is + a zero-install in-client toggle. Recommend these before any + download. In practice this ladder almost always works eventually — + most games run on stock, and the rest are fixed by Experimental, + Hotfix, or pinning a specific Valve Proton version. +3. Proton-GE / other installed binaries — a genuine but **rare** last + resort. It requires installing software, so it has to clear the gate + below. + +### The install gate + +Before recommending any install (Proton-GE, a downloaded binary), you +must be able to state — and you WILL state it in the plan's `## Notes` +— which official Valve Proton versions you checked for this issue +(stock, Experimental, Hotfix, a specific older Valve version) and why +each does not resolve it. When a report names a GE fix, actively check +whether the same fix is already available in a Valve Proton before +recommending the install. + +GE is **not banned.** When you have recent, **high-confidence** evidence +that *only* a GE build fixes the issue — e.g. a fix merged into GE that +upstream Valve Proton has not yet picked up, corroborated by recent +reports — recommending GE is the correct call. Flag it clearly and cite +the evidence. The bar is high confidence, not prohibition. + +But if you cannot name why the Valve options fail, you have NOT cleared +the gate: drop the install and recommend the Valve path instead. A +controller or performance issue resolving into an install is the +classic sign the gate was skipped — re-check the Valve ladder first. + ## Steam Deck If `/hardware` detected a Steam Deck (`/etc/os-release` `ID=steamos` @@ -135,9 +200,22 @@ Linux desktop: layouts are broken and only a keyboard-mapped layout works, that caveat IS the recommendation — state it, don't soften it into "pick the controller profile in the in-game menu." -- Prefer Deck-appropriate Proton (Proton Experimental / the Deck - hotfix, or a GE-Proton build reports confirm) over desktop-only - advice. Note when a specific GE-Proton version regressed the fix. +- **The Deck is fixed hardware** — same APU, SteamOS, gamescope, and + always-on Steam Input for every user. So a Deck-confirmed report + transfers cleanly: a single *recent*, dated "works on Deck" report is + close to authoritative for this user, far more so than a desktop + report (where another user's GPU/distro/compositor tells you little). + Weight one recent Deck-confirmed fix accordingly. +- Prefer Deck-appropriate Proton via the friction ladder: stock Proton, + then an **in-Steam** version (Proton Experimental / the Deck hotfix) — + zero install. Reach for a GE-Proton build only when reports confirm + it fixes a specific crash and nothing in-Steam does. Note when a + specific Proton version regressed the fix. +- If recent reports say the **native** path (controller, renderer) is + broken on current SteamOS and none confirm it still working, the + workaround becomes the *headline* recommendation, not a fallback + footnote — do not parrot the obsolete native fix because it is the + most up-voted. State plainly "the native path is dead, use X." A Deck plan whose launch-options line is empty but whose high-tier section gets the controller working is a GOOD plan — the input fix is diff --git a/apps/cli/src/skills/plan/SKILL.md b/apps/cli/src/skills/plan/SKILL.md index 4e8b1ae..0f80c09 100644 --- a/apps/cli/src/skills/plan/SKILL.md +++ b/apps/cli/src/skills/plan/SKILL.md @@ -51,7 +51,8 @@ for the game. > Apply these yourself — funfa does not run them. -- **** — []() +- **** — []() *(confirmed + on , )* - @@ -121,11 +122,30 @@ DXVK_HUD=fps DXVK_LOG_LEVEL=warn PROTON_NO_ESYNC=1 %command% ### High-tier recommendations -These are downloaded binaries, Proton-GE installs, registry edits, -**Steam Input controller-layout changes**, anything outside the -prefix that the user applies by hand. The CLI never executes them — -the user must read and apply them. So each bullet must be **readable -on its own**. +These are zero-install in-client toggles (switching to an in-Steam +Proton version, a **Steam Input controller-layout change**), and — only +as a last resort — downloaded binaries, Proton-GE installs, or registry +edits. The CLI never executes them — the user must read and apply them. +So each bullet must be **readable on its own**. + +Order bullets by friction: the zero-install fixes first, any install +last. Recommending an install (Proton-GE, a downloaded binary) is the +top rung of the friction ladder — rare but legitimate when the +evidence is strong. The bullet must name the exact issue it resolves, +and a `## Notes` line must clear the `/game-research` install gate: +state which official Valve Proton versions you checked (stock, +Experimental, Hotfix, a specific older version) and why each does not +fix it. An install bullet with no such Notes line is unjustified — drop +it and recommend the Valve path. If a controller or performance fix is +pushing you toward a GE install, that is the cue to re-check the Valve +ladder before committing. + +Add a short **provenance** annotation after the source link when you +have it: `(confirmed on , Deck/desktop)`. It +forces you to find how *current* the fix is — a fix last confirmed two +Proton releases ago deserves a Notes caveat — and lets the user judge +trust at a glance. Omit the annotation only when no source carries a +date; never fabricate one. For a Steam Deck controller fix, the high-tier bullet is the right place: name the exact community layout, say whether it is a gamepad or @@ -153,11 +173,26 @@ layout page when nothing more trusted documents it. you're walking a friend through the steps once: which tool, which menu, which version string, in what order. -**Example:** +**Preferred example — a zero-install in-Steam Proton switch:** ```markdown -- **Switch to Proton-GE 9-15 for shader-cache stability** — +- **Switch to Proton Experimental to fix the launch crash** — + [protondb.com](https://www.protondb.com/app/48190) *(confirmed + 2026-04 on Proton Experimental, Deck)* + - In Steam, right-click the game → Properties → Compatibility → + enable "Force the use of a specific Steam Play compatibility tool" + → pick `Proton Experimental` from the dropdown. No download — + Steam already ships it. Verify files, then relaunch. +``` + +**Last-resort example — a Proton-GE install (rare; name the exact +issue, and only when nothing in-Steam fixes it):** + +```markdown +- **Install Proton-GE 9-15 — fixes the videos-only-audio bug that no + Valve Proton resolves** — [github.com/GloriousEggroll/proton-ge-custom](https://github.com/GloriousEggroll/proton-ge-custom/releases/tag/GE-Proton9-15) + *(confirmed 2026-03 on GE-Proton9-15, desktop)* - Open ProtonUp-Qt (install via your package manager or Discover/AUR if missing). Choose Steam as the target, then install `GE-Proton9-15`. In Steam, right-click the game →