Skip to content

Commit db9312a

Browse files
gatezhclaude
andauthored
feat(ralphex-fe): rebuild from Alpine to Debian (#45)
* fix(claude-code): add missing bun install to sandbox postCreateCommand - Without bun install, npx playwright fails due to npm 11 cache key mismatch between versioned build-time and unversioned runtime lookups Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add quality-of-life settings to devcontainer configs - updateRemoteUserUID, otherPortsAttributes (silent auto-forward) - editor.formatOnSave + OXC default formatter with customization guide - window.title for multi-window distinction, NODE_OPTIONS 4GB heap - Sandbox: Claude Dark theme, coral status bar, skip permissions - Plugins: frontend-design, typescript-lsp, playwright, posthog - Firewall: allow OpenAI domains (auth, api, chatgpt) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: restructure CLAUDE.md into path-scoped rules - Slim CLAUDE.md from 290 to 39 lines (core rules only) - Add .claude/rules/ with path-scoped files: dockerfile, devcontainer, workflows, new-image - Fix stale references: Biome→OXC, zsh→fish, remove AGENTS.md symlink mentions - Remove derivable content (directory tree, README patterns) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add implementation plan for ralphex-fe Debian rebuild Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(ralphex-fe): add entrypoint and credential copier scripts init.sh adapted from umputun/baseimage for Debian (gosu, groupadd/groupdel). init-docker.sh copied from umputun/ralphex (credential copying from mounts). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(ralphex-fe): rewrite Dockerfile from Alpine to Debian (node:24-trixie-slim) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ralphex-fe): update workflow for Debian-based image - Drop RALPHEX_VERSION extraction (binary fetched as latest at build time) - Add ralphex-fe/files/** to trigger paths - Update verify commands for Debian (app user, Playwright cache, init scripts) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(ralphex-fe): update README for Debian-based image Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ralphex-fe): add docker.io, fzf, pipefail; upgrade checkout to v6 - Add docker.io package (needed for wrapper's --docker flag) - Add fzf (fuzzy finder, matches official ralphex image) - Add SHELL pipefail for Bun curl|bash install (Docker best practice) - Upgrade actions/checkout to v6 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style(ralphex-fe): combine LABEL instructions into single statement Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ralphex-fe): add --no-log-init and download-then-extract for ralphex - useradd --no-log-init prevents large sparse log files (Docker best practice) - Ralphex download separated from tar extraction to avoid masked curl failures in pipeless /bin/sh context Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add DL3002 and DL3016 to hadolint ignores - DL3002 (last USER not root): ralphex-fe entrypoint runs as root for APP_UID remapping, then drops to app user via gosu - DL3016 (pin npm versions): Claude Code intentionally unpinned — images rebuild daily to always get latest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add pre-commit CI validation rule to CLAUDE.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ralphex-fe): handle docker group created by docker.io package docker.io package creates a docker group during installation. Use groupadd -f (idempotent) + groupmod to ensure GID 999. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(ci): upgrade actions to latest stable versions - actions/checkout: v4 → v6 - docker/setup-qemu-action: v3 → v4 - docker/setup-buildx-action: v3 → v4 - docker/build-push-action: v5 → v7 Resolves Node.js 20 deprecation warnings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(ralphex-fe): migrate build to docker/github-builder for parallel platforms Replace sequential QEMU-based build with docker/github-builder which builds amd64 and arm64 in parallel on native runners. Verification runs on native runners (ubuntu-24.04 + ubuntu-24.04-arm). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(ci): upgrade dorny/paths-filter v3 → v4 Resolves Node.js 20 deprecation warning. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf(ralphex-fe): replace docker.io and golang-go with direct binary downloads - Docker CLI: static binary from download.docker.com instead of docker.io package (avoids containerd, runc, iptables — ~55MB of unneeded deps) - Go: direct binary from go.dev/dl/ instead of apt golang-go (avoids ~200MB of Go source + build deps via apt) Both match the patterns used in the official ralphex images. End result is identical: same Go version, same Docker CLI functionality. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf(ralphex-fe): parallel multi-stage downloads; drop QEMU from CI Dockerfile: restructured as multi-stage build — Go, Docker CLI, Hugo, and Ralphex binaries download in parallel stages (BuildKit runs independent stages concurrently). Final stage COPY --from each. CI: dropped arm64 QEMU build and QEMU setup step. arm64 is tested on native runners at merge time via docker/github-builder — no need to emulate it in pre-merge CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf(ralphex-fe): Chromium-only Playwright, apt/npm cache mounts, drop wget - Playwright: install only Chromium headless shell (was installing Firefox + WebKit too). This image is for headless Claude Code testing only. - apt-get: use --mount=type=cache for /var/cache/apt and /var/lib/apt/lists (Docker best practice — avoids re-downloading on layer rebuild) - npm: use --mount=type=cache for /root/.npm - Remove wget from final stage (Hugo downloads in parallel stage now) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 77bcea0 commit db9312a

18 files changed

Lines changed: 1219 additions & 468 deletions

File tree

‎.claude/CLAUDE.md‎

Lines changed: 27 additions & 276 deletions
Original file line numberDiff line numberDiff line change
@@ -1,289 +1,40 @@
1-
# AI Agent Instructions
1+
# Project Overview
22

3-
This document defines patterns, conventions, and guidelines for AI agents working with this repository.
3+
Dockerfiles for custom devcontainer images on GitHub Container Registry (ghcr.io). Each image provides a VS Code Dev Container for a specific development environment.
44

5-
## Repository Overview
5+
## Platform Constraints
66

7-
This repository contains Dockerfiles for custom devcontainer images hosted on GitHub Container Registry (ghcr.io). Each image is designed for VS Code Dev Containers with specific development environments.
8-
9-
## AI Agent Best Practices
10-
11-
### Always Verify with Official Documentation
12-
13-
When implementing features or making changes, **ALWAYS** check the latest official documentation:
14-
15-
- **GitHub Actions**: https://docs.github.com/en/actions
16-
- Runs on Ubuntu (GNU/Linux) - use GNU coreutils syntax, NOT macOS/BSD syntax
17-
- Example: `sed -i "pattern" file` (GNU) NOT `sed -i.bak "pattern" file` (BSD)
18-
- When substituting version strings with `sed`, use `|` as delimiter instead of `/`:
19-
- Correct: `sed -i "s|^ARG FOO=.*|ARG FOO=$NEW_VERSION|"` — safe with any version string
20-
- Incorrect: `sed -i "s/^ARG FOO=.*/ARG FOO=$NEW_VERSION/"` — breaks if version contains `/`
21-
- Check platform-specific tool behavior (sed, grep, awk, etc.)
22-
- Verify workflow syntax with official examples
23-
24-
- **Docker/Dockerfile**: https://docs.docker.com/reference/dockerfile/
25-
- Multi-platform builds use `TARGETARCH` (amd64, arm64)
26-
- Verify base image availability and compatibility
27-
28-
- **Tools and Dependencies**:
29-
- Bun: https://bun.sh/docs
30-
- Hugo: https://gohugo.io/documentation/
31-
- GitHub CLI: https://cli.github.com/manual/
32-
- Always verify command syntax from official docs, not assumptions
33-
34-
### Platform Awareness
35-
36-
- **GitHub Actions runners**: Ubuntu Linux (use GNU tools)
37-
- **Docker builds**: Multi-platform (linux/amd64, linux/arm64)
38-
- **Base images**: Check Alpine vs Debian (apk vs apt, musl vs glibc)
39-
- **Scripts**: Test for portability (sh vs bash, GNU vs BSD tools)
40-
41-
### Validation Before Committing
42-
43-
- YAML syntax validation for workflows
44-
- Dockerfile syntax validation
45-
- Test on target platform (not just local macOS/Windows)
46-
- Verify assumptions about available tools and their versions
47-
48-
## Directory Structure
49-
50-
```
51-
repository-root/
52-
├── AGENTS.md # AI agent instructions (this file)
53-
├── CLAUDE.md # Symlink to AGENTS.md
54-
├── README.md # Repository documentation
55-
├── .github/
56-
│ └── workflows/
57-
│ ├── README.md # Workflow documentation
58-
│ └── build-*.yml # GitHub Actions workflows
59-
├── devcontainer-{name}/ # Devcontainer images (VS Code integration)
60-
│ ├── README.md # Image-specific documentation
61-
│ └── .devcontainer/
62-
│ ├── Dockerfile # Image definition (source of truth)
63-
│ ├── devcontainer.json # VS Code devcontainer configuration
64-
│ └── *.sh # Optional scripts (e.g., init-firewall.sh)
65-
└── {standalone-name}/ # Standalone Docker images (no devcontainer)
66-
├── Dockerfile # Image definition
67-
└── README.md # Image documentation
68-
```
7+
- **GitHub Actions runners**: Ubuntu Linux — use GNU coreutils, NOT macOS/BSD syntax
8+
- `sed -i "pattern" file` (GNU), NOT `sed -i.bak "pattern" file` (BSD)
9+
- Use `|` as sed delimiter: `sed -i "s|^ARG FOO=.*|ARG FOO=$NEW_VERSION|"` — safe with version strings containing `/`
10+
- **Docker builds**: Multi-platform (`linux/amd64`, `linux/arm64`) — use `TARGETARCH` for arch-specific logic
11+
- **Base images**: Check Alpine vs Debian (`apk` vs `apt`, musl vs glibc)
6912

7013
## Naming Conventions
7114

72-
### Image Names
73-
- Devcontainer format: `devcontainer-{primary-tool}` or `devcontainer-{primary-tool}-{secondary-tool}`
74-
- Standalone format: `{base}-{variant}` (e.g., `ralphex-fe`)
75-
- Examples: `devcontainer-bun`, `devcontainer-hugo-bun`, `devcontainer-claude-bun`, `ralphex-fe`
15+
### Image names
16+
- Devcontainer: `devcontainer-{tool}` or `devcontainer-{tool}-{secondary}`
17+
- Standalone: `{base}-{variant}` (e.g., `ralphex-fe`)
7618

7719
### Version ARGs in Dockerfile
78-
- Place at the top of Dockerfile
79-
- Format: `ARG {TOOL}_VERSION={version}`
80-
- Examples:
81-
```dockerfile
82-
ARG BUN_VERSION=1.3.5
83-
ARG HUGO_VERSION=0.152.2
84-
ARG CLAUDE_CODE_VERSION=latest
85-
```
86-
87-
### Image Tags
88-
- Always include `latest` tag
89-
- Devcontainer version-specific tag format: `{tool}{version}-{variant}`
90-
- Examples: `ghcr.io/owner/devcontainer-bun:bun1.3.5-alpine`, `ghcr.io/owner/devcontainer-claude-bun:bun1.3.5-slim`
91-
- Standalone image version-specific tag format: `{primary-version}` (primary tool version only)
92-
- Example: `ghcr.io/owner/ralphex-fe:0.11.0` (ralphex version only; Bun/Hugo versions in README)
93-
94-
## Dockerfile Patterns
95-
96-
### Required OCI Labels
97-
All Dockerfiles must include these labels at the end:
98-
99-
```dockerfile
100-
LABEL org.opencontainers.image.source="https://github.com/{owner}/devcontainer-images"
101-
LABEL org.opencontainers.image.description="{Brief description}"
102-
LABEL org.opencontainers.image.licenses="MIT"
103-
LABEL org.opencontainers.image.title="{image-name}"
104-
LABEL org.opencontainers.image.url="https://github.com/{owner}/devcontainer-images"
105-
```
106-
107-
### Base Images
108-
- Prefer official images from Docker Hub
109-
- Use slim/alpine variants when possible
110-
- Bun: `oven/bun:{version}-alpine` or `oven/bun:{version}-slim`
111-
- Node: `node:{version}` or `node:{version}-slim`
112-
113-
### Common Packages
114-
Minimal images should include:
115-
- `ca-certificates` - HTTPS connections
116-
- `git` - Version control
117-
- `zsh` - Better shell for VS Code integration
118-
119-
### Alpine Playwright Support
120-
121-
When adding Playwright to an Alpine/musl-based image, do NOT use `playwright install` — the bundled Chromium binary requires glibc and is incompatible with Alpine's musl libc.
20+
- Place at top of file: `ARG {TOOL}_VERSION={version}`
12221

123-
Instead:
124-
1. Install system Chromium via apk: `apk add --no-cache chromium ttf-freefont`
125-
2. Set env vars in the Dockerfile (combine into one `ENV` instruction to minimize layers):
126-
```dockerfile
127-
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \
128-
PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium-browser
129-
```
130-
3. In the project's `playwright.config.ts`, wire up `executablePath` manually:
131-
```typescript
132-
launchOptions: {
133-
executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH,
134-
// --disable-dev-shm-usage: prevents Chromium crashes in Docker (default /dev/shm is 64MB)
135-
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
136-
}
137-
```
138-
4. Projects install only `@playwright/test` (e.g., `bun add -d @playwright/test`) — never `playwright install`.
139-
5. `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` is a project-level convention; Playwright does NOT read it automatically.
22+
### Image tags
23+
- Always include `latest`
24+
- Devcontainer: `{tool}{version}-{variant}` (e.g., `bun1.3.5-alpine`)
25+
- Standalone: `{primary-version}` only (e.g., `0.11.0`)
14026

141-
## devcontainer.json Patterns
142-
143-
### File Header
144-
```jsonc
145-
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
146-
// README at: {relevant-reference-url}
147-
```
148-
149-
### node_modules Mount
150-
Always include to keep node_modules out of host machine:
151-
```jsonc
152-
"mounts": [
153-
// Keep node_modules out of a host machine
154-
"source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
155-
]
156-
```
157-
158-
### VS Code Extensions
159-
- Group extensions by category with header comments
160-
- Include description comment for each extension
161-
- Format:
162-
```jsonc
163-
"extensions": [
164-
// **Category Name**
165-
// Extension Description
166-
"publisher.extension-id",
167-
168-
// **Another Category**
169-
// Another Extension Description
170-
"another.extension"
171-
]
172-
```
173-
174-
### Common Extension Categories
175-
- `**Claude Code**` - AI assistant
176-
- `**Bun**` - Bun runtime support
177-
- `**Code Quality**` - Biome (formatter and linter)
178-
- `**Git**` - GitLens
179-
- `**Tailwind**` - Tailwind CSS tooling
180-
- `**Hugo**` - Hugo static site generator (when applicable)
181-
182-
### Required VS Code Settings
183-
```jsonc
184-
"settings": {
185-
"terminal.integrated.defaultProfile.linux": "zsh",
186-
// Suppress extension recommendation prompts
187-
"extensions.ignoreRecommendations": true
188-
}
189-
```
190-
191-
## GitHub Actions Workflow Patterns
192-
193-
### Trigger Configuration
194-
195-
For devcontainer images:
196-
```yaml
197-
on:
198-
push:
199-
branches:
200-
- master
201-
paths:
202-
- '{image-name}/.devcontainer/Dockerfile'
203-
- '{image-name}/.devcontainer/*.sh' # If scripts exist
204-
workflow_dispatch:
205-
```
206-
207-
For standalone images:
208-
```yaml
209-
on:
210-
push:
211-
branches:
212-
- master
213-
paths:
214-
- '{image-name}/Dockerfile'
215-
workflow_dispatch:
216-
```
217-
218-
### Version Extraction
219-
Extract versions from Dockerfile ARGs:
220-
```yaml
221-
- name: Extract versions from Dockerfile
222-
id: versions
223-
run: |
224-
DOCKERFILE="{image-name}/.devcontainer/Dockerfile"
225-
VERSION=$(grep '^ARG {TOOL}_VERSION=' "$DOCKERFILE" | cut -d'=' -f2)
226-
echo "{tool}=$VERSION" >> $GITHUB_OUTPUT
227-
```
228-
229-
### Multi-platform Build
230-
Always build for both architectures:
231-
```yaml
232-
platforms: linux/amd64,linux/arm64
233-
```
234-
235-
### Caching
236-
Use GitHub Actions cache:
237-
```yaml
238-
cache-from: type=gha
239-
cache-to: type=gha,mode=max
240-
```
241-
242-
## README Patterns
243-
244-
### Image README Structure
245-
1. Title and brief description
246-
2. Features list
247-
3. Quick Start (pre-built image usage)
248-
4. Building locally instructions
249-
5. Configuration details
250-
6. Image tags
251-
7. Customization options
252-
8. Resources/links
253-
254-
### Main README Structure
255-
1. Repository overview
256-
2. Image documentation links
257-
3. Repository structure
258-
4. Available images with usage examples
259-
5. Adding a new image guide
260-
6. Building and publishing info
261-
262-
## When Adding a New Image
263-
264-
### Devcontainer Image
265-
1. Create directory: `devcontainer-{name}/`
266-
2. Add `.devcontainer/Dockerfile` following patterns above
267-
3. Add `.devcontainer/devcontainer.json` following patterns above
268-
4. Add `README.md` with image documentation
269-
5. Create `.github/workflows/build-devcontainer-{name}.yml`
270-
6. Update main `README.md` with new image entry
27+
## Code Style
27128

272-
### Standalone Docker Image
273-
1. Create directory: `{image-name}/`
274-
2. Add `Dockerfile` directly in the directory (no `.devcontainer/` subdirectory)
275-
3. Add `README.md` with image documentation
276-
4. Create `.github/workflows/build-{image-name}.yml`
277-
5. Update main `README.md` with new image entry
29+
- 2-space indentation in JSON/YAML
30+
- Use comments in devcontainer.json (JSONC format)
31+
- Dockerfile instruction order: ARG → FROM → packages → user/permissions → tools → LABEL
27832

279-
## Code Style
33+
## Validation
28034

281-
- Use 2-space indentation in JSON/YAML files
282-
- Use comments liberally in devcontainer.json (JSONC)
283-
- Keep Dockerfile instructions organized logically:
284-
1. ARG declarations
285-
2. FROM statement
286-
3. Package installation
287-
4. User/permission setup
288-
5. Tool installation
289-
6. Labels (at the end)
35+
- **Before committing**, check which CI workflows in `.github/workflows/` will run against the changed files and run those checks locally first (e.g., Hadolint for Dockerfiles, linters for YAML/JS, etc.)
36+
- Validate YAML and Dockerfile syntax before committing
37+
- Verify on target platform — not just local macOS/Windows
38+
- Check tool version availability and command syntax from official docs:
39+
- [GitHub Actions](https://docs.github.com/en/actions) · [Dockerfile reference](https://docs.docker.com/reference/dockerfile/)
40+
- [Bun](https://bun.sh/docs) · [Hugo](https://gohugo.io/documentation/) · [GitHub CLI](https://cli.github.com/manual/)

‎.claude/rules/devcontainer.md‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
paths:
3+
- "**/devcontainer.json"
4+
---
5+
6+
# devcontainer.json Conventions
7+
8+
## File Header
9+
10+
```jsonc
11+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
12+
// README at: {relevant-reference-url}
13+
```
14+
15+
## node_modules Mount
16+
17+
Always include to keep node_modules off the host:
18+
19+
```jsonc
20+
"mounts": [
21+
"source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
22+
]
23+
```
24+
25+
## VS Code Extensions
26+
27+
Group by category with header comments:
28+
29+
```jsonc
30+
"extensions": [
31+
// **Category Name**
32+
// Extension Description
33+
"publisher.extension-id"
34+
]
35+
```
36+
37+
Common categories: `**Claude Code**`, `**Bun**`, `**Code Quality**` (OXC), `**Git**` (GitLens), `**Tailwind**`, `**Hugo**`
38+
39+
## Required VS Code Settings
40+
41+
```jsonc
42+
"settings": {
43+
"terminal.integrated.defaultProfile.linux": "fish",
44+
"extensions.ignoreRecommendations": true
45+
}
46+
```

0 commit comments

Comments
 (0)