Skip to content

Include decisions in hook output during plan mode#123

Merged
gregology merged 2 commits intomainfrom
plan-mode-decisions
Apr 9, 2026
Merged

Include decisions in hook output during plan mode#123
gregology merged 2 commits intomainfrom
plan-mode-decisions

Conversation

@gregology
Copy link
Copy Markdown
Contributor

@gregology gregology bot commented Apr 9, 2026

Closes #122

Why

Decisions — rejected alternatives, rationale, revisit conditions — are invisible to Claude Code right now. The hook only surfaces context entries. That's fine during normal editing, but during plan mode the agent is reading files to understand the codebase before writing anything. That's exactly when architectural decisions matter most. Without them, Claude might confidently propose migrating to something you already evaluated and ruled out.

Approach

The issue proposed adding a separate bash hook that shells out to jq and sctx decisions. That works, but it means a new external dependency (jq), a second hook registration in claude_setup.go, and two separate processes running on every Read during plan mode.

Instead, this handles it natively inside sctx hook. The Claude Code hook input already includes permission_mode — we just weren't reading it. Now HandleClaudeHook parses that field, and when the mode is "plan", it appends matching decisions to the same additionalContext string alongside context entries. One hook call, one process, no new dependencies.

The core engine already returns DecisionEntries from Resolve — we were just ignoring them in the adapter. So the actual change is small: read the field, check the mode, format and append.

Decisions are scoped to the file being read (same glob matching as context entries) rather than dumping all decisions on every read. This keeps noise down as decision lists grow.

What changed

The early-return guard previously bailed when len(result.ContextEntries) == 0. Now it checks both context and decisions (when in plan mode), so the hook produces output if either matched. Outside plan mode, behavior is identical to before — existing tests pass without modification since they send no permission_mode.

Review walkthrough

Single commit, single concern:

  • Include decisions in hook output during plan mode — adds PermissionMode to ClaudeHookInput, adds formatDecisions helper, wires the conditional logic into HandleClaudeHook, updates the empty-result guard, adds tests covering plan/non-plan/both/neither combinations, and updates docs (README + cli-reference) to reflect the new behavior.
Developer metrics

Total duration: 7m 41s
Turns: 104
Tool calls: 76
Tokens: 1,660,710 input / 15,371 output

Stage Model Duration Turns Tool calls Tokens (in/out) Cache read Cache creation
triage claude-opus-4-6 2m 4s 34 31 96,691 / 2,016 66,633 30,051
decompose claude-opus-4-6 0m 47s 5 4 153,254 / 1,297 111,201 42,044
implement_step_1 claude-opus-4-6 2m 21s 28 17 420,775 / 8,385 379,853 40,890
docs_review claude-opus-4-6 1m 15s 24 15 557,313 / 2,463 504,628 52,662
craft_pr claude-opus-4-6 1m 11s 13 9 432,677 / 1,210 366,639 66,026

Resolves #122

gregology bot added 2 commits April 8, 2026 20:21
Modify `internal/adapter/claude.go` to:
1. Add `PermissionMode string` field (json tag `permission_mode`) to `ClaudeHookInput`.
2. Add a `formatDecisions([]core.DecisionEntry) string` helper that renders decisions as markdown, following the same pattern as the CLI's `cmdDecisions` output (decision, rationale, alternatives, revisit_when) but under a `## Architectural Decisions` heading with bullet points.
3. In `HandleClaudeHook`, after the `core.Resolve` call, check if `hookInput.PermissionMode == "plan"` and `len(result.DecisionEntries) > 0`. If so, append the formatted decisions to the additional context string.
4. Adjust the early-return guard at line 96 — currently `if len(result.ContextEntries) == 0 { return nil }`. Change to also check `result.DecisionEntries` when in plan mode, so the hook produces output if either context or decisions matched.

Modify `internal/adapter/claude_test.go` to add table-driven tests covering:
- Plan mode Read with matching decisions → decisions appear in `additionalContext`
- Non-plan mode (empty string / other value) with matching decisions → no decisions in output
- Plan mode with no matching decisions → silent no-op (if no context either)
- Plan mode with both context and decisions → both sections appear in output

No changes to `claude_setup.go` (no new hook registration needed), `core/` (already returns decisions), or the CLI.
Copy link
Copy Markdown

@Asad-Jaffery Asad-Jaffery left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great!!

How I tested

  1. Cloning the sctx repo and checking out the plan-mode-decisions branch
  2. Building a local binary (sctx-plan)
  3. Temporarily pointing the hooks in .claude/settings.local.json to use the local build instead of the installed sctx
  4. Adding a debug log to the hook that captures the mode, file path, and any decisions returned

@gregology gregology merged commit e853b7d into main Apr 9, 2026
2 checks passed
@gregology gregology deleted the plan-mode-decisions branch April 9, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Include decisions in hook output during plan mode

2 participants