> For the complete documentation index, see [llms.txt](https://docs.kouch.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kouch.dev/docs/adr/0013-steam-cloud-api-only.md).

# ADR 0013: Steam Cloud through the API only, no Auto-Cloud

## Status

Accepted on 2026-09-26. This reverses PLAN\_V2 Phase 4's first choice and the part of ADR 0012 that pointed the `saves\<emu>` junction into Steam's own `userdata\<account>\<app id>\remote` folder.

## Context

Phase 4 wanted cloud-safe data (saves, states, screenshots, config) to sync per Steam user. The plan's first idea was to junction `saves\<emu>` into Steam's `remote` folder and let Steam's Auto-Cloud upload whatever lands there, with the Steam Cloud API as the fallback.

An audit of `cloud.rs` while getting ready for Kouch's own app id (B, `3c31ec9`) showed that Auto-Cloud can't meet two hard requirements:

* **Ground rule 2.** Auto-Cloud uploads every file under its roots. It can't honour `system`, a profile's `user_data.private` globs (`66ce863`), or the refusals of `..` names and unknown folders. Kouch has to decide per file what leaves the PC.
* **No silent overwrites.** When a save changed on two PCs, Auto-Cloud keeps one side. Kouch must keep both.

The same audit found data-loss bugs in the old API path:

* blind overwrites in both directions
* re-uploads forever, because downloads got "now" as their mtime
* ignored commit results, quota and the Cloud-disabled state
* a startup sync that ran before the Steam user was known

## Decision

* **API only.** Kouch syncs through ISteamRemoteStorage from a `CloudBackend` trait (`app/src-tauri/src/cloud_sync.rs`). Nothing relies on files dropped into Steam's `remote` folder, and no Auto-Cloud roots are configured in Steamworks.
* **Local layout.** `saves\<emu>` stays a junction, but into Kouch's own `<config>\cloud\<steam id>\…`. That keeps each Steam user's data apart on one PC, as ADR 0012 wanted.
* **Change detection is three-way** against a per-user record (`<config>/cloud-state/<steam id>/<profile>.json`).
  * When a file changed on both sides, both copies are kept: the newer keeps the name, the older becomes `<file>.conflict-<unix s>`, which is never uploaded, and the user gets a toast.
  * Identical bytes don't count as a conflict.
* **Every file is checked on upload and on download:** `system`, `bios`, `private` globs, `..` and unknown folders are refused both ways. Quota, the per-profile cap and Steam's per-file limit stop the sync cleanly, with a toast.
* **Sync starts on Steam sign-in, not at startup.**
  1. Saves made before sign-in are adopted by the first user only.
  2. The junctions are re-pointed.
  3. Each profile that has cloud sync on downloads.
* **Steamworks settings:** 1 GB byte quota, 10,000 files, no Auto-Cloud roots. They're listed in `docs/RELEASE.md` "Steam Cloud: API only, no Auto-Cloud", together with a live checklist.

## Consequences

* Kouch owns correctness, so the sync engine is tested against an in-memory fake: 9 tests covering upload and download, a new PC, conflicts, quota, refusals and two users on one PC. Real Steam writes stay unverified until Kouch's app id exists.
* Steam's own cloud-conflict dialog never appears for Kouch; Kouch's toast and `.conflict-` files replace it.
* A user who only uses the legacy data layout (no Emulation folder) syncs for the first Steam user only; anyone else is told to set up the Emulation folder.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kouch.dev/docs/adr/0013-steam-cloud-api-only.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
