9.3 KiB
ORCHESTRATOR.md — Operating Manual for Successor Agents
You are taking over the autonomous development loop on SpaceWanderer (browser game: turn-based space adventure — build & expand your ship/base from found parts and resources, survive random encounters, manage a crew of flawed humans with good/bad traits; server-authoritative turn engine). Gameplay reference: Out There (Android), but more building-focused. This document captures operational knowledge that is NOT written down in AGENTS.md. Read AGENTS.md first — it defines the mandatory change process and this file complements it.
Credentials are deliberately NOT stored in this file — see §1 for where they live. Never paste token values into any tracked file.
1. Project identity
- Repo: Gitea at https://git.kkhost.pl → org OpenCode, repo SpaceWanderer (full name
OpenCode/SpaceWanderer). Every Gitea API/MCP call uses owner=OpenCode, repo=SpaceWanderer. - Local workdir + prod deploy dir:
/home/krzyw/projects/sandbox/space-wanderer(git checkout;docker compose up -d --builddeploys from here). - Prod URL (planned, not deployed yet): https://space-wanderer.dev.kkhost.pl (Traefik → docker-compose stack on this host); first deploy happens after the initial scaffold. Once live,
GET /api/versionreports the running version. - Gitea API access for git.kkhost.pl: prefer the gitea MCP tools — they are already configured with a token. For raw REST/curl, read the current token from the local .env file at repo root (variable
GITEA_TOKEN; .env is gitignored and must never be committed):source .env && curl -s -H "Authorization: token $GITEA_TOKEN" https://git.kkhost.pl/api/v1/user. (Incident note, Sept 2026: an early draft of the Flight-Ops doc committed a live token to the repo; that commit was purged from all refs and the token has since been rotated — never repeat this.) - Current user: kamilkrzywda (id 1).
- Current state: as of writing, the repo is empty (fresh
git init, no commits). Step zero for any successor: scaffold from../flight— copy architecture +.gitea/workflows/ci.yml+docker-compose*.ymlpatterns and adapt names — then this manual's loop applies.
2. The loop (per issue)
- Small incremental change on a feature branch off
master; connected issues may share one branch/PR with a single version bump. - Bump
package.jsonversion + add CHANGELOG.md entry at top:## v<version> — YYYY-MM-DD HH:MMthen bullet points of what changed (docs-only changes get patch bumps too). - Local verification ONLY (there are NO local e2e runs):
npx tsc --noEmit,npx vitest run(the whole unit suite must pass — the test count grows over time, so compare against the previous green run, never a hardcoded number),npx playwright test --list(all specs compile and list). - Push → CI (~7 min) → auto-merge on green (PRs have auto-merge configured; no manual merge needed — verify via
GET /pulls/{n}that state=closed and merged_at is set). Note: if a PR was created via API rather than create-on-push, double-check auto-merge actually fires. - Tag the version on master:
git tag v<version> origin/master && git push origin v<version>(aftergit fetch origin master). - Deploy prod in a PTY (long task):
cd /home/krzyw/projects/sandbox/space-wanderer && git checkout master && git reset --hard origin/master && docker compose up -d --build; then verifycurl https://space-wanderer.dev.kkhost.pl/api/versionreturns the new version and the root page is HTTP 200. - Close each issue with a comment: what changed, version, PR number, merge commit SHA, deployed URL.
- Repeat for the next open issue:
GET /issues?state=open&type=issues— note Gitea lists pull requests in this endpoint too; filter out entries with apull_requestkey.
3. Gitea API + MCP quirks (learned the hard way)
- The gitea MCP tools work for issues/PRs/files/tags, and Actions endpoints work IF you pass owner=
OpenCode, repo=SpaceWanderer. A wrong owner/repo makes EVERY call return{"message":"not found","url":"https://git.kkhost.pl/api/swagger"}— that swagger URL inside a 404 is the signature of "wrong path", not "Gitea is down". - MCP merge endpoint 405s → don't bother; auto-merge handles merging. Manual fallback if ever needed:
POST /repos/OpenCode/SpaceWanderer/pulls/{n}/mergewith body{"do":"merge","merge_style":"merge"}. - Gitea REST shapes (NOT GitHub's): list runs →
{workflow_runs:[...]}; run jobs →/actions/runs/{id}/jobsreturns{"jobs":[...]}; single job log via MCPget_job_log_preview(param tail_lines) ordownload_job_logto a file, then grep. - Failure anatomy in CI logs: the Playwright summary at the end lists "N failed" + test titles; each failure block has a code frame with line numbers plus an "Error Context:" path. The e2e step is the only one that can fail flakily; unit failures are real regressions.
- CI watcher pattern that works:
run_background_process(notify=true) running a loop that pollsGET /actions/runs/{id}every 60 s and exits when status=completed, printing status+conclusion each tick. Don't poll in the foreground; don't sleep-loop on pty_read.
4. CI facts (.gitea/workflows/ci.yml + docker-compose.ci.yml)
- Mirrors Flight-Ops: single job "build + unit + e2e" on runner gitea-runner (docker-in-docker). Fresh DB per run (volume removed); compose project
space-wanderer-ci; app container on a static IP →E2E_BASE_URL=http://<static-ip>:3000(exact IP TBD when scaffolding — copy../flight/.gitea/workflows/ci.yml+docker-compose.ci.ymland adapt);PW_REMOTE_BROWSER=0(CI runs local chromium — the shared remote browser server at 192.168.1.4 cannot reach a stack inside dind);E2E_COMPOSE_ARGS="-f docker-compose.ci.yml -p space-wanderer-ci"is read by e2e/state.spec.ts for its mid-rundocker compose restart. - Flaky uplink → retry loops in ci.yml; an occasional "flaky" test (failed once, passed on retry) does NOT fail the run.
- Branch protection requires status check
CI / build + unit + e2e (pull request)— PRs cannot merge until green; CI never deploys to production.
5. E2E conventions (e2e/*.spec.ts) — read before touching tests
- workers=1, serial in playwright.config.ts.
- expect.poll callbacks must be total — a throw inside fails the test instantly instead of retrying. Guard/filter everything you dereference.
- Deterministic dev hooks:
window.__*exposed in dev builds +/api/test/*endpoints behind an env flag deliberately NOT set in prod. - Turn-based game → actions resolve synchronously server-side, so tests are inherently more deterministic than Flight-Ops's real-time sim; no pause-sim pattern needed.
6. Game-specific gotchas
- None recorded yet — this is where hard-won knowledge accumulates as it is discovered. (Flight-Ops's equivalent sections documented Playwright evaluate serialization dropping prototype getters and MapLibre tile quantization — expect similar "the tool lies to you" surprises with whatever rendering approach lands.)
7. App architecture quick map
- TARGET ARCHITECTURE — code not written yet; scaffold from
../flight. - Next.js 16 App Router + React 19 + TypeScript strict, bun package manager (bun.lock), Node 22 in CI/Docker.
- SQLite via Drizzle ORM + sql.js (WASM, kept external in next.config.ts) at db/space-wanderer.db volume-mounted; schema designed to switch to Postgres later.
- Vitest unit tests colocated (
**/*.test.ts); Playwright e2e ine2e/, CI-only. - Server-authoritative TURN engine in lib/ — unlike Flight-Ops there is NO tick loop or sim clock: state advances only when a player action resolves a turn, and every action endpoint returns the full post-action snapshot which the client applies immediately (polling optional/later for multiplayer).
- Plain React hooks for client state, no external store; session via stored id + custom header.
- Dev/e2e hooks:
window.__sw*in dev builds +/api/test/*behind env flag not set in prod. - Core game systems to build: turn engine, random encounter resolution, ship module grid (build/expand from found parts), resource management, crew with good/bad traits.
8. Finding current state (this file keeps no snapshots)
This manual is meant to stay valid long-term, so it deliberately contains NO version or issue snapshots — they rot. To orient yourself when you take over: git log --oneline -10 + CHANGELOG.md for what has shipped; GET /issues?state=open&type=issues (filter out entries with a pull_request key) for what is left to do; PLAN.md's "Later" section for the roadmap backlog. Note: PLAN.md does not exist yet — it will be the game design doc.
9. Standing user instruction & etiquette
- The user's standing order for this project: work through the issue list autonomously — implement → PR → CI green → merge → tag → deploy prod → close with comment → next — until told to stop.
- Small incremental changes; each part fully tested (unit + e2e) before moving on.
- Long terminal tasks → pty_* tools (deploys, builds). Background watchers → run_background_process with notify=true.
- Never push directly to master; never deploy from a feature branch; CI never touches prod — production deploys are manual only (
docker compose up -d --buildafter tagging). - Never commit credentials. Tokens/secrets live in the MCP server config or with the user, never in tracked files (see incident note in §1).