scaffold the Godot port, as its own repo with its own agent
The port is deliberately separate from the reverse-engineering project: its own repository, its own clone, its own container. Two writers in one working tree means files change under whoever is mid-edit and a `git add -A` by one sweeps up the other's work -- which happened today in the Reborn tree, so this is set up not to repeat it. The wall: Godot never reads a disc format. An offline Rust exporter converts the user's disc into JSON + PNG + Ogg, and the Godot project reads only that. No GDExtension, no Rust in port/. Beyond the practical reason -- Godot cannot read IPFB, RATC, T8aD, XMA or WMV -- there is the design one: modding is a goal, and if the runtime reads the original formats then modding means reverse engineering, whereas if it reads JSON it means opening a file. The decoders come from sylpheed-formats PINNED BY REVISION (8b6dbcf), not vendored and not reimplemented. `sylpheed_formats::media` in particular already owns every case where one playable thing is not one archive entry: entries that span segment files, banks with several sub-waves, and the cutscene voices, which are one continuous XMA stream chunked into VOICE_*.slb entries whose boundaries do NOT match the cues. That last one is the easiest thing in this project to get subtly wrong, so the mission says outright not to re-derive it. docs/MISSION.md is the objective (P0-P7, each gated by an artifact rather than by compiling). docs/BLOCKED.md lists what cannot proceed until the RE agent answers Q1-Q10, and says plainly that none of it may be guessed -- this agent has no emulator and no oracle, so a value it invents is indistinguishable from a decoded one a month later. The container is deliberately small: 3 cpus / 4 GB against the RE container's 6 / 7, and an image with no C++ toolchain, no Vulkan stack and no emulator. Two full-size containers do not fit on this box beside a desktop. Its launcher sets the git identity through GIT_AUTHOR_*/GIT_COMMITTER_* rather than writing [user] into .git/config -- the config route captures every commit made in that tree, including a human's, which is how six of today's commits ended up attributed to the RE agent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
100
docker/Dockerfile
Normal file
100
docker/Dockerfile
Normal file
@@ -0,0 +1,100 @@
|
||||
# Autonomous port agent for the Sylpheed Godot menu shell.
|
||||
#
|
||||
# DELIBERATELY SMALL. The reverse-engineering container next door is 4.36 GB
|
||||
# because it builds Xenia Canary and drives it under a software Vulkan stack.
|
||||
# This agent has no emulator, no oracle and no C++ build: it converts already-
|
||||
# decoded assets and drives Godot. Keeping it light is what lets both containers
|
||||
# run on one 12-core / 15 GB box without the memory pressure that has crashed it.
|
||||
#
|
||||
# What it needs, and nothing else: Rust (the exporter), Godot 4 (the runtime),
|
||||
# ffmpeg (the transcode), and a headless display to screenshot Godot for
|
||||
# comparison against the reference renderer.
|
||||
|
||||
FROM ubuntu:24.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
LANG=C.UTF-8 \
|
||||
TZ=Etc/UTC
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
# toolchain for the exporter and for building sylpheed-cli from /reborn
|
||||
build-essential pkg-config git curl ca-certificates \
|
||||
libssl-dev \
|
||||
# Godot 4 needs these even headless; the windowed run needs the X libs
|
||||
libx11-6 libxcursor1 libxinerama1 libxrandr2 libxi6 libgl1 \
|
||||
libasound2t64 libpulse0 libfontconfig1 \
|
||||
# the transcode target (libtheora + libvorbis ship in Ubuntu's ffmpeg)
|
||||
ffmpeg \
|
||||
# headless display + the screenshot path, for diffing Godot's output
|
||||
# against `sylpheed-cli screen render`
|
||||
xvfb x11-utils openbox imagemagick \
|
||||
# everyday
|
||||
python3 jq ripgrep unzip file less nano tini sudo procps \
|
||||
# expect drives Claude Code's one-time interactive gates
|
||||
expect \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# ── Godot 4 ──────────────────────────────────────────────────────────────────
|
||||
# Pinned. An engine version bump changes rendering, and this project compares
|
||||
# screenshots against a reference renderer — so an upgrade must be a deliberate,
|
||||
# stated act rather than a silent drift.
|
||||
ARG GODOT_VERSION=4.3
|
||||
RUN cd /tmp \
|
||||
&& curl -fsSLO "https://github.com/godotengine/godot/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" \
|
||||
&& unzip -q "Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" \
|
||||
&& mv "Godot_v${GODOT_VERSION}-stable_linux.x86_64" /usr/local/bin/godot \
|
||||
&& chmod +x /usr/local/bin/godot \
|
||||
&& printf '#!/bin/sh\nexec /usr/local/bin/godot --headless "$@"\n' > /usr/local/bin/godot-headless \
|
||||
&& chmod +x /usr/local/bin/godot-headless \
|
||||
&& rm -f "Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip"
|
||||
|
||||
# ── Node + Claude Code ───────────────────────────────────────────────────────
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& npm install -g @anthropic-ai/claude-code \
|
||||
&& npm cache clean --force \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# ── The agent user ───────────────────────────────────────────────────────────
|
||||
# NOT root: Claude Code refuses --dangerously-skip-permissions with root
|
||||
# privileges. Ubuntu 24.04 ships its own `ubuntu` account at uid 1000, so the
|
||||
# common case — matching a host user who is also 1000 — collides with it.
|
||||
ARG AGENT_UID=1000
|
||||
ARG AGENT_GID=1000
|
||||
RUN if getent passwd "${AGENT_UID}" >/dev/null; then \
|
||||
userdel -r "$(getent passwd "${AGENT_UID}" | cut -d: -f1)" 2>/dev/null || true; \
|
||||
fi; \
|
||||
if getent group "${AGENT_GID}" >/dev/null; then \
|
||||
groupdel "$(getent group "${AGENT_GID}" | cut -d: -f1)" 2>/dev/null || true; \
|
||||
fi; \
|
||||
groupadd -g "${AGENT_GID}" agent \
|
||||
&& useradd -m -u "${AGENT_UID}" -g "${AGENT_GID}" -s /bin/bash -d /sylph-home/port agent \
|
||||
&& mkdir -p /sylph-home/port /work /reborn \
|
||||
&& chown -R "${AGENT_UID}:${AGENT_GID}" /sylph-home \
|
||||
&& echo 'agent ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/agent
|
||||
|
||||
COPY bin/ /usr/local/bin/
|
||||
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/* /usr/local/bin/entrypoint.sh
|
||||
|
||||
USER agent
|
||||
WORKDIR /work
|
||||
|
||||
# CARGO_TARGET_DIR points OUTSIDE the bind-mounted repo so the host and the
|
||||
# container do not invalidate each other's incremental state on every switch.
|
||||
ENV RUSTUP_HOME=/sylph-home/port/.rustup \
|
||||
CARGO_HOME=/sylph-home/port/.cargo \
|
||||
CARGO_TARGET_DIR=/sylph-home/port/target-container \
|
||||
PATH=/sylph-home/port/.cargo/bin:/usr/local/bin:/usr/bin:/bin
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
||||
| sh -s -- -y --default-toolchain stable --profile minimal --component clippy --component rustfmt
|
||||
|
||||
RUN mkdir -p /sylph-home/port/target-container /sylph-home/port/.claude
|
||||
|
||||
ENV HOME=/sylph-home/port \
|
||||
DISPLAY=:97 \
|
||||
SCREEN_GEOMETRY=1280x720x24 \
|
||||
PROJECT_DIR=/work
|
||||
|
||||
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint.sh"]
|
||||
CMD ["bash"]
|
||||
Reference in New Issue
Block a user