# AGENTS.md — OpenFUT **Read this first.** It is the entry point for AI-assisted work on OpenFUT. It supersedes the root `README.md` and `CLAUDE.md`, which are **stale** (they describe an earlier FIFA 23 plan). ## Project OpenFUT is a preservation / private-server project that restores **offline, single-player FIFA Ultimate Team (FUT)** after EA retired the online servers. You must own the game legitimately; the project does not bypass ownership checks — it only re-serves the dead online services locally. **Current active target: FIFA 17 (PC).** A clean-room emulation of the full online + FUT stack was proven working end-to-end on **2026-08-01** (auth → Blaze login → device-trust → FUT hub). This lives in `fifa17-recon/`. The FIFA 17 work is explicitly the **Rosetta Stone for FIFA 23** (identical Blaze/LSX/UTAS wire format), so FIFA 23 remains the eventual second target. Three moving parts, kept strictly separate: - **The FIFA client** — the retail game (FIFA 17 now). Unmodified except live cert-verify patches. - **The emulation layer** — Python responders in `fifa17-recon/tools/` (LSX, Blaze, UTAS, roster) that impersonate EA's online services on localhost. This is where all reverse engineering lives. - **OpenFUT Core** — a game-independent REST FUT economy backend (`openfut-core/`), feature-complete and tested. Knows nothing about FIFA. Intended to eventually back the emulation layer's FUT data. > The emulation layer and Core are **not yet wired together.** The FIFA 17 UTAS server currently > serves its own hardcoded/JSON payloads, not Core's API. See `docs/PROJECT_STATE.md`. ## Repository map Monorepo. `openfut-core`, `openfut-bridge`, `openfut-launcher`, `fifa-blaze` are **git submodules** (each with independent history — use `tea`/Gitea, not `gh`). `fifa17-recon/` is a plain directory. | Path | What it is | Status | |---|---|---| | `fifa17-recon/` | **The live path.** FIFA 17 offline FUT emulation: Python responders, cert patcher, runbook, RE write-ups. | Working | | `openfut-core/` | Rust (Axum + SQLite) FUT economy backend. Game-independent REST API. | Working, tested | | `openfut-bridge/` | Rust FIFA 23 in-process hook / proxy RE effort. | Blocked (see below) | | `fifa-blaze/` | Rust Blaze protocol emulator scaffold for FIFA 23 (capture stub). | Milestone 1 stub | | `openfut-launcher/` | Rust egui/eframe desktop launcher (targets FIFA 23 hook flow). | Legacy plan | | `docs/` | **Mirrors** of the vault (`OpenFUT-Vault`), which is canonical. Direction pivots + context. | — | | `tools/` | Host-side RE helpers (file-watch-diff, exporters, squad-injector) from the FLE-bridge idea. | Legacy plan | | `setup.sh` | FIFA 23 full-stack orchestrator (core+bridge). | Legacy plan | **Legacy vs live:** the project pivoted twice — (1) FIFA 23 Blaze backend → (2) FIFA 23 as a match renderer driven by an FLE Lua bridge (`docs/direction.md`) → (3) **FIFA 17 full online emulation, which succeeded and is now the primary path** (`fifa17-recon/`). Treat `openfut-bridge`, `openfut-launcher`, `fifa-blaze`, `tools/`, `setup.sh`, and `docs/direction.md` as historical unless a task explicitly targets the FIFA 23 port. ## Architecture (live path) ``` FIFA 17 client (Wine/Proton, base 0x140000000) │ autopatch.py NOPs two ProtoSSL cert-verify gates in /proc/PID/mem ├─ LSX 127.0.0.1:4216 → lsx_responder_v2.py (Origin login/profile/authcode) ├─ TLS 127.0.0.1:42127 → blaze_responder_v3b.py (Blaze redirector, via DNAT of 159.153.51.20) ├─ Blaze 42130 / Nucleus 42131 → blaze_responder_v3b.py (Fire2/Heat2 binary + login) ├─ easw.easports.com (→127.0.0.1) :8099 → utas_server.py (UTAS/RS4 FUT API + device-trust) └─ roster :8081 → roster_server.py (FUT roster-update XML) OpenFUT Core (openfut-core, :8080) ── clean REST FUT economy ── NOT YET CONNECTED to the above ``` Host arming (`root_arm.sh` via `pkexec`, volatile across reboot): `ptrace_scope=0`, `route_localnet=1`, iptables DNAT `159.153.51.20→127.0.0.1:42127`, `/etc/hosts easw.easports.com`. ## Development commands (verified) **FIFA 17 emulation** (from `fifa17-recon/tools/`): - Start everything (idempotent; re-run after reboot): `./openfut-fut.sh start` - Status / stop / restart: `./openfut-fut.sh status | stop | restart` - Then launch the game fresh (`~/Desktop/launch-fifa17.sh`) and pick Ultimate Team. - Logs: `/tmp/{lsx,blaze,roster,utas,autopatch}.log` - Full procedure + gate-ladder troubleshooting: `fifa17-recon/FUT-RUNBOOK.md` **OpenFUT Core** (from `openfut-core/`): `cargo run` (creates `openfut.db`) · `cargo test` (full in-memory integration suite; requires `data/`) · `cargo test ` for one · `cargo clippy -- -D warnings` · `cargo fmt`. Env: `LISTEN_ADDR` (127.0.0.1:8080), `DATABASE_URL` (sqlite://openfut.db), `DATA_DIR` (data). **Other Rust crates** (`openfut-bridge`, `fifa-blaze`, `openfut-launcher`): standard `cargo run/build/test/clippy/fmt` from within each. `fifa-blaze` is a workspace (`--bin blaze-server`). **CI:** only `openfut-core` has it (`.gitea/workflows/ci.yml`): `fmt --check`, `clippy -D warnings`, `build --locked`, `test --locked` on push/PR to main. No CI on the other crates or the recon dir. There is **no install step, no Docker, no JS/TS frontend, no typecheck** in this repo. Do not invent them. ## Coding conventions - **Rust (Core):** Axum 0.7 + SQLx 0.7 (SQLite, compile-time-checked queries). Strict layering — `routes/` (handlers, extract state, call services) → `services/` (own **all** DB access + logic) → `models/` (pure `Serde`/`FromRow` data). Errors via `AppError` (`src/error.rs`) with `IntoResponse`. One file per domain across `routes/`, `services/`, `models/`. **Single-profile design:** every service reads "the active profile" as the first DB row — intentional, don't parameterize it. Content is data-driven: JSON under `data/` loaded at startup into Arc registries in `AppState`. Add content by dropping JSON files, not code. Migrations are numbered SQL in `migrations/`. Keep `clippy -D warnings` and `fmt` clean (CI enforces). - **Python (recon):** stdlib-only servers, no framework. Each responder is a standalone script with the reverse-engineered contract documented in its module docstring (byte offsets, VAs, symbol names). When changing a responder, preserve byte-exactness — the client is the oracle. - **Clean-room, always.** Every finding derives from binaries we own + live observation. **Never** use, reference, or reproduce leaked EA source. If a task seems to need it, stop and say so. ## AI-agent rules 1. Read this file before exploring the repo. 2. Read the vault file relevant to the task (`../OpenFUT-Vault/`), not the whole tree. Repo `docs/` files are mirrors of the vault — consult them for the same content, but treat the vault as canonical. 3. Don't scan the whole repository unless the knowledge base is clearly stale — if you find it stale, update the vault, then its repo `docs/` mirror. 4. Search the specific directory (`fifa17-recon/`, `openfut-core/src//`) before a repo-wide search. 5. Update the vault when architecture materially changes (and sync the matching `docs/` mirror). 6. Don't refactor or rewrite unrelated working code. 7. Prefer small, testable changes; run the narrowest relevant test first (`cargo test `). 8. **Never invent EA/FIFA/Blaze protocol behavior.** Values you don't know are `TODO/CONFIRM`, not confident guesses. The live client is the only oracle for whether a gate is satisfied. 9. Clearly separate discovered behavior from hypotheses; record findings in `../OpenFUT-Vault/02 Reverse Engineering/FIFA 17/Protocol Findings.md` under the right confidence tier — never silently promote a hypothesis to a fact. 10. Root `README.md` / `CLAUDE.md` and `openfut-bridge/CLAUDE.md` describe superseded FIFA 23 plans; prefer vault + repository evidence over them when they conflict. ## AI Session Bootstrap Future agents should start with: 1. Read `AGENTS.md`. 2. Read the vault README (`../OpenFUT-Vault/README.md`) to locate the canonical files. 3. Identify the subsystem the task affects and read the corresponding vault file: Architecture, Project State, Roadmap/Current Priorities, or Protocol Findings. 4. Inspect only the relevant source directories. 5. Check `../OpenFUT-Vault/02 Reverse Engineering/FIFA 17/Protocol Findings.md` before assuming anything about FIFA/EA behavior. 6. Check `../OpenFUT-Vault/06 Agent Memory/Project State.md` before assuming a feature exists. 7. Implement the smallest coherent change. 8. Run the narrowest relevant tests. 9. Update the vault (and its repo `docs/` mirror) only if the change makes existing knowledge inaccurate. Do not reread the entire repository during every session. ## OpenFUT Knowledge Base **The OpenFUT Vault is the canonical project knowledge base.** Repo `docs/` files mirror it; the vault wins on any disagreement. Consult it before starting substantial work and update it after durable discoveries. Vault location: `../OpenFUT-Vault/` — start at `../OpenFUT-Vault/README.md`. Canonical files: - Dashboard: `00 Dashboard/OpenFUT.md` - Architecture: `01 Architecture/Architecture.md` (repo mirror `docs/ARCHITECTURE.md`) - RE findings: `02 Reverse Engineering/FIFA 17/Protocol Findings.md` (repo mirror `docs/research/KNOWN_FINDINGS.md`) - Direction history: `04 Decisions/Direction History.md` - Project State: `06 Agent Memory/Project State.md` (repo mirror `docs/PROJECT_STATE.md`) - Current Priorities: `06 Agent Memory/Current Priorities.md` - Known Issues: `06 Agent Memory/Known Issues.md` - Important Discoveries: `06 Agent Memory/Important Discoveries.md` - Roadmap: `08 Roadmap/Roadmap.md` (repo mirror `docs/ROADMAP.md`) When editing knowledge that exists in both places, edit the vault first, then update the matching `docs/` mirror so they stay in sync.