feat: YOLO mode, fully-customizable guard, customization skill + installer wiring#423
Merged
Merged
Conversation
2026-06-20-issue-audit.md was a temporary analysis artifact from a triage run — not referenced anywhere and not part of the published package (files allowlist). Remove it to keep the repo root clean. Co-authored-by: Claude Fable 5 <81847+claude@users.noreply.github.com>
Adds opt-in YOLO mode and per-command customization so the whole guard is tunable from config/env: - yolo: relaxes the soft gates (network-exec block, completion enforcement, subagent lock, block toasts); destructive guarding stays on by default. - allowDestructive: turns off destructive guarding too — with yolo that is 'full YOLO' (nothing blocked); works standalone as a direct override. - allowCommands: regex allow-list; a matching bash command is never blocked. - extraDestructive: regex deny-list; matching commands are treated destructive. YOLO only relaxes keys the user did not set explicitly, so any per-key option still wins. New GOAL_GUARD_* env vars + opencode.json options for all of the above; documented in the README config table with a YOLO section. 10 new tests. Co-authored-by: Gemini <gemini@users.noreply.github.com>
…he installer - Add a goal-mode-customization skill (skills/goal-mode-customization/SKILL.md) and a /goal-mode-customize OpenCode command that teach the agent how to tune the guard (config keys, YOLO, allow/deny rules, sidebar) and apply it correctly. - Installer ships them: 'skills' is now a COMPONENT_DIR and skills/ is in the npm files allowlist, so the skill+command install with the package and are refreshed on every (re)install. Manifest-tracked, so --uninstall removes them. - Update flow: postinstall already re-runs the installer on a global update; add explicit 'update' (npm i -g @latest) and 'reinstall' (installer --force) scripts. - install.test.mjs updated to assert the skill+command install and the new COMPONENT_DIRS shape. Co-authored-by: codeplane-agent[bot] <287208015+codeplane-agent[bot]@users.noreply.github.com>
devinoldenburg
commented
Jun 21, 2026
devinoldenburg
left a comment
Owner
Author
There was a problem hiding this comment.
Independent review — verdict: APPROVE (sound)
(Posting as a comment: GitHub blocks self-approval since I'm the PR author. No blocking defects found.)
Reviewed rigorously against all focus areas; verified by running the suite, lint, validator, config probes, and a full installer lifecycle.
Verification performed
node --test tests/*.test.mjs→ 660 pass / 0 fail (incl. 10 new YOLO/customization tests + the install assertion).npm run lintexits 0;node scripts/validate-opencode-config.mjspasses;npm pack --dry-runshipsskills/goal-mode-customization/SKILL.md+commands/goal-mode-customize.md.- Full installer lifecycle into a temp config dir: install copies skill+command and records them in the manifest, reinstall is idempotent (0 copied),
--uninstallremoves them cleanly including the now-emptyskills/dir.
Focus-area findings (all sound)
- YOLO security/correctness —
yolorelaxes only the four intended soft gates (blockNetworkExec,enforceCompletion,restrictSubagents,toastOnBlock); destructive guarding stays on. 'Explicit per-key wins' holds for both env and options (theexplicitset is seeded fromenvConfigkeys and grows in the opts loop — verified:{yolo:true}+GOAL_GUARD_BLOCK_NETWORK_EXEC=1keeps blocking on;{restrictSubagents:true}+GOAL_GUARD_YOLO=1keeps the lock).allowDestructiveis correctly gated and works standalone. Defaultyolo:false→ no accidental disabling. - Allow-list bypass (guard.js:582,586-587) — applied only to the block decision; invalid patterns are swallowed in
compileGuardPatterns;allowCommandPatterns.length>0short-circuit means the empty default never bypasses anything;lastIndex=0reset is harmless/defensive. User-supplied regex ReDoS is the user's own opt-in, not a guard vuln. - extraDestructive precedence (guard.js:585-586) — allowlist correctly wins (
!allowlisted && ... destructive). Test proves the allow path AND that a sibling command is still blocked. - Config persistence —
allowCommands/extraDestructiveresolve to frozen string arrays; regex compilation lives in guard.js, so no RegExp leaks into the (snapshotted) config.JSON.stringifyround-trips cleanly. - Installer —
skillsis a safe relative COMPONENT_DIR; the existingdoesNotMatch /auth|sessions|.../guard test still holds; manifest-tracked install/uninstall verified. - Tests — non-tautological (assert both the bypass and the still-blocked counter-case; invalid-pattern test proves the guard still functions).
Nits (non-blocking)
tests/yolo.test.mjs:1-2— BiomeorganizeImportswants the two imports sorted.npm run lintdoesn't gate on it (exits 0), so harmless, but worth a one-line fix.guard.js:580-581— the 'no dirty mark' comment is precise for the before-hook, buttool.execute.afterdoes not consult the allowlist, so an allow-listed destructive command still marks an active goal session dirty. This is arguably correct (the command did run/mutate) and never blocks — just slightly broader than the comment implies.coerceListstringifies non-string inputs (object →"[object Object]", arraynull→"null"). These compile to inert/non-matching regexes or are swallowed, so garbage-in is non-fatal — no change required.- README uses
./plugins/goal-guard.jswhile the skill/command useopencode-goal-mode; both are valid OpenCode plugin refs and each file is internally consistent.
Solid, well-tested, safe-by-default change. LGTM.
2efded3 to
5391b41
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes the Goal Mode guard highly customizable, adds an opt-in YOLO mode, ships a customization skill installed via the installer, and tidies the repo. Built as small, atomic commits.
Commits
2026-06-20-issue-audit.md(not referenced, not packaged).YOLO mode & customization (config/env)
yolo— relax the soft gates (network-exec block, completion enforcement, Goal-only subagent lock, block toasts); destructive guarding stays on.allowDestructive— turn destructive guarding off too; withyolo= full YOLO (nothing blocked, all rights). Works standalone.allowCommands— regex allow-list; a matching bash command is never blocked.extraDestructive— regex deny-list; matching commands are treated destructive.GOAL_GUARD_*env vars +opencode.jsonoptions; invalid custom regexes are ignored, never fatal. Documented in the README config table + a YOLO section.Customization skill + installer/update
skills/goal-mode-customization/SKILL.mdand a/goal-mode-customizecommand teach the agent how to tune the guard and apply the change.skillsis a newCOMPONENT_DIR,skills/is in the npmfilesallowlist, so they install with the package and refresh on every (re)install;--uninstallremoves them (manifest-tracked).postinstallalready re-runs the installer on a global update; added explicitupdate/reinstallscripts.Verification
node --test "tests/*.test.mjs"→ 660 pass, 0 fail (10 new YOLO/customization tests; install test asserts the skill+command install).npm run lintclean;node scripts/validate-opencode-config.mjspasses;npm run publish:check -- --skip-registryready;npm pack --dry-runshipsskills/+ the command.Does not touch Issue #2.