Conductor + Claude: plan-tune PreToolUse hook breaks native AskUserQuestion (auto-installed in Conductor)
- Dominant language
- TypeScript
- Stars
- 133k
- Forks
- 19.9k
- Avg merge
- 18h 46m
- Merged PRs (30d)
- 26
Description
## Summary
In **Conductor** sessions running **Claude Code**, gstack's plan-tune AUQ hooks **break Conductor's native `AskUserQuestion`**. Every AUQ call returns `[Tool result missing due to internal error]` (or the input is echoed with no rendered options). The same Conductor workspace running **Codex/GPT works fine**, because Codex doesn't load `~/.claude/settings.json` hooks.
The important part: the premise behind the v1.58.1.0 "Conductor prose AskUserQuestion" feature — *"Conductor disables native AUQ and its MCP variant is flaky"* — appears to be **self-inflicted**. Conductor's AUQ is not flaky. gstack's own PreToolUse hook is what breaks it, and then the code attributes the failure to Conductor and routes to prose.
## Impact
- Claude + Conductor users lose clickable `AskUserQuestion` entirely (every decision silently degrades to prose, or errors).
- It's auto-installed with no opt-in: `setup` treats a Conductor workspace as an implicit opt-in for the plan-tune hooks (see below), so a routine `/gstack-upgrade` silently plants the breakage.
## Root cause
`AskUserQuestion` in Conductor + Claude Code is resolved through the Agent-SDK `canUseTool` elicitation bridge (`CLAUDE_CODE_ENTRYPOINT=sdk-ts`; the `mcp__conductor__AskUserQuestion` tool is injected by Conductor's harness, not present in `~/.claude.json`).
gstack registers a **PreToolUse hook** (`hosts/claude/hooks/question-preference-hook.ts`, source `plan-tune-cathedral`) on the matcher `(AskUserQuestion|mcp__.*__AskUserQuestion)`. When that hook participates in the permission flow — **even when it returns `permissionDecision: "defer"`** — it corrupts the `canUseTool` round-trip, and the tool result comes back missing.
`setup` auto-installs it in Conductor:
```sh
# setup, ~line 1389
if [ "$PT_DECISION" = "prompt" ] && { [ -n "${CONDUCTOR_WORKSPACE_PATH:-}" ] || [ -n "${CONDUCTOR_PORT:-}" ]; }; then
PT_DECISION="yes"
_PT_CONDUCTOR_AUTO=1
fi
```
Introduced in **v1.58.1.0** (`c7ae632`, "feat: hermetic local E2E + Conductor prose AskUserQuestion").
## Reproduction
1. Open a Conductor workspace, Claude Code agent, with gstack's plan-tune hooks installed (the Conductor default).
2. Trigger any `AskUserQuestion` / `mcp__conductor__AskUserQuestion` call.
3. Observe: no options render; result is `[Tool result missing due to internal error]`.
4. Remove the AUQ hooks from `~/.claude/settings.json` (or `gstack-config set plan_tune_hooks no`, delete the `hooks` block, restart).
5. Trigger AUQ again → it renders and works. (Verified live, 3×.)
Cross-check: the identical Conductor workspace on Codex/GPT renders AUQ fine throughout — Codex never reads `~/.claude/settings.json`, so the hook is never in the path. This isolates the hook as the cause.
Note: gating the `deny` behind a flag so the hook returns `defer` does **not** fix it — the hook has to be fully **unregistered**. Its mere presence in the permission flow is enough to break the bridge.
## Suggested fix
At minimum, stop auto-installing the AUQ **PreToolUse** hook in Conductor, since it's what breaks native AUQ there:
```diff
- # Conductor host reliability: ... Treat Conductor as an implicit opt-in ...
- if [ "$PT_DECISION" = "prompt" ] && { [ -n "${CONDUCTOR_WORKSPACE_PATH:-}" ] || [ -n "${CONDUCTOR_PORT:-}" ]; }; then
- PT_DECISION="yes"
- _PT_CONDUCTOR_AUTO=1
- fi
```
More fundamentally, it's worth re-validating the whole "Conductor prose AUQ" premise: native AUQ works in Conductor when this PreToolUse hook isn't registered, so the flakiness the feature works around looks like it's caused by the feature itself. If the PostToolUse capture/fallback hooks are confirmed harmless to the bridge (they fire after the result, so they likely are), the preference-enforcement value could be kept by only dropping the PreToolUse participation in Conductor — but that needs a test on real Conductor hardware.
## Workaround (for affected users)
```sh
# unregister the AUQ hooks and stop setup from re-adding them (even in Conductor)
gstack-config set plan_tune_hooks no
# then remove the plan-tune-cathedral / auq-error-fallback hooks from ~/.claude/settings.json
```
## Environment
- gstack `v1.58.5.0`
- Claude Code `2.1.201` via Agent SDK (`CLAUDE_CODE_ENTRYPOINT=sdk-ts`)
- Conductor (macOS, local mode)
- Regression introduced in gstack `v1.58.1.0` (`c7ae632`)
Happy to open a PR from a fork if the minimal `setup` change above looks right to you.
Contributor guide
Research direction
Start in setup around line 1389 and inspect hosts/claude/hooks/question-preference-hook.ts, including the plan-tune-cathedral matcher. Reproduce in a Conductor workspace with Claude Code, then verify that setup no longer auto-registers the AUQ PreToolUse hook and that native AskUserQuestion renders successfully without it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- shell, typescript
- Domain
- cli, devtools
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100