garrytan / garrytan/gstack

Conductor: write proposed TODOs to TODOS.md instead of prose decision brief; block /ship on unresolved proposals

Open
#2,090 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
133k
Forks
19.9k
Avg merge
18h 46m
Merged PRs (30d)
26

Description

## Problem

When a TODO decision arises inside a Conductor session (e.g. during `/plan-ceo-review`), gstack currently:

1. Tries to call `AskUserQuestion` — immediately blocked by the `question-preference-hook`'s `isConductor()` guard.
2. Falls back to a **prose decision brief** in the chat: D label, ELI10, Recommendation, one paragraph per option, \"reply with a letter, then STOP.\"

The prose fallback is still **synchronous**. The user must be present and reply in-chat before the skill continues. It also means multiple pending TODO decisions arrive as separate, sequential prose blocks — no way to batch-review them.

This is a subset of the broader AUQ-in-Conductor problem (#2035, #2006), but it's worth treating separately because the *goal* here is different: TODO proposals don't need an immediate answer. They can be deferred without blocking the session.

## Proposed alternative: write proposals to TODOS.md

Instead of rendering a prose brief and stopping, when gstack is in a Conductor session and needs a TODO decision, it should:

1. **Write the proposed item directly to TODOS.md** using a new `proposed` status (or `**Status:** pending-decision`).
2. Include the full decision context inline — What, Why, Pros, Cons, Options (A/Add · B/Skip · C/Build now), Effort, Priority — so the user has everything they need to decide without digging into chat history.
3. **Continue the session** rather than blocking. The user reviews TODOS.md at their own pace.

Conductor has an inline diff comment feature: the user can leave a comment on any line of a modified file directly in the Conductor UI. This makes TODOS.md a natural async communication channel — the user comments on a proposed item with their decision (A/B/C), and the agent picks it up next session.

## The comment-reading gap

Conductor's current MCP surface exposes `DiffComment` for **writing** inline comments, but no tool for **reading** them back. gstack cannot programmatically check whether the user has already responded to a proposed TODO via a Conductor diff comment.

Two paths forward:

**Option A — Conductor adds a read tool.**
A `GetDiffComments` MCP tool (or similar) that returns comments on a given file would let gstack read responses and resolve proposals automatically. This would be a Conductor-side feature request.

**Option B — User updates the TODOS.md status field directly.**
Require the user to change `**Status:** proposed` to `accepted` / `skipped` / `build-now` in TODOS.md after reviewing. This keeps everything in the file, no MCP round-trip needed. gstack can read the file to check resolution.

Option B requires less infrastructure and keeps TODOS.md as the single source of truth. Option A is more ergonomic for users who prefer the Conductor comment UI.

## `/ship` guard

Regardless of which option is chosen, `/ship` Step 14 should block (or warn loudly) if TODOS.md contains any items in `proposed` / `pending-decision` status. The intent is to prevent shipping past unreviewed TODO proposals.

If Option A lands, the guard could additionally check whether any Conductor diff comments on TODOS.md are unresolved.

## Opt-in / user preference

This could be gated behind a preference (`gstack-config set todos-decision-mode file-async`) so users who prefer the current prose-brief flow aren't affected. Conductor-session detection could auto-enable it, with an explicit `always-prose` escape hatch.

## Related issues

- **#2035** — root cause: `question-preference-hook` emits `permissionDecision: "defer"` on no-op paths, breaking AUQ in recent Claude Code builds (same reporter, macOS/VSCode). Proposed fix: change `defer()` to emit no `permissionDecision`.
- **#2006** — same root cause, independent report. Includes the isolation table and minimal fix.
- **#1208** — AUQ panel layout breaks with long decision-brief bodies and multi-tab batches. PR #1241 proposes moving decision briefs outside the tool call into prose. The file-write approach here is a further step in the same direction: move the decision context into a persistent artifact rather than ephemeral chat.
- **#1124** — design question: why does TODOS.md live in git while `~/.gstack/projects/` docs stay local? No maintainer response yet. The async-proposal flow here reinforces that TODOS.md is the right place for shared, persistent decisions.
- **#2015** — Hermes host: use native `clarify` tool instead of AUQ. Demonstrates gstack already routes question UI per host. Conductor could be treated similarly: same host-specific routing, different target (file write instead of tool call).

## Acceptance criteria

- [ ] When `isConductor()` and a TODO decision is triggered, gstack writes a `proposed` item to TODOS.md instead of rendering a prose brief
- [ ] The written item includes all decision context (What/Why/Pros/Cons/Options/Effort/Priority) following `TODOS-format.md`
- [ ] `/ship` Step 14 detects `proposed`-status items and blocks or warns before pushing
- [ ] Behavior is opt-in or Conductor-auto with a prose escape hatch
- [ ] Existing prose-fallback behavior is preserved for non-Conductor sessions

Contributor guide

Open the contributing guide

Research direction

Start by tracing the TODO decision flow around isConductor() and the question-preference-hook, then inspect TODOS.md, TODOS-format.md, and /ship Step 14. Confirm how proposed status and decision context should be represented, how Conductor responses are handled, and how existing prose fallback works outside Conductor. Done means the acceptance criteria pass without changing non-Conductor behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.