Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions apps/cli/src/__tests__/review-plan.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down
10 changes: 7 additions & 3 deletions apps/cli/src/core/review-plan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@ export const runReviewFlow = async (
prompts: ReviewPrompts = defaultPrompts,
opts: ReviewOptions = {}
): Promise<ReviewOutcome> => {
// 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?",
Expand Down
98 changes: 81 additions & 17 deletions apps/cli/src/skills/funfa/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <appid>: ...`.
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 <appid>: ...`).
prior plan's body as your starting point, and prefix the new
plan's `summary` with `reused prior plan <appid>: ...`. 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 <appid>: ...`.
- **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

Expand Down Expand Up @@ -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,
Expand All @@ -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.
Expand Down
84 changes: 81 additions & 3 deletions apps/cli/src/skills/game-research/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<appid>.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/<appid>` — community tier reports.
Includes user reports with launch-options strings, env vars, and
Proton version pinning. The aggregate tier (Native / Platinum /
Expand Down Expand Up @@ -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`
Expand All @@ -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
Expand Down
51 changes: 43 additions & 8 deletions apps/cli/src/skills/plan/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ for the game.

> Apply these yourself — funfa does not run them.

- **<short description>** — [<host>](<full URL>)
- **<short description>** — [<host>](<full URL>) *(confirmed <date>
on <Proton version>, <Deck|desktop>)*
- <one-paragraph step-by-step instruction, written as if telling a
friend who has Lutris/ProtonUp-Qt installed but no other context>

Expand Down Expand Up @@ -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 <date> on <Proton version>, 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
Expand Down Expand Up @@ -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 →
Expand Down
Loading