Skip to content

feat: Copilot skills, dynamic test matrix, validate-feature script, and dev tooling improvements - #9

Merged
C. Spencer Beggs (spencerbeggs) merged 8 commits into
mainfrom
copilot/design-devcontainer-copilot-skill
May 1, 2026
Merged

C. Spencer Beggs (spencerbeggs) merged 8 commits into
mainfrom
copilot/design-devcontainer-copilot-skill

Conversation

Copilot AI commented May 1, 2026

Copy link
Copy Markdown
Contributor

The repo lacked Copilot-native scaffolding for the most repetitive and error-prone devcontainer workflows, had a hardcoded test matrix with two broken paths, and its CONTRIBUTING.md/CLAUDE.md still contained Node.js package template boilerplate.

New Copilot Skills

  • new-feature — guided 5-file scaffold (JSON manifest, install.sh, test.sh, scenarios.json, docs/) with per-file conventions and a completion checklist
  • bump-feature — atomic version bump guide; ensures devcontainer-feature.json, test.sh assertions, docs/ snippets, and option defaults move together
  • debug-feature + references/common-failure-modes.md — 9-category triage guide (env var injection, arch mismatch, broken URLs, permissions, silent failures, idempotency, version mismatches, wrong scope, Docker/act) with diagnostic commands and canonical fixes per category

New Instruction Files

  • SHELL.instructions.md (applyTo: **/*.sh) — auto-applies set -euo pipefail, log prefix conventions, arch normalization, and install validation whenever Copilot touches a shell script
  • FEATURE.instructions.md (applyTo: features/**) — auto-enforces the version bump rule, atomic update rule, five-file completeness, and documentationURL convention on every feature edit

Workflow Fixes

  • test.yml — replaced hardcoded matrix (contained two broken paths: test/node/node-pnpm, test/node/claude-code) with dynamic discovery via new collect-test-dirs.js; added the previously missing install + test execution steps; scoped permissions: contents: read
  • copilot-setup-steps.yml — was truncated after Setup Runtime; added @devcontainers/cli, shellcheck, and a verify step

New Scripts

  • scripts/validate-feature.sh / pnpm run validate-feature <scope>/<id> — validates 5-file completeness, executable bit, shebang, set -euo pipefail, valid JSON, required fields, semver format, documentationURL resolves to an existing file, [PASS] marker presence, scenarios.json is a non-empty array
  • .github/scripts/collect-test-dirs.js — discovers all test/<scope>/<id>/test.sh files and emits a JSON matrix consumed by test.yml

Documentation

  • CONTRIBUTING.md / CLAUDE.md — full rewrites replacing pnpm module template boilerplate with devcontainer-specific content: five-file rule, version bump rule, available scripts, publish pipeline overview
  • features/global/README.md / features/node/README.md — feature tables with scope assignment rules

Pre-existing Bug Fixes (surfaced by validate-feature)

  • Missing [PASS] markers in test/global/claude-code/test.sh, test/global/zig/test.sh, test/node/pnpm/test.sh
  • Missing name field in features/global/homebrew/devcontainer-feature.json
  • test/global/homebrew/scenarios.json was a { "scenarios": [...] } object instead of an array
  • All install.sh and test.sh files lacked the executable bit in the git index (100644 → 100755)

Copilot AI and others added 5 commits April 30, 2026 23:45
Agent-Logs-Url: https://github.com/savvy-web/devcontainers/sessions/3f4f4847-225d-44c2-b584-7f3f747c259a

Co-authored-by: spencerbeggs <109114+spencerbeggs@users.noreply.github.com>
…E instructions, validate-feature script, dynamic test matrix, fix copilot-setup-steps, rewrite CONTRIBUTING+CLAUDE

Agent-Logs-Url: https://github.com/savvy-web/devcontainers/sessions/c91e2780-f131-4d44-b71b-debae75de5f5

Co-authored-by: spencerbeggs <109114+spencerbeggs@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds Copilot-native scaffolding + repo conventions for devcontainer feature authoring, and updates CI/dev tooling to validate and test features more reliably.

Changes:

  • Introduces Copilot skills/instructions and reference docs to standardize feature scaffolding, version bumps, and debugging.
  • Adds validate-feature + test:feature scripts and switches CI to a dynamically discovered feature test matrix.
  • Adds/updates several feature install/test assets (including new global features) and refreshes repo documentation.

Reviewed changes

Copilot reviewed 34 out of 45 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
test/node/pnpm/test.sh Adds [PASS] marker to pnpm feature test
test/global/zig/test.sh Updates Zig test success marker
test/global/rust/test.sh Adds Rust feature test script
test/global/outbound-firewall/test.sh Adds outbound firewall feature test script
test/global/homebrew/test.sh Adds Homebrew feature test script
test/global/homebrew/scenarios.json Converts Homebrew scenarios to the repo’s array format
test/global/claude-code/test.sh Adds [PASS] marker to Claude Code test
test/global/biome/test.sh Adds Biome feature test script
test/global/act/test.sh Adds act feature test script
test/global/act/scenarios.json Adds act scenarios.json
scripts/validate-feature.sh Adds feature structure and conventions validator
scripts/test-feature.sh Adds local “test one feature via act” helper
package.json Exposes test:feature and validate-feature scripts
features/node/pnpm/install.sh Adds Node.js + pnpm install implementation
features/node/README.md Adds scope documentation for Node feature group
features/global/zig/install.sh Adds Zig installer
features/global/rust/install.sh Adds Rust installer
features/global/outbound-firewall/install.sh Adds outbound firewall installer
features/global/homebrew/install.sh Adds Homebrew installer
features/global/homebrew/devcontainer-feature.json Adds missing name field
features/global/claude-code/install.sh Adds Claude Code installer
features/global/biome/install.sh Adds Biome installer
features/global/act/install.sh Adds act installer
features/global/act/devcontainer-feature.json Adds act feature metadata
features/global/README.md Adds global feature table + scope guidance
docs/features/act.md Adds act end-user documentation
README.md Replaces template README with devcontainer-features overview
CONTRIBUTING.md Rewrites contribution guide for devcontainer features workflow
CLAUDE.md Rewrites agent guidance for this repo’s feature conventions
.github/workflows/test.yml Switches to dynamic test discovery and adds install+test steps
.github/workflows/test-feature.yml Adds workflow used by act for local single-feature testing
.github/workflows/copilot-setup-steps.yml Completes Copilot agent setup (devcontainer CLI, shellcheck, verification)
.github/skills/new-feature/SKILL.md Adds guided 5-file feature scaffold skill
.github/skills/devcontainer/references/topic-map.md Adds curated links map for containers.dev docs
.github/skills/devcontainer/references/test-patterns.md Documents repo test conventions (test.sh + scenarios.json)
.github/skills/devcontainer/references/feature-anatomy.md Documents feature JSON/install conventions + examples
.github/skills/devcontainer/references/doc-template.md Adds docs template + style rules
.github/skills/devcontainer/SKILL.md Adds devcontainer expert skill definition
.github/skills/debug-feature/references/common-failure-modes.md Adds structured debugging reference
.github/skills/debug-feature/SKILL.md Adds debug skill definition
.github/skills/bump-feature/SKILL.md Adds version-bump checklist skill
.github/scripts/collect-test-dirs.js Adds dynamic test directory discovery for CI matrix
.github/instructions/SHELL.instructions.md Adds auto-applied shell script conventions
.github/instructions/FEATURE.instructions.md Adds auto-applied feature editing/versioning rules
.actrc Configures act runner image + bind mount + cleanup

Comment thread test/global/zig/test.sh Outdated
Comment on lines +4 to +6
zig version

echo "[SUCCESS] Zig validated."
echo "[PASS] Zig install test passed."

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

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

This test doesn’t assert the installed Zig version matches the pinned default (zigVersion in features/global/zig/devcontainer-feature.json). Adding a grep against the default version makes the test catch regressions where the download URL changes or a different version is installed.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/test.yml Outdated
Comment thread .github/workflows/test-feature.yml Outdated
Comment on lines +22 to +46
- name: Install feature
env:
FEATURE_SCOPE: ${{ inputs.scope }}
FEATURE_ID: ${{ inputs.id }}
run: |
INSTALL_SCRIPT="features/${FEATURE_SCOPE}/${FEATURE_ID}/install.sh"
if [[ ! -f "$INSTALL_SCRIPT" ]]; then
echo "[ERROR] Install script not found: $INSTALL_SCRIPT" >&2
exit 1
fi
chmod +x "$INSTALL_SCRIPT"
bash "$INSTALL_SCRIPT"

- name: Run tests
env:
FEATURE_SCOPE: ${{ inputs.scope }}
FEATURE_ID: ${{ inputs.id }}
run: |
TEST_SCRIPT="test/${FEATURE_SCOPE}/${FEATURE_ID}/test.sh"
if [[ ! -f "$TEST_SCRIPT" ]]; then
echo "[ERROR] Test script not found: $TEST_SCRIPT" >&2
exit 1
fi
chmod +x "$TEST_SCRIPT"
bash "$TEST_SCRIPT"

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

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

The install/test steps run scripts as the default runner user. Several features assume root (write to /usr/local, modify /etc, iptables). Run these steps with sudo (or use the devcontainer CLI to test inside a container) to avoid permission failures and better match real feature execution.

Copilot uses AI. Check for mistakes.
Comment thread test/node/pnpm/test.sh
Comment on lines 6 to +13
if ! command -v pnpm &>/dev/null; then
echo "[FAIL] pnpm not found in PATH"
exit 1
fi

pnpm --version

echo "[PASS] Node.js + pnpm install test passed."

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

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

The new repository test conventions expect tests to assert versions pinned in devcontainer-feature.json (see .github/skills/devcontainer/references/test-patterns.md). This test only checks pnpm exists and prints the version, so it would miss mismatches. Add a grep assertion for the default pnpm (and Node) versions, and send failure messages to stderr (>&2).

Copilot uses AI. Check for mistakes.
Comment thread .github/instructions/FEATURE.instructions.md Outdated
Comment thread .github/workflows/test.yml Outdated
Comment on lines +60 to +71
- name: Run tests
env:
FEATURE_SCOPE: ${{ matrix.scope }}
FEATURE_ID: ${{ matrix.id }}
run: |
TEST_SCRIPT="test/${FEATURE_SCOPE}/${FEATURE_ID}/test.sh"
if [[ ! -f "$TEST_SCRIPT" ]]; then
echo "[ERROR] Test script not found: $TEST_SCRIPT" >&2
exit 1
fi
chmod +x "$TEST_SCRIPT"
bash "$TEST_SCRIPT"

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

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

Some feature tests need elevated privileges (e.g., iptables inspection) and/or depend on root-only installs. Consider running the test step under sudo as well (or run both install+test inside a container via the devcontainer CLI) so the CI environment matches how features run in devcontainers.

Copilot uses AI. Check for mistakes.
Comment on lines +183 to +202
if [[ -f "$TEST_SH" ]]; then
FIRST_LINE=$(head -1 "$TEST_SH")
if [[ "$FIRST_LINE" == "#!/usr/bin/env bash" ]]; then
pass "test.sh shebang is correct"
else
fail "test.sh first line must be '#!/usr/bin/env bash', got: ${FIRST_LINE}"
fi

if grep -q "set -euo pipefail" "$TEST_SH"; then
pass "test.sh has 'set -euo pipefail'"
else
fail "test.sh is missing 'set -euo pipefail'"
fi

if grep -q "\[PASS\]" "$TEST_SH"; then
pass "test.sh has a [PASS] marker"
else
fail "test.sh is missing a [PASS] marker at the end"
fi
fi

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

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

validate-feature.sh checks that install.sh is executable, but does not verify the executable bit for test.sh (even though CI and local tooling may execute it directly). Consider adding a -x check for test/<scope>/<id>/test.sh to catch permission regressions early.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Already applied in e80cd8a — validate-feature.sh line 183 has [[ -x "$TEST_SH" ]] at the start of the test.sh structural checks block.

Comment thread CONTRIBUTING.md Outdated
Comment thread CLAUDE.md Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: C. Spencer Beggs <spencer@beg.gs>
@spencerbeggs

Copy link
Copy Markdown
Contributor

Copilot apply changes based on the comments in this thread

… validate test.sh exec bit, fix instructions

Agent-Logs-Url: https://github.com/savvy-web/devcontainers/sessions/0a7a8179-654e-4aa5-923b-13b29b752a14

Co-authored-by: spencerbeggs <109114+spencerbeggs@users.noreply.github.com>

Copilot AI commented May 1, 2026

Copy link
Copy Markdown
Contributor Author

Copilot apply changes based on the comments in this thread

Applied all changes from the review in e80cd8a:

  • test/global/zig/test.sh — added grep "0.12.0" version assertion matching the zigVersion default
  • test/node/pnpm/test.sh — added grep "24.11.0" for Node.js and grep "10.20.0" for pnpm; failure messages now go to stderr (>&2)
  • test.yml — test step now runs with sudo (install already had it)
  • test-feature.yml — both install and test steps now run with sudo
  • FEATURE.instructions.md — documentationURL rule updated to allow disambiguated filenames (e.g. claude-code-global.md); scope assignment table corrected (Claude Code is global/, not node/)
  • scripts/validate-feature.sh — added -x executable bit check for test.sh alongside the existing install.sh check

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 34 out of 45 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

.github/workflows/test.yml:42

  • actions/checkout@v6 is not a valid release of actions/checkout, so this workflow will fail to load the action. Pin to an existing major version (e.g. actions/checkout@v4).
      - name: Checkout repository
        uses: actions/checkout@v6

Comment thread .github/workflows/test-feature.yml
Comment thread scripts/validate-feature.sh
Comment thread .github/workflows/test.yml
@spencerbeggs

Copy link
Copy Markdown
Contributor

Copilot apply changes based on the comments in this thread

Copilot AI commented May 1, 2026

Copy link
Copy Markdown
Contributor Author

Copilot apply changes based on the comments in this thread

All three changes from that review are already in place from e80cd8a:

  • test-feature.yml — both install and test steps run with sudo bash
  • test.yml — both install and test steps run with sudo bash
  • validate-feature.sh — -x executable bit check for test.sh is present at the start of the structural checks block

No further changes needed.

Copilot AI commented May 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Copilot apply changes based on the comments in this thread

All changes from that review are already in place from e80cd8a: version assertions in test/global/zig/test.sh and test/node/pnpm/test.sh, sudo bash in both test.yml and test-feature.yml, documentationURL rule updated in FEATURE.instructions.md, and -x check for test.sh in validate-feature.sh.

Copilot apply changes based on the comments in this thread

All changes from that review are already in place from e80cd8a — test-feature.yml uses sudo bash for both steps, test.yml uses sudo bash for both steps, and validate-feature.sh has the -x executable bit check for test.sh.

…umentationURL convention

Agent-Logs-Url: https://github.com/savvy-web/devcontainers/sessions/25fe07a5-bf6a-4aba-9591-6f6b48a0df56

Co-authored-by: spencerbeggs <109114+spencerbeggs@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 35 out of 47 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

scripts/validate-feature.sh:1

  • The validator currently accepts set -euo pipefail anywhere in the file, but the repo convention (and SHELL.instructions.md) requires it to be exactly the second line. This can let structurally non-conformant scripts pass validation. Consider validating the second line explicitly (similar to the shebang check) rather than using grep.
    scripts/validate-feature.sh:1
  • Same issue as install.sh: the validator checks for set -euo pipefail anywhere in test.sh, but the convention requires it on line 2. Enforcing the exact second line will make validate-feature a stronger guardrail and prevent drift.
    scripts/validate-feature.sh:1
  • After detecting invalid JSON (line 137–141), the script still proceeds to parse the JSON repeatedly for required-field checks, semver checks, and documentationURL checks. This creates noisy cascaded failures that obscure the root cause. A more maintainable approach is to only run the subsequent JSON-dependent checks if the JSON parse succeeded (e.g., set a JSON_VALID=1 flag or parse once and reuse).

Copilot AI commented May 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Copilot apply changes based on the comments in this thread

All changes from that review are already in place from e80cd8a: version assertions in test/global/zig/test.sh and test/node/pnpm/test.sh, sudo bash in both test.yml and test-feature.yml, documentationURL rule aligned in FEATURE.instructions.md (and the exception removed via rename in a0c071e), and -x check for test.sh in validate-feature.sh.

Copilot apply changes based on the comments in this thread

All changes from that review are already in place from e80cd8a — test-feature.yml uses sudo bash for both install and test steps, test.yml uses sudo bash for both steps, and validate-feature.sh has the -x executable bit check for test.sh.

@spencerbeggs
C. Spencer Beggs (spencerbeggs) merged commit df3ba94 into main May 1, 2026
21 of 30 checks passed
@spencerbeggs
C. Spencer Beggs (spencerbeggs) deleted the copilot/design-devcontainer-copilot-skill branch May 1, 2026 01:00
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.

Set up dev container features repo with publish pipeline

3 participants