Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_016eTor2tpxKb4dXbd8RqnvZ
4.9 KiB
Working on this repo with Claude
CI runs on Gitea Actions at git.wallacenet.ca/devadmin/ProLibertateGames
(workflows in .github/workflows/), publishing to Cloudflare Pages
(plg.wallacenet.ca). The workflow below was measured on the dev machine
(~/ProLibertateGames); it replaces the earlier GitHub-sandbox notes, which no
longer apply.
Build, test and lint locally
Gradle works on the dev machine. Two environment variables are required: the default JDK is 25, which Gradle 8.14 cannot use, and the Android SDK lives in the home directory.
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export ANDROID_HOME=$HOME/android-sdk # platform 34, build-tools 34.0.0
./gradlew testDebugUnitTest lintDebug assembleDebug
The Katan tests run in seconds; a clean build takes a few minutes. Run the full
suite, lint and assembleDebug before pushing: they are what CI runs. There is
no KVM, so no emulator; the engine and the UI logic are covered by unit tests
(see docs/UI-catan.md).
Shipping: branch, PR, CI, merge
- Branch from
dev; before pushing, mergeorigin/devin (it moves between sessions). - Plain
git pushhas no credentials. Use the Gitea token as a one-off header:git -c "http.extraheader=Authorization: token $(cat ~/.config/gitea/token)" push -u origin <branch>. - Open the PR with
POST /api/v1/repos/devadmin/ProLibertateGames/pulls(same token,Authorization: token ...). CI (ci.yml) runs on the PR: build, unit tests and Android lint; it publishes nothing. Poll/actions/runsuntil it completes (about 7 minutes). - Merge with
POST .../pulls/N/merge {"Do":"merge"}. The push todevrunsci.ymlagain and publishes the build (about 9 minutes).
Merging is a shipping action
Both long-lived branches publish, so a merge is a release, not just an integration:
devpublishes av<series>.N-devbuild tohttps://plg.wallacenet.ca/dev/latest.json, offered by the in-app updater to anyone on the Dev channel.mainrunsrelease.ymland publishes a production release for everyone on the Production channel. Confirm before merging tomain.release.ymlrunsassembleDebugonly (no tests, no lint), so amainrelease is only as verified as thedevbuild it replays.
Katan
The island game is catalogue id catan, shown as Katan. It has two rule
sets chosen at setup: the base game (docs/RULES-catan.md) and Cities & Knights
(docs/RULES-catan-ck.md, code in game/catan/CatanCk*.kt, state behind
CatanState.ck, which is null in the base game). The screen is layered; see
docs/UI-catan.md before changing it.
Bash output is filtered before it reaches the model
.claude/settings.json registers a PreToolUse hook on Bash that rewrites
each command through rtk: git status runs as
rtk git status, and rtk compresses the output. Write commands normally — the
rewrite is transparent and costs nothing to invoke.
Measured on this repo rather than quoted from rtk's README:
| Command | Raw | Filtered | Saved |
|---|---|---|---|
git diff HEAD~3 |
521 KB | 28 KB | 95% |
grep -rn "fun " app/src/main |
117 KB | 19 KB | 84% |
find . -name "*.kt" |
7.7 KB | 1.7 KB | 79% |
git log -20 |
20 KB | 5.3 KB | 74% |
git diff --stat |
4.0 KB | 4.0 KB | 1% |
ls of a single package |
50 B | 62 B | −24% |
The saving is all in the large outputs, which is the point — a full diff of a
few commits is otherwise most of a context window. Already-compact output grows
slightly, because rtk adds a header; at those sizes it does not matter. rtk gain reports what the current session has actually saved.
Two limits are worth knowing. The Read, Grep and Glob tools are not
Bash, so they never reach the hook and are unaffected; a deliberate rg or
find in a shell is filtered. And filtering never truncates a file: cat
becomes rtk read, which was checked byte-for-byte against this repo's longest
Kotlin source (GameSetupScreen.kt, 946 lines) and came back identical. Commit
messages survive the rewrite intact, quotes and colons included. To bypass
filtering for one command, run rtk proxy <cmd>.
rtk is reinstalled at the start of every session
The container starts empty, so .claude/hooks/session-start.sh installs rtk
before the session does anything. It pins RTK_VERSION, because the installer
otherwise asks api.github.com for the latest tag and the proxy answers 403 for
every repository except this one — the lookup fails and takes the install with
it. Bump that variable by hand.
The hook is written not to matter when it fails. Outside the sandbox it installs
nothing and just prints the command to run, since dropping a binary into
someone's ~/.local/bin uninvited is not its business; if the download fails it
says so and exits clean. With rtk absent the rewrite hook no-ops, and the only
consequence is verbose output.