Skip to content

Commit 38ad7d1

Browse files
committed
feat: plan-to-goal capture via ExitPlanMode PostToolUse hook
When a plan is approved (ExitPlanMode) and an active goal exists, the hook parses the plan's numbered steps and nudges Claude to add them as goal steps, ensuring plan work persists across sessions. Co-developed-by: Claude Code v2.1.50 (claude-opus-4-6)
1 parent b646c19 commit 38ad7d1

6 files changed

Lines changed: 93 additions & 3 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"name": "context-daddy",
1010
"source": "./",
1111
"description": "Your codebase's context needs a responsible adult. Fast code exploration, living project narratives, and tribal knowledge that survives across sessions.",
12-
"version": "0.14.5",
12+
"version": "0.14.6",
1313
"author": {
1414
"name": "Robert Taylor"
1515
},

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "context-daddy",
3-
"version": "0.14.5",
3+
"version": "0.14.6",
44
"description": "Your codebase's context needs a responsible adult. Fast code exploration, living project narratives, and tribal knowledge that survives across sessions.",
55
"author": {
66
"name": "Robert Taylor"

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to the context-tools plugin will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.14.6] - 2026-03-02
9+
10+
### Added
11+
- **Plan-to-goal capture** - PostToolUse hook on ExitPlanMode detects approved plan steps and nudges Claude to add them as goal steps, ensuring plan work persists across sessions
12+
813
## [0.14.5] - 2026-03-02
914

1015
### Added

hooks/hooks.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@
102102
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/goals-post-tool.sh"
103103
}
104104
]
105+
},
106+
{
107+
"matcher": "ExitPlanMode",
108+
"hooks": [
109+
{
110+
"type": "command",
111+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/plan-capture.sh"
112+
}
113+
]
105114
}
106115
],
107116
"PreToolUse": [

hooks/plan-capture.sh

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#!/usr/bin/env bash
2+
# PostToolUse hook for ExitPlanMode
3+
# When a plan is approved and an active goal exists, nudges Claude to
4+
# capture the plan's steps as goal steps so they persist across sessions.
5+
set -euo pipefail
6+
7+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../scripts" && pwd)"
8+
PROJECT_ROOT="${PWD}"
9+
CLAUDE_DIR="${PROJECT_ROOT}/.claude"
10+
CURRENT_GOAL_FILE="${CLAUDE_DIR}/.current-goal"
11+
PLANS_DIR="${HOME}/.claude/plans"
12+
13+
# Quick exit if no active goal or no plans directory
14+
if [[ ! -f "${CURRENT_GOAL_FILE}" ]] || [[ ! -d "${PLANS_DIR}" ]]; then
15+
echo '{}'
16+
exit 0
17+
fi
18+
19+
# Find the most recently modified plan file (modified in the last 60 seconds)
20+
PLAN_FILE=$(find "${PLANS_DIR}" -name '*.md' -not -name '*.backup-*' -mmin -1 -print0 2>/dev/null \
21+
| xargs -0 ls -t 2>/dev/null \
22+
| head -1)
23+
24+
if [[ -z "${PLAN_FILE}" ]]; then
25+
echo '{}'
26+
exit 0
27+
fi
28+
29+
# Extract numbered steps from the plan (### N. Title pattern)
30+
# Also handles ## Changes / ### N. Title patterns
31+
export _PC_PLAN_FILE="${PLAN_FILE}"
32+
STEPS=$(python3 -c '
33+
import os
34+
import re
35+
from pathlib import Path
36+
37+
plan_file = os.environ["_PC_PLAN_FILE"]
38+
content = Path(plan_file).read_text()
39+
40+
steps = []
41+
for m in re.finditer(r"^###\s+(\d+)\.\s+(.+)$", content, re.MULTILINE):
42+
num = m.group(1)
43+
title = m.group(2).strip()
44+
# Clean up markdown formatting from title
45+
title = re.sub(r"`([^`]+)`", r"\1", title)
46+
# Truncate long titles
47+
if len(title) > 80:
48+
title = title[:77] + "..."
49+
steps.append(f" {num}. {title}")
50+
51+
if steps:
52+
print("\n".join(steps))
53+
' 2>/dev/null || true)
54+
55+
if [[ -z "${STEPS}" ]]; then
56+
echo '{}'
57+
exit 0
58+
fi
59+
60+
# Get current goal info for the message
61+
GOAL_STATUS=$(bash "${SCRIPT_DIR}/goal-context-helper.sh" --status "${PROJECT_ROOT}" 2>/dev/null || true)
62+
63+
# Build the nudge message
64+
MSG="📋 Plan approved with steps that should be tracked in your active goal.
65+
66+
Plan steps detected:
67+
${STEPS}
68+
69+
**ACTION**: Use goal_add_step to add these as goal steps (skip any that duplicate existing steps). Use short kebab-case step IDs derived from the titles."
70+
71+
MSG_ESCAPED=$(echo -n "${MSG}" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" | sed 's/^"//;s/"$//')
72+
cat << EOF
73+
{
74+
"systemMessage": "${MSG_ESCAPED}"
75+
}
76+
EOF

scripts/goal-context-helper.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ lines.append(" Commands: /context-daddy:goal (manage) | /context-daddy:goal-do
200200
# Behavioral guidance
201201
lines.append("")
202202
lines.append(" **IMPORTANT - Goal-driven workflow:**")
203-
lines.append(" - When the user asks for a large multi-step task, use the goal system (goal_create + goal_add_step) instead of EnterPlanMode.")
203+
lines.append(" - When the user asks for a large multi-step task, prefer the goal system (goal_create + goal_add_step) over EnterPlanMode. If you do use EnterPlanMode, the plan steps will be auto-captured as goal steps.")
204204
lines.append(" - After completing a step, use goal_update_step to mark it done, then CONTINUE to the next step without waiting to be asked.")
205205
lines.append(" - Only stop between steps if you need user input or clarification.")
206206
lines.append(" - To reorder or remove steps: edit the goal file directly (rearrange/delete the `- [ ] [step-id]` lines). Step IDs, not positions, identify steps.")

0 commit comments

Comments
 (0)