Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 90 additions & 2 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: Checks

# Two lightweight structural checks that enforce project invariants which can't
# be caught by code review alone: zero dependencies and a valid CHANGELOG format.
# Lightweight structural checks that enforce project invariants which can't
# be caught by code review alone: zero dependencies, a valid CHANGELOG format,
# and no permission declarations in agent prompt files.
# These run on every push and PR — they're fast (no install step needed).

on:
Expand Down Expand Up @@ -55,3 +56,90 @@ jobs:
}
console.log('OK: ## [Unreleased] section found');
"

no-permissions-in-agent-prompts:
name: No permissions section in agent prompts
runs-on: ubuntu-latest
# Pattern enforced: permissions are declared exclusively in index.js via SUBAGENT_DEFS.
# A ## Permissions section in an agents/*.md file is purely documentary and diverges
# from the real enforcement — it creates false documentation. Any such section is
# mechanically forbidden (see docs/guiding-principles.md).
steps:
- uses: actions/checkout@v4

- name: Assert no ## Permissions section in agents/*.md
run: |
if grep -l '^## Permissions$' agents/*.md 2>/dev/null; then
echo "Error: Found '## Permissions' section in one or more agent prompt files."
echo "Permissions must be declared exclusively in index.js via SUBAGENT_DEFS."
echo "Remove the ## Permissions section from the files listed above."
exit 1
fi
echo "OK: no ## Permissions section found in agents/*.md"

# Pattern enforced: product briefs written by the brainstorm agent must be structurally valid
# so downstream agents (Planning, Orion) can parse them reliably. A brief missing required
# sections or frontmatter is not machine-actionable. This check catches structural regressions
# without validating content quality.
brief-schema:
name: Product brief schema check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Assert all docs/briefs/*.md files are structurally valid
run: |
shopt -s nullglob
brief_files=(docs/briefs/*.md)
if [ ${#brief_files[@]} -eq 0 ]; then
echo "OK: no briefs found — nothing to check"
exit 0
fi

failed=0

for file in "${brief_files[@]}"; do
file_failed=0

# Check frontmatter block (file must start with ---)
if ! head -1 "$file" | tr -d '\r' | grep -q '^---$'; then
echo "FAIL [$file]: missing YAML frontmatter (file must start with ---)"
file_failed=1
else
# Check required frontmatter fields
for field in project: type: status: created: updated:; do
if ! awk '/^---$/{f++; if(f==2) exit; next} f==1{print}' "$file" | grep -qE "^${field}($|[[:space:]])"; then
echo "FAIL [$file]: missing frontmatter field '${field}'"
file_failed=1
fi
done

# Check for duplicate frontmatter keys
dupes=$(awk '/^---$/{f++; if(f==2) exit; next} f==1 && /^[^#[:space:]]/{print $1}' "$file" | sort | uniq -d)
if [ -n "$dupes" ]; then
echo "FAIL [$file]: duplicate frontmatter key(s): $dupes"
file_failed=1
fi
fi

# Check required section headings
for section in "## Problem" "## Vision" "## Users" "## Core Use Cases" "## Success Criteria" "## Scope"; do
if ! grep -q "^${section}$" "$file"; then
echo "FAIL [$file]: missing section '${section}'"
file_failed=1
fi
done

if [ "$file_failed" -eq 0 ]; then
echo "OK: $file"
else
failed=1
fi
done

if [ "$failed" -ne 0 ]; then
echo ""
echo "Error: one or more brief files failed the schema check (see above)."
exit 1
fi

3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,9 @@ For the principles behind these rules, see [`docs/guiding-principles.md`](docs/g
| `eslint.config.js` + `npm run lint` | `node:` protocol prefix on all built-in imports in `*.js` files | Manually / pre-PR |
| `.github/workflows/checks.yml` job `zero-deps` | No `dependencies` or `devDependencies` in `package.json` | Every push + PR |
| `.github/workflows/checks.yml` job `changelog-unreleased` | `## [Unreleased]` section must exist in `CHANGELOG.md` | Every push + PR |
| `.github/workflows/checks.yml` job `agent-write-dirs-exist` | Every `write`/`edit` permission target directory declared in `index.js` must exist in the repo | Every push + PR |
| `.git-hooks/commit-msg` | Commit message is non-empty (guards against `git commit` without `-m`) | On commit (after `sh .git-hooks/install.sh`) |
| `docs/guiding-principles.md` | Non-interactive git, zero deps, user-facing CHANGELOG, default-deny permissions, external prompts | Human + Gardener review |
| `docs/guiding-principles.md` | Non-interactive git, zero deps, user-facing CHANGELOG, default-deny permissions, external prompts, write/edit target dirs | Human + Gardener review |
| `tests/lifecycle.test.js` + `npm test` | Correctness of the 5 lifecycle tool functions | Manually / pre-PR |

### Installing the git hook
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Exec-plans now support an optional `brief:` frontmatter field to trace the brainstorm → implementation link bidirectionally.

### Changed
- The `brainstorm` agent now challenges your assumptions before drafting — Phase 2 applies Socratic pressure on stated assumptions and constraints, and a mandatory adversarial gate runs before the brief is written: the agent presents the strongest case against building the product and asks what would cause it to fail. Briefs are stronger as a result.
- The `brainstorm` agent now hard-blocks on incomplete briefs — if the Problem statement, Success Criteria, or Scope In are missing or unresolved, the brief won't be drafted until those gaps are closed. Cosmetic disagreements are noted as open questions; substantive ones block the output entirely.
- Scope inflation is now flagged throughout the brainstorm session — if the in-scope list grows to 5 or more items, the agent surfaces it once and asks what's truly essential.
- Harness now operates fully autonomously — it explores the codebase, decides what to encode, and acts without asking for confirmation at each step. It only stops in three explicit cases: the pattern can't be mechanized, encoding requires creating a new workflow file, or the trigger is too vague with no codebase signal to anchor it.

### Fixed
- Lifecycle tools (`project_state`, `mark_block_done`, `complete_plan`, `register_spec`, `check_artifacts`) now return valid responses — previously the `execute` functions returned raw objects instead of strings, causing the OpenCode plugin API to silently discard their output
- Harness agent now has full `bash`, `read`, `write`, `edit`, `glob`, and `grep` permissions — previously it was registered with a restricted command allowlist and scoped file targets, which prevented it from running arbitrary lint commands or writing enforcement artifacts outside the predefined list.
- The harness agent no longer writes human-facing checklists to `AGENTS.md` — it now correctly identifies them as documentation and routes them to CI checks or `docs/guiding-principles.md` instead. An unwired script in the repo is also no longer treated as a valid enforcement artifact.
- Brainstorm agent now enforces a hard stop before responding to the user — the `docs/briefs/` scan is mandatory regardless of how much context the user provides at session start, preventing the agent from skipping existing brief detection

### Removed
- `memory.md` concept removed — the persistent project memory feature has been deprecated. The `experimental.chat.system.transform` hook and memory.md injections have been removed from the plugin. Only the scratchpad survives compaction.
Expand Down
Loading
Loading