Skip to content

Commit c62aa5b

Browse files
committed
X-Smart-Squash: Squashed 51 commits:
dfbf8345b feat: add devcontainer and Claude Code agent development environment 125265f23 docs: add Vertex AI setup and devcontainer build instructions to CLAUDE.md 446368067 feat: add launcher script with worktree isolation and GitHub PAT support 255973f63 feat: use official GitHub MCP server, fix run.sh, add bubblewrap 186b64f91 refactor: convert skills to collector-dev plugin with scoped tool permissions 654e94d16 feat: create branch and draft PR upfront, tighten iterate permissions 2c55d55db feat: add watch-ci skill for CI monitoring loop c5b99277f feat: add end-to-end task skill with CI monitoring loop 2e595c66c fix: load collector-dev plugin via --plugin-dir flag 495175e07 feat: stream agent activity to stdout in autonomous mode 37ae0c778 feat: add --local mode for debugging without worktree or PR 8d676b290 feat: add --headless mode (worktree + stream-json, no PR) 310f54b8a fix: initialize submodules in worktree after creation 3bc345bb6 fix: only init required submodules, drop --recursive 4026f1bbb fix: headless mode now invokes /collector-dev:task skill like default mode bbfc92dee feat: add preflight checks with clear error messages 02cd22383 refactor: remove gh CLI dependency, agent creates PR via GitHub MCP 63927219d refactor: move skills from plugin to standalone, simplify CLAUDE.md a56fcf0b9 refactor: switch worktree to clone, consolidate to 2 skills, fix audit issues c7d94e59a fix: move git push deny to container-only settings 97333c681 security: remove SSH mount, git push blocked by lack of credentials 27f9c5643 fix: set clone remote to GitHub URL instead of local path 9ca06ebb9 refactor: switch back to worktrees, mount .git at same absolute path dffd017f2 perf: shallow submodule checkout in worktrees (--depth 1) 0b48869be perf: mount submodules from main repo instead of cloning per worktree c7235b886 feat: make submodule mounting optional via --symlink-submodules 1ed07b9c7 feat: add --branch flag, use /tmp/collector-worktrees/ for worktrees 1ec7baa6a fix: reject --branch with --local mode 3a5bae34c fix: mount .git read-write so git commit works in container ae67afece security: mount .git read-only with worktree subdir read-write 4de75efbb fix: set theme and verbose defaults in entrypoint to skip startup prompts 75951d2c3 fix: chmod worktree git dir for container uid mismatch 4a890e4fd fix: use chmod a+rwX to fix directory permissions in worktree git dir d98fa6120 fix: mount .git read-write, partial ro/rw overlay doesn't work cb28d8977 security: remove SYS_PTRACE/NET_ADMIN/NET_RAW caps, drop --symlink-submodules d54640991 feat: specify GitHub MCP toolsets via X-MCP-Toolsets header cdc273455 feat: watch-ci updates PR body with agent status after each CI cycle 94df7c938 docs: add MCP Context Protector integration plan 1c4e4e6c9 fix: autonomous mode inlines task instructions instead of invoking /task skill deba75adc feat: add /dev-loop skill combining task + watch-ci + PR comment handling 2943f398b feat: allow specifying skill in autonomous mode, default to /dev-loop 36c9709c0 fix: remove local keyword from case branch (not a function) 0c1222999 docs: update MCP security plan — recommend mcp-watchdog over mcp-context-protector 7d156e3ee fix: push branch from host before launching autonomous agent 1bcb0215b fix: only push branch in autonomous /dev-loop mode, not for explicit skills 0903b5dff feat: TUI is now default for all modes, --no-tui for stream-json e058a9283 docs: clarify push_files usage in dev-loop and watch-ci skills 587f879da docs: add devcontainer README with GitHub PAT permissions and setup guide ba617318a fix: shfmt formatting and shellcheck SC2064 warning in run.sh d1620ff8c fix: shfmt formatting — use 4-space indent per .editorconfig 3ff6a8415 fix: address PR review feedback for devcontainer scripts
1 parent b2f230b commit c62aa5b

File tree

13 files changed

+1027
-2
lines changed

13 files changed

+1027
-2
lines changed

.claude/settings.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"permissions": {
3+
"deny": [
4+
"mcp__github__merge_pull_request",
5+
"mcp__github__delete_file",
6+
"mcp__github__fork_repository",
7+
"mcp__github__create_repository",
8+
"mcp__github__actions_run_trigger"
9+
]
10+
}
11+
}

.claude/skills/dev-loop/SKILL.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
name: dev-loop
3+
description: Full autonomous development loop — implement, build, test, commit, push, create PR, monitor CI, fix failures until green
4+
disable-model-invocation: true
5+
allowed-tools: Bash(cmake *), Bash(ctest *), Bash(nproc), Bash(git add *), Bash(git commit *), Bash(git diff *), Bash(git describe *), Bash(git branch *), Bash(git status), Bash(git log *), Bash(git rev-parse *), Bash(clang-format *), Bash(sleep *), Bash(date *), Read, Write, Edit, Glob, Grep, Agent
6+
---
7+
8+
# Dev Loop
9+
10+
Complete a development task end-to-end: implement, build, test, push, create PR, monitor CI, fix failures.
11+
Do NOT stop until CI is green or you are blocked.
12+
13+
## Phase 1: Implement
14+
15+
1. Read and understand the task from $ARGUMENTS
16+
2. Explore relevant code
17+
3. Implement the changes
18+
4. Build: `cmake -S . -B cmake-build -DCMAKE_BUILD_TYPE=Release -DCOLLECTOR_VERSION=$(git describe --tags --abbrev=10 --long) && cmake --build cmake-build -- -j$(nproc)`
19+
- If build fails, fix and retry
20+
5. Test: `ctest --no-tests=error -V --test-dir cmake-build`
21+
- If tests fail, fix and retry
22+
6. Format: `clang-format --style=file -i <changed .cpp/.h files>`
23+
7. Commit: `git add` changed files, `git commit` with a descriptive message
24+
25+
## Phase 2: Push and create PR
26+
27+
Use the GitHub MCP server to push files and create a PR.
28+
Do NOT use `git push` — it will fail (no SSH keys in this container).
29+
30+
1. Get the current branch name and the list of changed files:
31+
- `git branch --show-current` for the branch
32+
- `git diff --name-only origin/HEAD..HEAD` for changed files
33+
2. Use the GitHub MCP `push_files` tool to push the changed files directly to
34+
the remote branch. This creates a commit via the GitHub API using the file
35+
contents from your local workspace — it does not sync git history.
36+
- owner: stackrox, repo: collector, branch: <current branch>
37+
- Read each changed file and include its content
38+
- Provide a commit message
39+
3. Search for an open PR for this branch via GitHub MCP
40+
4. If no PR exists, create a draft PR via GitHub MCP
41+
42+
## Phase 3: Monitor CI
43+
44+
Loop until all checks pass or blocked (max 6 cycles, ~3 hours):
45+
46+
1. Wait 10 minutes: `sleep 600`
47+
2. Check CI status via GitHub MCP (PR checks, workflow runs)
48+
3. Update PR body with an `## Agent Status` section:
49+
```
50+
## Agent Status
51+
**Last updated:** <`date -u +"%Y-%m-%d %H:%M UTC"`>
52+
**CI cycle:** N of 6
53+
**Status:** PENDING | PASSED | FIXED | FLAKE | BLOCKED
54+
**Details:** <one-line summary>
55+
```
56+
4. Evaluate:
57+
- **All checks passed** → update PR body, report success, stop
58+
- **Still running** → continue loop
59+
- **Failed**
60+
- Get job logs via GitHub MCP
61+
- Diagnose: build error, test assertion, lint, infra flake
62+
- If fixable: fix → build → test → push changed files via MCP → continue
63+
- If infra flake: note as FLAKE, continue
64+
- If not fixable: update PR body, report BLOCKED, stop
65+
66+
## Phase 4: Check PR comments
67+
68+
Before each CI cycle, check if there are new PR review comments via GitHub MCP.
69+
If a reviewer left feedback:
70+
- Address the feedback (edit code, fix issues)
71+
- Build and test
72+
- Push changed files via MCP
73+
- Note in the Agent Status section what feedback was addressed
74+
75+
## Completion
76+
77+
Print summary:
78+
```
79+
STATUS: PASSED | BLOCKED | TIMEOUT
80+
Branch: <branch>
81+
PR: <url>
82+
Cycles: N
83+
Changes: <list of files modified>
84+
```

.claude/skills/task/SKILL.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
name: task
3+
description: Implement a change — edit code, build, test, format, commit locally. No push.
4+
disable-model-invocation: true
5+
allowed-tools: Bash(cmake *), Bash(ctest *), Bash(nproc), Bash(git add *), Bash(git commit *), Bash(git diff *), Bash(git describe *), Bash(git branch *), Bash(git status), Bash(clang-format *), Read, Write, Edit, Glob, Grep, Agent
6+
---
7+
8+
# Task
9+
10+
Implement a change locally: edit, build, test, format, commit.
11+
Do NOT push or create PRs — use /watch-ci for that.
12+
13+
## Steps
14+
15+
1. Read and understand the task from $ARGUMENTS
16+
2. Explore relevant code in the repository
17+
3. Implement the changes
18+
4. Build:
19+
- `cmake -S . -B cmake-build -DCMAKE_BUILD_TYPE=Release -DCOLLECTOR_VERSION=$(git describe --tags --abbrev=10 --long) && cmake --build cmake-build -- -j$(nproc)`
20+
- If build fails, fix and retry
21+
5. Run unit tests:
22+
- `ctest --no-tests=error -V --test-dir cmake-build`
23+
- If tests fail, fix and retry
24+
6. Format changed C++ files:
25+
- `clang-format --style=file -i <changed .cpp/.h files>`
26+
7. Commit:
27+
- `git add` the changed files
28+
- `git commit` with a descriptive message
29+
30+
## STOP here. Report and wait.
31+
32+
Print this summary and then STOP. Do not continue with any other actions.
33+
34+
```
35+
TASK COMPLETE
36+
Branch: <current branch>
37+
Commit: <commit hash>
38+
Files changed: <list>
39+
Tests: <pass/fail count>
40+
```
41+
42+
The user will review and decide whether to run /watch-ci.
43+
Do NOT push, create branches, or create PRs.

.claude/skills/watch-ci/SKILL.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
name: watch-ci
3+
description: Push files to existing remote branch via GitHub MCP, create PR if needed, monitor CI, fix failures until green
4+
disable-model-invocation: true
5+
allowed-tools: Bash(cmake *), Bash(ctest *), Bash(nproc), Bash(git add *), Bash(git commit *), Bash(git diff *), Bash(git describe *), Bash(git branch *), Bash(git status), Bash(git log *), Bash(git rev-parse *), Bash(clang-format *), Bash(sleep *), Bash(date *), Read, Write, Edit, Glob, Grep
6+
---
7+
8+
# Watch CI
9+
10+
Push changed files via the GitHub MCP server, create PR if needed, and monitor CI until green.
11+
Do NOT use `git push` — it will fail (no SSH keys in this container).
12+
13+
## How pushing works
14+
15+
Use the GitHub MCP `push_files` tool to send file contents directly to the remote
16+
branch via the GitHub API. This does NOT sync local git history — it creates a new
17+
commit on the remote with the file contents you provide.
18+
19+
1. Get the branch name: `git branch --show-current`
20+
2. Get changed files: `git diff --name-only origin/HEAD..HEAD`
21+
3. Read each changed file's content
22+
4. Call `push_files` with owner: stackrox, repo: collector, branch, files, and commit message
23+
24+
## Steps
25+
26+
1. **Push** changed files:
27+
- Use the GitHub MCP `push_files` tool as described above
28+
- If no files have changed since last push, skip
29+
30+
2. **Find or create PR**:
31+
- Use the GitHub MCP server to search for an open PR for this branch
32+
- If no PR exists, create a draft PR via the GitHub MCP server
33+
34+
3. **Monitor CI loop** (repeat until all checks pass or blocked):
35+
- Wait 10 minutes: `sleep 600`
36+
- Use the GitHub MCP server to get PR check status and workflow runs
37+
- Update PR body with an `## Agent Status` section:
38+
```
39+
## Agent Status
40+
**Last updated:** <`date -u +"%Y-%m-%d %H:%M UTC"`>
41+
**CI cycle:** N of 6
42+
**Status:** PENDING | PASSED | FIXED | FLAKE | BLOCKED
43+
**Details:** <one-line summary>
44+
```
45+
- Evaluate:
46+
- **All checks passed** → update PR body, report success and stop
47+
- **Checks still running** → report progress, continue loop
48+
- **Checks failed** →
49+
- Get job logs via the GitHub MCP server
50+
- Diagnose:
51+
- Build failure: read error, fix code
52+
- Unit test failure: read assertion, fix code
53+
- Lint failure: run `clang-format --style=file -i`
54+
- Integration test infra flake (VM timeout, network): report as flake, continue
55+
- Integration test real failure: analyze and fix code
56+
- If fixable: fix → build → test → push changed files via MCP → continue loop
57+
- If not fixable: update PR body, report diagnosis and stop
58+
59+
4. **Safety limits**:
60+
- Maximum 6 CI cycles (about 3 hours of monitoring)
61+
- If exceeded, update PR body and stop
62+
63+
5. **Summary**: end with a status line:
64+
- `PASSED` — all checks green
65+
- `PENDING` — checks still running
66+
- `FIXED` — failure diagnosed and fix pushed
67+
- `FLAKE` — infra failure, not a code issue
68+
- `BLOCKED` — failure requires human intervention

.devcontainer/Dockerfile

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Collector development container
2+
# Based on the collector-builder image which has all C++ dependencies pre-installed.
3+
# Adds Claude Code, Go, and developer tooling for agent-driven development.
4+
#
5+
# Build environment: CentOS Stream 10 with clang, llvm, cmake, grpc, protobuf,
6+
# libbpf, bpftool, and all other collector dependencies.
7+
8+
ARG COLLECTOR_BUILDER_TAG=master
9+
FROM quay.io/stackrox-io/collector-builder:${COLLECTOR_BUILDER_TAG}
10+
11+
# Install developer tooling not in the builder image
12+
# Note: git, findutils, which, openssh-clients already in builder
13+
# bubblewrap: Claude Code uses this for built-in command sandboxing
14+
RUN dnf install -y \
15+
bubblewrap \
16+
clang-tools-extra \
17+
jq \
18+
socat \
19+
zsh \
20+
procps-ng \
21+
sudo \
22+
python3-pip \
23+
iptables \
24+
ipset \
25+
&& dnf clean all
26+
27+
# Determine architecture strings used by various download URLs
28+
# uname -m gives aarch64 or x86_64
29+
# Go uses arm64/amd64, ripgrep/fd use aarch64/x86_64
30+
RUN ARCH=$(uname -m) \
31+
&& GOARCH=$([ "$ARCH" = "aarch64" ] && echo "arm64" || echo "amd64") \
32+
# Install Go
33+
&& curl -fsSL "https://go.dev/dl/go1.23.6.linux-${GOARCH}.tar.gz" | tar -C /usr/local -xzf - \
34+
# Install ripgrep
35+
&& curl -fsSL "https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-${ARCH}-unknown-linux-gnu.tar.gz" \
36+
| tar -xzf - --strip-components=1 -C /usr/local/bin "ripgrep-14.1.1-${ARCH}-unknown-linux-gnu/rg" \
37+
# Install fd
38+
&& curl -fsSL "https://github.com/sharkdp/fd/releases/download/v10.2.0/fd-v10.2.0-${ARCH}-unknown-linux-gnu.tar.gz" \
39+
| tar -xzf - --strip-components=1 -C /usr/local/bin "fd-v10.2.0-${ARCH}-unknown-linux-gnu/fd"
40+
41+
ENV PATH="/usr/local/go/bin:${PATH}"
42+
ENV GOPATH="/home/dev/go"
43+
ENV PATH="${GOPATH}/bin:${PATH}"
44+
45+
# Install Node.js (needed for Claude Code)
46+
ARG NODE_VERSION=22
47+
RUN curl -fsSL https://rpm.nodesource.com/setup_${NODE_VERSION}.x | bash - \
48+
&& dnf install -y nodejs \
49+
&& dnf clean all
50+
51+
# Install Claude Code
52+
RUN npm install -g @anthropic-ai/claude-code
53+
54+
# Install gcloud CLI (for Vertex AI auth and GCP VM management)
55+
RUN curl -fsSL https://sdk.cloud.google.com > /tmp/install-gcloud.sh \
56+
&& bash /tmp/install-gcloud.sh --disable-prompts --install-dir=/opt \
57+
&& rm /tmp/install-gcloud.sh
58+
ENV PATH="/opt/google-cloud-sdk/bin:${PATH}"
59+
60+
# Create non-root dev user with passwordless sudo
61+
RUN useradd -m -s /bin/zsh dev \
62+
&& echo "dev ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/dev \
63+
&& mkdir -p /home/dev/.claude/debug /home/dev/.commandhistory \
64+
&& chown -R dev:dev /home/dev/.claude /home/dev/.commandhistory
65+
66+
# Install ansible for VM-based testing (optional, lightweight)
67+
RUN pip3 install ansible-core
68+
69+
# Firewall script for network isolation (optional, used with --dangerously-skip-permissions)
70+
COPY --chmod=755 init-firewall.sh /usr/local/bin/init-firewall.sh
71+
COPY --chmod=755 entrypoint.sh /usr/local/bin/entrypoint.sh
72+
73+
USER dev
74+
WORKDIR /workspace
75+
76+
# Persist shell history and Claude state across rebuilds (volumes in devcontainer.json)
77+
ENV HISTFILE=/home/dev/.commandhistory/.zsh_history
78+
79+
ENV SHELL=/bin/zsh
80+
ENV DEVCONTAINER=true
81+
82+
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

0 commit comments

Comments
 (0)