docs: correct grok's read-only story; delete the orphaned grok-args - #788
Merged
Conversation
The docs described a guard that does not exist. docs/CAPABILITIES.md and
docs/harnesses.md both said a mode: read-only skill is confined on grok by an
explicit tool allowlist under grok's own --sandbox read-only, generated by
scripts/skill_mode.sh grok-args.
Every part of that is wrong:
* adapters/grok.sh carries no allowlist, deliberately. Headless grok aborts
the entire turn on a denied tool (stopReason=Cancelled) instead of
degrading, and skills are authored for Claude Code, so they reach for tools
no allowlist predicted. It runs --permission-mode bypassPermissions with no
--allow and no --deny rules.
* grok's own --sandbox read-only is silently ignored on grok 0.2.101 (writes
still land) and nest-conflicts with the wrapper sandbox.
* grok-args itself had no callers once run-grok.sh became setup-only (#785).
So an operator reading either doc would conclude a read-only grok skill was
tool-confined when nothing was confining it. What actually enforces read-only,
on all six harnesses, is the dispatcher's OS sandbox in
harness-adapter/lib/sandbox.sh plus the workflow's post-run revert.
Changes:
* scripts/skill_mode.sh - grok-args removed, not rewired: the real mechanism
is not expressible in this file. A tombstone comment records why it should
not come back in that shape. The header no longer claims allowedTools is
the enforcement.
* docs/CAPABILITIES.md - replaces the wrong paragraph with the three
enforcement layers and which one is load-bearing, plus why native harness
sandboxes are not relied on (codex's kills the network, grok's is ignored,
pi/vibe/kimi have none). Also disambiguates capabilities: [read_only]
(documentation, unenforced) from mode: read-only (enforced).
* docs/harnesses.md - rewrites the capability-mode section for grok.
* harness-adapter/lib/sandbox.sh - header said "five harnesses" and named
opencode, which is not one of the six.
* harness-adapter/docs/aeon-integration.md - marks its three-branch shape as
superseded; aeon routes every harness through run-harness now.
* scripts/tests/test_skill_mode.sh - the three grok-args cases asserted a
guard that never worked. Replaced with a guard that the subcommand stays
gone and that the usage line no longer advertises it.
All 17 capability-mode tests pass, plus notify, skill-requires, harness-adapter
grok and run-grok suites; okf-validate clean.
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.
Follow-up to #785 and #787. Two loose ends flagged there, which turn out to be the same defect: the docs describe a read-only guard that does not exist, and the code they cite is dead.
The claim, and why every part of it is false
docs/CAPABILITIES.mdanddocs/harnesses.mdboth said that amode: read-onlyskill is confined on grok by an explicit tool allowlist under grok's own--sandbox read-only, generated byscripts/skill_mode.sh grok-args:adapters/grok.shcarries no allowlist, deliberately. Headless grok aborts the entire turn on a denied tool (stopReason=Cancelled) instead of degrading, and skills are authored for Claude Code, so they reach for tools no allowlist predicted. It runs--permission-mode bypassPermissionswith no--allowand no--denyrules.--sandbox read-onlyis silently ignored on grok 0.2.101 — writes still land — and it nest-conflicts with the wrapper sandbox.grok-argshad no callers at all oncerun-grok.shbecame setup-only in chore(grok): reduce run-grok.sh to setup-only, move its tests to the adapter #785.--permission-mode dontAsk, which is not what any code path passes.An operator reading either doc would have concluded a read-only grok skill was tool-confined. Nothing was confining it. #787 is what actually fixed the runtime hole; this fixes the document that would have told you there was no hole.
What actually enforces read-only
The dispatcher's OS sandbox (
harness-adapter/lib/sandbox.sh—bwrap --ro-bindon Linux,sandbox-execon macOS), on all six harnesses, plus the workflow's post-run revert.CAPABILITIES.mdnow lays out the three layers and says which one is load-bearing:Write/Edit/git/gh/python3from the model's tool setIt also records why native harness sandboxes are not relied on: codex's works but kills the network, grok's is ignored, and pi/vibe/kimi ship none.
grok-argsis removed, not rewiredThe other option was to point it at the real mechanism. That is not possible — an OS sandbox applied by the dispatcher is not expressible as a permission-flag generator, and the file's entire premise was mirroring
allowedToolsinto grok's grammar. A tombstone comment records why it should not come back in that shape.Tests
The three
grok-argscases asserted the properties of a guard that never worked (grok read-only tier sets --sandbox read-only— grok ignores it). Deleting them outright would leave nothing recording that this was tried and rejected, so they are replaced by a guard that the subcommand stays gone and that the usage line no longer advertises it.One trap worth noting: the natural way to assert the usage message —
fails under the suite's
set -o pipefail, because the script's ownexit 2becomes the pipeline's status even though the grep matched. Captured into a variable first.Also swept up
harness-adapter/lib/sandbox.sh— header said "all five harnesses" and namedopencode, which is not one of the six.harness-adapter/docs/aeon-integration.md— its three-branch shape (grok -> untouched run-grok.sh) predates refactor(harness): route messages.yml + mcp-server through run-harness #784. Marked superseded rather than rewritten, since it is a historical deployment runbook; it now points a fresh integrator at routing everything throughrun-harnessfrom the start.Verification
test_skill_mode(17),test_notify,test_skill_requires,test_harness_adapter_grok,test_run_grok— all pass.okf-validateclean.shellcheck -S warningclean on both edited scripts (sandbox.sh's SC2148 is pre-existing onmain— no shebang on a sourced lib — and CI does not run shellcheck).No runtime behaviour changes:
grok-argshad no callers, and every other edit is a comment or a document.