Skip to content

Add Docker containerization and skillbench enhancements#9

Merged
mattbeane merged 2 commits intomainfrom
feature/add-docker
Mar 25, 2026
Merged

Add Docker containerization and skillbench enhancements#9
mattbeane merged 2 commits intomainfrom
feature/add-docker

Conversation

@TheStarkor
Copy link
Copy Markdown
Contributor

@TheStarkor TheStarkor commented Mar 25, 2026

Summary by CodeRabbit

  • New Features

    • Docker-based workflow for running collection and an interactive container shell
    • New Make targets to build, run collection (including verbose/all modes) and open a shell
    • Automatic detection of workspaces to mount into the container for collection
    • New CLI flag to optionally include previously excluded workspaces during collection
    • Improved project discovery and remote-repo fallback when running collection
  • Documentation

    • Added Docker quick-start with guidance on outputs written to host dist/ directory

…gement

- Introduced a Dockerfile to build a lightweight image for running skillbench.
- Added a Makefile with targets for building the Docker image and collecting data.
- Implemented a script to dynamically generate Docker bind-mount arguments for workspace folders.
- Updated README.md with Docker quick start instructions for ease of use.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Lite

Run ID: 55bbb243-8b64-49c1-a861-dd2e5c04a582

📥 Commits

Reviewing files that changed from the base of the PR and between d44c44f and 24d69b6.

📒 Files selected for processing (1)
  • Dockerfile
✅ Files skipped from review due to trivial changes (1)
  • Dockerfile

Walkthrough

Adds Docker-based workflows: a new Dockerfile and Make targets, a helper script to emit workspace bind-mounts, README instructions, and updates to skillbench.py for platform-aware DB discovery, git-config fallback, and a new --include-excluded collect flag.

Changes

Cohort / File(s) Summary
Docker image
Dockerfile
New Dockerfile building Python 3.10-slim, installs Git and GitHub CLI (gh) by detecting container CPU architecture and extracting the appropriate gh tarball; sets HOME=/home/app, WORKDIR=/work, and default CMD to python3 skillbench.py --help.
Make workflows
Makefile
New Makefile with docker-build, docker-collect, docker-collect-all, docker-collect-verbose, docker-shell; configures image name, mounts (agent stores, optional GH auth), conditional --include-excluded flag, runtime workspace mounts computed via scripts/skillbench_docker_mounts.py, and TTY-aware interactive flags.
Mount helper script
scripts/skillbench_docker_mounts.py
New executable script that imports session_parser.scan_sessions(), gathers workspace paths (skipping invalid, temp, non-existent, and duplicate host paths), and prints space-separated read-only -v <host>:<host>:ro mount arguments.
Documentation
README.md
Added "Docker quick start (Make)" section documenting make docker-collect and make docker-collect-all, noting outputs go to host dist/ and default privacy behavior (only public/OSS repos auto-included).
Core CLI changes
skillbench.py
Platform-aware CASS SQLite DB discovery with CASS_DATA_DIR override and project-local fallback; improved git_remote_url() using .git/config parsing (handles gitdir: indirection); added --include-excluded CLI option for skillbench collect and updated related messaging.
Other
(no additional files)
No exported/public library API changes beyond CLI flag and new script entrypoint.

Sequence Diagram

sequenceDiagram
    actor User
    participant Make as "Make target"
    participant MountScript as "skillbench_docker_mounts.py"
    participant Parser as "session_parser"
    participant Docker as "Docker daemon / Container"
    participant CLI as "skillbench.py (collect)"

    User->>Make: run `make docker-collect`
    Make->>MountScript: python3 scripts/skillbench_docker_mounts.py
    MountScript->>Parser: call scan_sessions(verbose=False)
    Parser-->>MountScript: workspace summaries
    MountScript->>Make: emit `-v host:host:ro` mount args
    Make->>Docker: docker run with mounts, env, image
    Docker->>CLI: start `python3 skillbench.py collect --user [--include-excluded?]`
    CLI->>CLI: discover CASS DB, parse git config, scan repos
    CLI-->>Docker: produce collection output
    Docker-->>User: write outputs to host `dist/`
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I dug a Docker den beneath the log,
I stitched mounts like pockets for each repo and cog,
With gh in paw and Make to guide the hop,
Skillbench collects while the carrots never stop,
A little rabbit cheers: containerized and spry! 🥕


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai bot changed the title @coderabbit Add Docker containerization and skillbench enhancements Mar 25, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d44c44f15e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1409 to +1411
if not allowed_paths and include_excluded:
# Explicit opt-in: proceed with excluded workspaces too.
allowed_paths = [e["path"] for e in (included + excluded)]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Honor --include-excluded when public repos are present

The --include-excluded flag currently takes effect only when included is empty, because excluded paths are appended inside if not allowed_paths and include_excluded. In mixed cases (some public/OSS repos plus some excluded repos), an explicit opt-in still exports only the included set, so workflows like make docker-collect-all silently omit the excluded workspaces users asked to include.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (5)
Makefile (2)

19-25: AGENT_MOUNTS may fail if directories don't exist on the host.

The mounts for .codex, .codex-cli, and .openai-codex will cause Docker errors if these directories don't exist on the host system. Most users won't have all three Codex variants.

Consider either:

  1. Creating missing directories before mounting, or
  2. Making mounts conditional, or
  3. Using a script to filter existing directories
♻️ Option 1: Create directories in docker-collect
 docker-collect: docker-build
 	`@mkdir` -p dist
+	`@mkdir` -p "$(HOME)/.claude" "$(HOME)/.gemini" "$(HOME)/.codex" "$(HOME)/.codex-cli" "$(HOME)/.openai-codex" 2>/dev/null || true
 	docker run --rm \
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Makefile` around lines 19 - 25, AGENT_MOUNTS currently includes fixed host
paths that will cause Docker to fail if those host directories (e.g.,
$(HOME)/.codex, $(HOME)/.codex-cli, $(HOME)/.openai-codex) don't exist; change
the Makefile to construct AGENT_MOUNTS dynamically by testing each host
directory's existence and only appending the corresponding mount (using the
existing CONTAINER_HOME variable for the container side) or create missing
directories beforehand in a helper target (e.g., a docker-collect or
prepare-mounts target) so Docker sees only valid mounts; modify the AGENT_MOUNTS
definition to use a shell snippet or phony target that filters/creates the three
codex-related directories before running the docker command.

57-70: docker-collect-verbose doesn't support INCLUDE_EXCLUDED flag.

Unlike docker-collect, the verbose target doesn't include $(COLLECT_FLAGS), so INCLUDE_EXCLUDED=1 make docker-collect-verbose won't work as expected.

♻️ Pass COLLECT_FLAGS to verbose target (without -y for interactivity)
+# Verbose flags: same as COLLECT_FLAGS but without -y for interactive mode
+COLLECT_FLAGS_VERBOSE :=
+ifeq ($(INCLUDE_EXCLUDED),1)
+COLLECT_FLAGS_VERBOSE += --include-excluded
+endif
+
 docker-collect-verbose: docker-build
 	`@mkdir` -p dist
 	docker run --rm $(DOCKER_INTERACTIVE) \
 		...
 		"$(IMAGE)" \
-		python3 skillbench.py collect
+		python3 skillbench.py collect $(COLLECT_FLAGS_VERBOSE)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Makefile` around lines 57 - 70, The verbose Makefile target
docker-collect-verbose currently omits $(COLLECT_FLAGS) so INCLUDE_EXCLUDED (and
other flags) are ignored; update the command that runs python3 skillbench.py
collect in docker-collect-verbose to append the collection flags using
$(filter-out -y,$(COLLECT_FLAGS)) so interactivity is preserved while still
passing INCLUDE_EXCLUDED and other flags (mirror how docker-collect uses
$(COLLECT_FLAGS) but remove the -y flag for interactivity).
scripts/skillbench_docker_mounts.py (1)

45-47: Minor: Substring check may have false positives.

The check if gemini_tmp in ws uses substring matching, which could incorrectly skip paths like /path/to/.gemini/tmp_backup or /home/user/.gemini/tmp2/project. Consider using path prefix or exact component matching.

♻️ Optional: Use path-based check
-        if gemini_tmp in ws:
+        # Skip paths under ~/.gemini/tmp/ (Gemini hash folders)
+        if ws.startswith(gemini_tmp + "/") or ws == gemini_tmp:
             continue
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/skillbench_docker_mounts.py` around lines 45 - 47, The substring
check `if gemini_tmp in ws` can produce false positives; replace it with a
path-aware check using pathlib so you only skip mounts that are actually under
the gemini_tmp directory (e.g., resolve both paths and use Path.is_relative_to
or compare the leading path parts) when evaluating `ws` vs `gemini_tmp` in the
mount loop in scripts/skillbench_docker_mounts.py.
Dockerfile (2)

38-47: Consider adding tarfile extraction filter for Python 3.12+ compatibility.

Python 3.12+ deprecates extraction without an explicit filter parameter due to security concerns with path traversal. While the risk is low here (trusted source, single file extraction), adding the filter future-proofs the build.

♻️ Optional: Add extraction filter
 tf = tarfile.open(fileobj=io.BytesIO(blob), mode="r:gz")
+# Python 3.12+ requires explicit filter; 'data' is the safe default
+if hasattr(tarfile, 'data_filter'):
+    tf.extraction_filter = tarfile.data_filter
 gh_member = next((m for m in tf.getmembers() if m.name.endswith("/bin/gh")), None)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 38 - 47, The tar extraction should use an explicit
extraction filter to satisfy Python 3.12+ requirements; replace the current
tf.extractfile(gh_member) usage by calling tf.extract(...) (or tf.extractall
with a filter) and provide a filter callable that validates/whitelists the
member (e.g., accepts only the gh_member where
gh_member.name.endswith("/bin/gh")) before extraction so you explicitly allow
that path; update the code paths that reference tf.getmembers and gh_member and
ensure you extract to out_path (/usr/local/bin/gh) with correct permissions
after the filtered extraction.

35-48: Consider adding error handling for network failures.

The urllib.request.urlopen calls lack explicit error handling. If the GitHub API or release download fails (network issues, rate limits, 404), the build will fail with an unclear Python traceback.

♻️ Optional: Add error handling
+try:
     with urllib.request.urlopen(url) as r:
         blob = r.read()
+except urllib.error.URLError as e:
+    raise SystemExit(f"Failed to download gh: {e}")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 35 - 48, Wrap the network and archive operations in
explicit error handling: around urllib.request.urlopen(url) catch
urllib.error.HTTPError, urllib.error.URLError and socket.timeout and implement a
small retry/backoff or at least raise a clear SystemExit with the HTTP
status/error details; also catch tarfile.ReadError around
tarfile.open(fileobj=...) and handle the case where tf.extractfile(gh_member)
returns None with a descriptive SystemExit; ensure any failure logs the URL and
out_path and exits non‑zero so the Docker build fails with a clear message
(refer to urllib.request.urlopen, tarfile.open, tf.getmembers, tf.extractfile,
out_path, os.chmod).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Dockerfile`:
- Around line 38-47: The tar extraction should use an explicit extraction filter
to satisfy Python 3.12+ requirements; replace the current
tf.extractfile(gh_member) usage by calling tf.extract(...) (or tf.extractall
with a filter) and provide a filter callable that validates/whitelists the
member (e.g., accepts only the gh_member where
gh_member.name.endswith("/bin/gh")) before extraction so you explicitly allow
that path; update the code paths that reference tf.getmembers and gh_member and
ensure you extract to out_path (/usr/local/bin/gh) with correct permissions
after the filtered extraction.
- Around line 35-48: Wrap the network and archive operations in explicit error
handling: around urllib.request.urlopen(url) catch urllib.error.HTTPError,
urllib.error.URLError and socket.timeout and implement a small retry/backoff or
at least raise a clear SystemExit with the HTTP status/error details; also catch
tarfile.ReadError around tarfile.open(fileobj=...) and handle the case where
tf.extractfile(gh_member) returns None with a descriptive SystemExit; ensure any
failure logs the URL and out_path and exits non‑zero so the Docker build fails
with a clear message (refer to urllib.request.urlopen, tarfile.open,
tf.getmembers, tf.extractfile, out_path, os.chmod).

In `@Makefile`:
- Around line 19-25: AGENT_MOUNTS currently includes fixed host paths that will
cause Docker to fail if those host directories (e.g., $(HOME)/.codex,
$(HOME)/.codex-cli, $(HOME)/.openai-codex) don't exist; change the Makefile to
construct AGENT_MOUNTS dynamically by testing each host directory's existence
and only appending the corresponding mount (using the existing CONTAINER_HOME
variable for the container side) or create missing directories beforehand in a
helper target (e.g., a docker-collect or prepare-mounts target) so Docker sees
only valid mounts; modify the AGENT_MOUNTS definition to use a shell snippet or
phony target that filters/creates the three codex-related directories before
running the docker command.
- Around line 57-70: The verbose Makefile target docker-collect-verbose
currently omits $(COLLECT_FLAGS) so INCLUDE_EXCLUDED (and other flags) are
ignored; update the command that runs python3 skillbench.py collect in
docker-collect-verbose to append the collection flags using $(filter-out
-y,$(COLLECT_FLAGS)) so interactivity is preserved while still passing
INCLUDE_EXCLUDED and other flags (mirror how docker-collect uses
$(COLLECT_FLAGS) but remove the -y flag for interactivity).

In `@scripts/skillbench_docker_mounts.py`:
- Around line 45-47: The substring check `if gemini_tmp in ws` can produce false
positives; replace it with a path-aware check using pathlib so you only skip
mounts that are actually under the gemini_tmp directory (e.g., resolve both
paths and use Path.is_relative_to or compare the leading path parts) when
evaluating `ws` vs `gemini_tmp` in the mount loop in
scripts/skillbench_docker_mounts.py.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Lite

Run ID: 2a7f2041-40ac-4fad-ba3b-59ec0f438500

📥 Commits

Reviewing files that changed from the base of the PR and between 8a222d0 and d44c44f.

📒 Files selected for processing (5)
  • Dockerfile
  • Makefile
  • README.md
  • scripts/skillbench_docker_mounts.py
  • skillbench.py

@mattbeane mattbeane merged commit 24d69b6 into main Mar 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants