feat(planning): draft-goal-condition skill — docs-conformant /goal shape + mechanical length gate - #592
Conversation
…length gate Craft a paste-ready /goal completion condition from a stated intent. The skill reads the current official /goal docs live for the condition shape and character limit (nothing hardcoded, so it does not rot when the documented contract changes between Claude Code versions), drafts a transcript-demonstrable condition, and — since a model cannot reliably count characters — proves the draft fits the limit with a deterministic counter (scripts/goal-condition-length.sh, caller passes the live limit; exit 0 within / 1 over / 2 usage) covered by a companion test. A step-0 lever-fit gate routes interval-shaped work to /loop and cloud/sessionless work to routines/schedule instead of authoring a goal. Bumps planning 0.21.2 -> 0.22.0 (minor, new feature). Closes #481 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011V31qpAHP3jfs76B9d5Rfo
|
Claude finished @kyle-sexton's task in 3m 21s —— View job PR Review:
|
Windows core.filemode=false dropped the +x recorded locally; the repo convention (and the exec-bit hygiene gate) requires shell scripts to be mode 100755, matching the sibling scripts under plugins/*/scripts/. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011V31qpAHP3jfs76B9d5Rfo
|
Claude finished @kyle-sexton's task in 2m 44s —— View job PR Review:
|
Address three Claude-review findings on #592: - Medium: goal-condition-length.sh ran with `set -uo pipefail` but not `set -e`, so a crashed counter (perl/wc failing or emitting nothing) left $chars empty; the `-gt` test then errored-and-fell-through to a false `status=ok`/exit 0. Add an integer guard on $chars right after counting — non-numeric now exits 2. Covered by a new test that shadows both perl and wc to force the failure path. - Low: usage() used a fixed `sed -n '2,20p'` range that silently truncated the last two header lines. Switch to a sentinel range (/^# Mechanical/,/^# Output/) so usage stays in sync as the header changes. - Info: SKILL.md now leads with the quoting-robust --file invocation (immune to a condition containing ', `, or $), keeping stdin as the simple-case secondary. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011V31qpAHP3jfs76B9d5Rfo
|
Claude finished @kyle-sexton's task in 1m 16s —— View job PR Review:
|
Review-finding classificationAll three Claude-review findings addressed in
Verification
|
|
Claude finished @kyle-sexton's task in 2m 8s —— View job PR Review:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: afef2f0d4c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The draft-goal-condition doc-fetch failure path guarded only the character limit against drift, letting the condition shape silently fall back to the embedded Step 2 four-part shape — contradicting the skill's own rule to never bake the shape. The proceed path now requires the user to paste the live condition shape as well as the limit, or defer until the docs are reachable. Addresses the Codex P2 review finding on #592. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 1m 38s —— View job PR Review:
|
| Finding | Commit | Status |
|---|---|---|
$chars guard — counter failure was a silent false positive |
afef2f0 |
FIXED — [[ "$chars" =~ ^[0-9]+$ ]] guard at line 108; test case 14 exercises both stub paths |
usage() range 2,20 silently truncated header |
afef2f0 |
FIXED — sentinel range at line 29 |
| SKILL.md stdin invocation was quoting-fragile | afef2f0 |
FIXED — --file promoted to primary at lines 56–62 |
| Doc-fetch failure path: shape not required from user (Codex P2) | 112b080 |
FIXED — both shape and limit now required at line 39 |
No remaining findings. This PR is ready to merge.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 112b0801e0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
Adds a new
planningskill,draft-goal-condition, that crafts a paste-ready/goalcompletion condition from a stated intent. It (1) reads the current official/goaldocs live for the condition shape and character limit — nothing hardcoded, so the skill does not rot when the documented contract changes between Claude Code versions; (2) drafts a transcript-demonstrable condition in the doc's effective-condition shape; and (3) because a language model cannot reliably count characters, proves the draft fits the limit with a deterministic counter script rather than model estimation. A step-0 lever-fit gate routes interval-shaped work to/loopand cloud/sessionless work to routines//scheduleinstead of authoring a goal.Placement:
planning. This was the maintainer-confirmed placement in the #481 interview thread — the plugin'sinterviewskill already locks a task contract (goal, constraints, acceptance criteria), which is nearly isomorphic to the/goaleffective-condition shape; planning produces crafted artifacts from intent, exactly this skill's job. It ships as a standalone authoring helper (likequestionnaire), not a new pipeline stage, so the README's "eight pipeline skills" framing is unchanged.Skill name
draft-goal-conditionand the lever-fit gate scope addition are the maintainer's decisions recorded on #481.Implementation
New files:
plugins/planning/skills/draft-goal-condition/SKILL.md— the skill (81 lines). Steps: lever-fit gate → read the live contract → draft to the effective-condition shape → mechanical length check + trim/re-validate loop → paste-ready output.plugins/planning/scripts/goal-condition-length.sh— deterministic, model-free character-length gate. The limit is passed in by the caller (--limit N, read live from the docs), never baked into the script; reads the condition from stdin or--file. Counts Unicode code points (perl-primary,wc -mfallback). Exit0within limit,1over,2usage/env error; stdoutchars=<n> limit=<N> status=<ok|over>.plugins/planning/scripts/goal-condition-length.test.sh— companion black-box test (13 cases), auto-discovered byscripts/run-plugin-tests.sh.Changed files:
plugins/planning/.claude-plugin/plugin.json— version0.21.2→0.22.0(minor, new feature); added keywordsdraft-goal-condition,goal,completion-condition,autonomous-goal.plugins/planning/CHANGELOG.md—0.22.0entry.plugins/planning/README.md— one skill-table row.Frontmatter blast radius (called out for review): this is a brand-new SKILL.md, so all frontmatter fields are new:
name: draft-goal-conditiondescription:— 824/1536 chars. Triggers are single-quoted and/goal-specific ('craft a /goal','write a goal condition','set up an autonomous goal','make Claude keep working until X','my /goal is too long / over the limit','turn this into a completion condition'), plus explicit skip/route-elsewhere triggers for interval/cloud/one-shot work. No overlap with neighbors:interviewlocks a PLAN.md task contract;questionnaireproduces a person-handoff doc; neither matches/goalauthoring.argument-hint: "[intent]",user-invocable: true,disable-model-invocation: false(auto-discoverable on/goal-crafting intent).Verification
Current official character limit — verified live, not from training data. Fetched
https://code.claude.com/docs/en/goalduring implementation (2026-07-19). The page states verbatim: "The condition can be up to 4,000 characters." The limit is on characters, not tokens, and the evaluator "does not call tools, so it can only judge what Claude has already surfaced in the conversation" — hence the transcript-demonstrable requirement. The verified4000appears only in this PR body and the runtime doc; it is grep-clean of the skill and both scripts (grep -rn '4000\|4,000' plugins/planning/skills/draft-goal-condition plugins/planning/scripts/*.sh→ no matches), satisfying the "no baked limit" acceptance criterion.Length gate against a real conforming example (limit passed at runtime = the live-verified 4000):
Length gate against a real oversized example (same intent padded to 4,800 chars):
Suite / lint (all green locally):
bash plugins/planning/scripts/goal-condition-length.test.sh→ 13/13 pass.shellcheck --rcfile=.shellcheckrc+shfmt -don both scripts → clean.check-skill.sh draft-goal-condition→ PASS, 0 errors (the single WARN is the literalUse when:phrasing preference; all planning neighbors —interview,questionnaire,brainstorm— useUse for/Use proactivelyand carry the same accepted WARN, so this matches the plugin-family convention; the regression-critical single-quoted-trigger check passes).markdownlint-cli2on the SKILL/README/CHANGELOG → 0 errors.node scripts/validate-plugin-contracts.mjsandgenerate-catalog.mjs --check→ pass / in sync.Closes #481
Related
/goalprompt-crafting skill).🤖 Generated with a Claude Code implementation subagent (issue #481)