From 0c90c1a0fbe14526d768a04c820aa06711cb6b6f Mon Sep 17 00:00:00 2001 From: Patient Eden Date: Sat, 14 Mar 2026 06:53:06 +0000 Subject: [PATCH] feat(ci): add GitHub Actions workflow for structural validation Adds .github/workflows/ci.yml to validate the starter kit's integrity on every push and PR to main. Since this repo contains no TypeScript or test files, the workflow validates what actually exists: required markdown/JSON files are present, JSON files parse correctly, and key structural sections are in place (CLAUDE.md identity sections, daemon/loop.md phase references). Closes #10 Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 112 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..bdfaea2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,112 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check required files exist + run: | + required_files=( + "CLAUDE.md" + "SOUL.md" + "SKILL.md" + "README.md" + "daemon/loop.md" + "daemon/health.json" + "daemon/queue.json" + "daemon/processed.json" + "daemon/outbox.json" + "memory/journal.md" + "memory/contacts.md" + "memory/learnings.md" + ) + missing=0 + for f in "${required_files[@]}"; do + if [ ! -f "$f" ]; then + echo "MISSING: $f" + missing=$((missing + 1)) + else + echo "OK: $f" + fi + done + if [ "$missing" -gt 0 ]; then + echo "" + echo "Error: $missing required file(s) missing from starter kit." + exit 1 + fi + + - name: Validate health.json is valid JSON + run: | + python3 -c "import json, sys; json.load(open('daemon/health.json'))" \ + && echo "OK: daemon/health.json is valid JSON" \ + || (echo "Error: daemon/health.json is not valid JSON" && exit 1) + + - name: Validate queue.json is valid JSON + run: | + python3 -c "import json, sys; json.load(open('daemon/queue.json'))" \ + && echo "OK: daemon/queue.json is valid JSON" \ + || (echo "Error: daemon/queue.json is not valid JSON" && exit 1) + + - name: Validate processed.json is valid JSON + run: | + python3 -c "import json, sys; json.load(open('daemon/processed.json'))" \ + && echo "OK: daemon/processed.json is valid JSON" \ + || (echo "Error: daemon/processed.json is not valid JSON" && exit 1) + + - name: Validate outbox.json is valid JSON + run: | + python3 -c "import json, sys; json.load(open('daemon/outbox.json'))" \ + && echo "OK: daemon/outbox.json is valid JSON" \ + || (echo "Error: daemon/outbox.json is not valid JSON" && exit 1) + + - name: Check CLAUDE.md has required sections + run: | + required_sections=( + "## Identity" + "## Default Wallet" + "## GitHub" + ) + missing=0 + for section in "${required_sections[@]}"; do + if ! grep -qF "$section" CLAUDE.md; then + echo "MISSING section in CLAUDE.md: $section" + missing=$((missing + 1)) + else + echo "OK: $section" + fi + done + if [ "$missing" -gt 0 ]; then + echo "" + echo "Error: $missing required section(s) missing from CLAUDE.md." + exit 1 + fi + + - name: Check daemon/loop.md has required phases + run: | + required_phases=( + "heartbeat" + "inbox" + "health" + ) + missing=0 + for phase in "${required_phases[@]}"; do + if ! grep -qi "$phase" daemon/loop.md; then + echo "MISSING phase reference in daemon/loop.md: $phase" + missing=$((missing + 1)) + else + echo "OK: phase '$phase' referenced" + fi + done + if [ "$missing" -gt 0 ]; then + echo "" + echo "Error: $missing required phase(s) missing from daemon/loop.md." + exit 1 + fi