docs(ai): move agent rules to ai/skills and add an AI development sandbox (#1498)

The sandbox provides an isolated Docker environment for AI-assisted development
(OpenCode + Claude Code + Qwen Code) against the local AkkudoktorEOS repository.

The sandbox does not protect the repository from harmful changes by the agent.
It limits what a misled agent can reach on the machine, but the agent can still
write any change into the repository.

Primary security defence is to check every change before it is run on the host.
Same holds for opening a pull request or updating one.

Additional changes

- Reduce AGENTS.md to the project summary, baseline rules, completion checklist,
  and an index of the skills.
- Add skills for the Python environment and REST API error responses.
- Add the development guide page docs/develop/ai.md: the AI coding
  workflow, how agents get the project rules from AGENTS.md and ai/skills,
  and how to use the sandbox (start, agent logins, project commands with a
  virtual environment outside the workspace, running EOS and EOSdash,
  GitHub access, persistent data, security model).
- Add a checklist for reviewing agent changes before pushing, starting with
  .git, which stays writable in the sandbox.
- Check out all text files with LF line endings (.gitattributes), also on
  Windows with core.autocrlf, so the sandbox scripts run in the container
  and git in the container agrees with git on the host. Batch files keep CRLF.
- Publish the ports of ai/compose.yaml on request (AI_SANDBOX_PORTS=1).
  docker compose run publishes them only with --service-ports. Off by
  default, so that several sandboxes can run in parallel.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Bobby Noelte
2026-11-09 09:15:12 +01:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 628226d3d9
commit 2245976de4
21 changed files with 2041 additions and 150 deletions
+75
View File
@@ -0,0 +1,75 @@
# ai/Dockerfile
# AI development sandbox for AkkudoktorEOS.
# Runs as a non-root user whose UID/GID match the host to keep bind-mount ownership sane.
# uv comes from its official image. BuildKit does not expand variables in
# `COPY --from`, so the image is a named stage with a global ARG. Keep
# UV_VERSION in sync with .github/workflows/pre-commit.yml.
ARG UV_VERSION=0.12.9
FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv
FROM debian:bookworm-slim
ARG UID=1000
ARG GID=1000
ARG USERNAME=dev
# Pinned tool versions (UV_VERSION is above). Bump them and rebuild
# (AI_SANDBOX_REBUILD=1) to update.
ARG CLAUDE_CODE_VERSION=2.1.319
ARG OPENCODE_VERSION=1.19.5
ARG QWEN_CODE_VERSION=0.27.0
ENV DEBIAN_FRONTEND=noninteractive \
PYTHONUNBUFFERED=1 \
UV_LINK_MODE=copy \
PATH="/home/${USERNAME}/.local/bin:${PATH}"
# Base tooling: git, GitHub CLI and build tools. No sudo: the agent must not
# be able to become root, even if no-new-privileges were removed.
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
gh \
gnupg \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Copy the uv binary from the uv stage.
COPY --from=uv /uv /uvx /bin/
# Install Python 3.13 outside /root (mode 0700, unreachable for the dev user)
# and link it into /usr/local/bin, where uv finds it as an interpreter on PATH.
RUN UV_PYTHON_INSTALL_DIR=/opt/uv-python UV_PYTHON_BIN_DIR=/usr/local/bin \
uv python install 3.13 \
&& chmod -R a+rX /opt/uv-python \
&& /usr/local/bin/python3.13 --version
# Install Node.js 22.x (needed for the AI CLIs).
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
# AI CLIs as global npm packages (installed under /usr, readable for everyone).
RUN npm install -g \
"@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}" \
"opencode-ai@${OPENCODE_VERSION}" \
"@qwen-code/qwen-code@${QWEN_CODE_VERSION}" \
&& npm cache clean --force
# Create a non-root user matching the host UID/GID.
RUN groupadd -g ${GID} ${USERNAME} 2>/dev/null || true \
&& useradd -m -u ${UID} -g ${GID} -s /bin/bash ${USERNAME}
# Install the entrypoint into the read-only image layer, owned by root.
# It must NOT live under /home/dev: that path is the persistent `ai-home`
# volume, so a copy there would be shadowed by a stale file from the volume
# and would be writable by the agent.
COPY --chown=root:root --chmod=0755 entrypoint.sh /usr/local/bin/entrypoint.sh
USER ${USERNAME}
WORKDIR /workspace
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["bash"]