Distill best practices from agent-runtimes M1-M3 memory files

12 additions/updates across 5 best-practice files:
- docker-uid-matching: userdel simplification, SSH agent socket UID match
- debugging: GIT_SSH_COMMAND scope limitation
- test-driven-development: subprocess mock gotcha, routing callables,
  Pydantic v2 field_validator defaults, sys.exit at module level
- spec-driven-development: multi-agent orchestration practices (commit WIP,
  self-verify, import conventions, assembly budget)
- validation: test pre-commit hooks after adding dependencies

Source: agent-runtimes/memory/ (decisions, gotchas-docker, gotchas-python,
process-lessons, m1/m2/m3 reflections)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul O'Reilly
2026-03-25 11:11:54 +13:00
parent e7c8214499
commit 1b5e73dc54
6 changed files with 91 additions and 16 deletions

View File

@@ -77,7 +77,9 @@ exec gosu "$AGENT_USER" "$@"
- **`gosu` over `su`/`sudo`.** `gosu` execs directly (PID 1 becomes the real process), while `su` creates a child process that breaks signal handling. `gosu` is the standard tool for this pattern.
- **Handle existing UIDs/GIDs.** The host UID may already be taken by another user in the container. Ubuntu 24.04 images ship with a `ubuntu` user at UID 1000 — the most common host UID. The wrapper must evict the conflicting user to a high unused UID (e.g., 59999 and search downward) before assigning the target UID to the agent user. `usermod -u <new> <conflicting_user>` followed by `usermod -u <target> agent`. Same applies to GIDs — use `getent group` to check before `groupmod`.
- **Handle existing UIDs/GIDs.** The host UID may already be taken by another user in the container. Ubuntu 24.04 images ship with a `ubuntu` user at UID 1000 — the most common host UID. The wrapper must evict the conflicting user to a high unused UID (e.g., 59999 and search downward) before assigning the target UID to the agent user. `usermod -u <new> <conflicting_user>` followed by `usermod -u <target> agent`. Same applies to GIDs — use `getent group` to check before `groupmod`. **Simpler alternative:** Delete the conflicting user at build time (`RUN userdel ubuntu` in the Dockerfile). This avoids runtime conflict handling entirely and is preferred when you control the image.
- **SSH agent socket forwarding requires UID match.** When mounting `$SSH_AUTH_SOCK` into a container, the socket is mode 0600 owned by the host UID. The container process must run as the same UID to use it — which the UID wrapper handles naturally. Set `SSH_AUTH_SOCK` in the container env to the mounted path. Note: private keys cannot be extracted via the agent protocol — it only supports signing operations.
- **Skip when not root.** In Kubernetes, `securityContext.runAsUser` sets the UID before the container starts. The wrapper detects this (`id -u != 0`) and skips adjustment — the platform is handling it.