What happened
Phase 4 step 5 (self-review post) and Phase 6 (commit) prescribe the "$(cat <<'EOF' ... EOF)" command-substitution form:
gh pr comment <number> --body "$(cat <<'EOF'
...
EOF
)"
and
git commit -m "$(cat <<'EOF'
...
EOF
)"
In at least one downstream harness (a gardener tend headless dispatch of the medieval-factions-dev-loop skill, generated from this template), this exact invocation is rejected outright by the Bash tool's static command classifier with Contains command_substitution — it never reaches the shell. Two related rejections were observed in the same session: grep -rn "a\|b" <path> was rejected with Contains simple_expansion (the \| alternation), and both git diff origin/main...HEAD --stat and an awk one-liner containing || came back as This command requires approval — a hard block in a headless run with no human available to approve.
Why it matters
This is template-wide: every generated dev-loop skill inherits these exact snippets in Phase 4 step 5 and Phase 6, including the phase whose output is the loop's main audit artifact (the self-review comment). An agent that follows the prescribed form literally, rather than improvising a workaround, fails to post its self-review or its commit at all.
Workaround that worked
Write the body with the Write tool to a scratch path inside the working directory, then pass it by file — --body-file / -F avoid command substitution entirely and preserve the multi-line formatting the heredoc was protecting:
gh pr comment <number> --body-file /path/in/workdir/selfreview.md
gh issue create --title "..." --body-file /path/in/workdir/issue.md
git commit -F /path/in/workdir/commitmsg.txt
Suggested instruction text
Replace the "$(cat <<'EOF' ... EOF)" snippets in Phase 4 step 5 and Phase 6 with the --body-file / -F form above, and add a line near the existing scratch-file-handling rule (create-dev-loop.md:259):
Avoid command substitution in Bash tool calls. Some harnesses' command classifiers reject $(...) outright, so a prescribed --body "$(cat <<'EOF' ... EOF)" can fail before reaching the shell. Compose long bodies with the Write tool to a scratch file inside the working directory and pass --body-file (gh) or -F (git commit). Likewise prefer separate grep invocations over \| alternation, which some classifiers flag as an expansion.
Also observed (not filed separately — mention if useful)
gh pr comment failed twice with transient HTTP/2 transport errors (http2: client conn could not be established, then unexpected EOF) before succeeding on a third attempt. Nothing in Edge cases mentions retrying a transient gh network failure; an agent treating the first failure as terminal would silently drop its self-review. A one-line "retry transient gh network errors once or twice before treating them as blocked" in Edge cases would cover it.
Originally filed against dmccoystephenson/medieval-factions-dev-loop#24 and routed upstream per that skill's template-rule policy — this is a harness/template-wide gap, not Medieval-Factions-specific.
What happened
Phase 4 step 5 (self-review post) and Phase 6 (commit) prescribe the
"$(cat <<'EOF' ... EOF)"command-substitution form:and
In at least one downstream harness (a
gardener tendheadless dispatch of themedieval-factions-dev-loopskill, generated from this template), this exact invocation is rejected outright by the Bash tool's static command classifier withContains command_substitution— it never reaches the shell. Two related rejections were observed in the same session:grep -rn "a\|b" <path>was rejected withContains simple_expansion(the\|alternation), and bothgit diff origin/main...HEAD --statand anawkone-liner containing||came back asThis command requires approval— a hard block in a headless run with no human available to approve.Why it matters
This is template-wide: every generated dev-loop skill inherits these exact snippets in Phase 4 step 5 and Phase 6, including the phase whose output is the loop's main audit artifact (the self-review comment). An agent that follows the prescribed form literally, rather than improvising a workaround, fails to post its self-review or its commit at all.
Workaround that worked
Write the body with the
Writetool to a scratch path inside the working directory, then pass it by file —--body-file/-Favoid command substitution entirely and preserve the multi-line formatting the heredoc was protecting:Suggested instruction text
Replace the
"$(cat <<'EOF' ... EOF)"snippets in Phase 4 step 5 and Phase 6 with the--body-file/-Fform above, and add a line near the existing scratch-file-handling rule (create-dev-loop.md:259):Also observed (not filed separately — mention if useful)
gh pr commentfailed twice with transient HTTP/2 transport errors (http2: client conn could not be established, thenunexpected EOF) before succeeding on a third attempt. Nothing in Edge cases mentions retrying a transientghnetwork failure; an agent treating the first failure as terminal would silently drop its self-review. A one-line "retry transientghnetwork errors once or twice before treating them as blocked" in Edge cases would cover it.Originally filed against dmccoystephenson/medieval-factions-dev-loop#24 and routed upstream per that skill's template-rule policy — this is a harness/template-wide gap, not Medieval-Factions-specific.