# Question Tuning with gstack's AskUserQuestion Preferences: Complete Configuration Guide

> Master question tuning with gstack's AskUserQuestion preferences. Gain persistent control over interactive prompts and auto-resolve interactions. Read our complete configuration guide.

- Repository: [Garry Tan/gstack](https://github.com/garrytan/gstack)
- Tags: how-to-guide
- Published: 2026-05-15

---

**Question tuning in gstack gives developers persistent control over interactive prompts by storing per-question preferences that auto-resolve AskUserQuestion interactions unless they are safety-critical "one-way doors."**

The `garrytan/gstack` repository implements a sophisticated preference system through its `/plan-tune` skill that eliminates repetitive prompting while maintaining security boundaries. By managing how agents handle **AskUserQuestion** instances, this feature creates deterministic, auditable workflows where user choices persist across sessions.

## The Four-Layer Question Tuning Architecture

### Typed Question Registry

At the foundation lies the typed registry in [`scripts/question-registry.ts`](https://github.com/garrytan/gstack/blob/main/scripts/question-registry.ts), which catalogs every AskUserQuestion by a stable `question_id`. Each entry records the owning skill, categorical shape, whether the question acts as a *one-way* safety gate, stable option keys, an optional psychographic `signal_key`, and a human-readable description.

```typescript
// scripts/question-registry.ts
export const QUESTIONS = {
  'ship-new-feature-review': {
    id: 'ship-new-feature-review',
    skill: 'ship',
    category: 'approval',
    door_type: 'one-way',
    options: ['accept', 'defer', 'reject'],
    signal_key: 'scope-appetite',
    description: 'Review a newly-added feature – ship now, defer, or reject?',
  },
};

```

### Preamble Injection via `/plan-tune`

When a skill's preamble tier is greater than or equal to 2, the resolver `generateQuestionTuning` (defined in [`scripts/resolvers/question-tuning.ts`](https://github.com/garrytan/gstack/blob/main/scripts/resolvers/question-tuning.ts)) injects three code blocks into the skill's template. The orchestrator in [`scripts/resolvers/preamble.ts`](https://github.com/garrytan/gstack/blob/main/scripts/resolvers/preamble.ts) triggers this injection:

```typescript
// scripts/resolvers/preamble.ts (excerpt)
if (ctx.preambleTier >= 2) {
  parts.push(generateQuestionTuning(ctx)); // injects the three blocks
}

```

These blocks include:
- A **pre-check** running `gstack-question-preference --check <id>` before each prompt
- A **post-log** recording answers via `gstack-question-log`
- An **inline-tune** prompt offering a `tune:` shortcut after the answer

### Preference and Logging Binaries

The runtime relies on two binaries to persist state:

**`bin/gstack-question-preference`** reads and writes per-question preferences. Valid preference values are `never-ask`, `always-ask`, and `ask-only-for-one-way`. When invoked with `--check`, it returns the current preference; if the value is `never-ask` and the question is not a one-way door, the agent auto-decides the recommended option.

**`bin/gstack-question-log`** appends a JSON-L record for every AskUserQuestion, validated against the registry schema to ensure data integrity.

### One-Way Door Safety Classification

Safety-critical questions must always prompt the user. The primary source is the `door_type` field in the registry. As a fallback, `classifyQuestion` in [`scripts/one-way-doors.ts`](https://github.com/garrytan/gstack/blob/main/scripts/one-way-doors.ts) inspects question summaries for destructive patterns such as `rm -rf`, `DROP TABLE`, or `terraform destroy`, and flags high-risk skill-category combinations like `cso:approval` or `land-and-deploy:approval`.

## How the Question Tuning Pipeline Works

The execution flow creates a deterministic pipeline from template generation to preference persistence:

1. **Skill template** receives preamble injection via `generateQuestionTuning`
2. **Pre-check** queries `gstack-question-preference --check <question_id>`
3. **Decision gate**: If preference is `never-ask` and `door_type` is not `one-way`, the agent auto-selects the recommended option and annotates the response with `Auto-decided <question_id> → <option> (your preference)`
4. **Interaction**: If asking, the agent presents the question and captures the answer
5. **Logging**: `gstack-question-log` writes a JSON-L record containing `skill`, `question_id`, `question_summary`, `category`, `door_type`, `options_count`, `user_choice`, `recommended`, and `session_id`
6. **Inline tuning**: If the user types `tune: <preference>`, the system updates the preference for future sessions

### Checking Preferences in Practice

Before presenting any AskUserQuestion, the agent executes:

```bash

# Agent runs this before asking

gstack-question-preference --check ship-new-feature-review

# → possible output: "never-ask"

```

If the output indicates `never-ask` and the question is not a one-way door, the agent bypasses the prompt and automatically selects the recommended option.

### Logging User Answers

Every answered question generates an immutable log entry:

```bash
gstack-question-log '{
  "skill":"ship",
  "question_id":"ship-new-feature-review",
  "question_summary":"Ship the new feature?",
  "category":"approval",
  "door_type":"one-way",
  "options_count":3,
  "user_choice":"accept",
  "recommended":"accept",
  "session_id":"$_SESSION_ID"
}' 2>/dev/null || true

```

## Security: User-Origin Gate and Profile Poisoning Defense

The system enforces strict provenance for preference updates. Inline "tune:" feedback is only persisted when the `tune:` token appears in the **user's own chat turn**, never in tool output, files, or PR bodies. The binary rejects any write where the `source` field does not equal `"inline-user"`, exiting with code 2 to prevent profile-poisoning attacks.

When a user provides feedback:

```

tune: never-ask

```

The agent validates the source and writes:

```bash
gstack-question-preference --write '{
  "question_id":"ship-new-feature-review",
  "preference":"never-ask",
  "source":"inline-user"
}'

```

## Summary

- **Question tuning** in `garrytan/gstack` controls AskUserQuestion behavior through persistent preferences stored in [`scripts/question-registry.ts`](https://github.com/garrytan/gstack/blob/main/scripts/question-registry.ts)
- The **`/plan-tune`** skill injects preamble code blocks via [`scripts/resolvers/question-tuning.ts`](https://github.com/garrytan/gstack/blob/main/scripts/resolvers/question-tuning.ts) when `preambleTier >= 2`
- **Preferences** (`never-ask`, `always-ask`, `ask-only-for-one-way`) are managed by `bin/gstack-question-preference` and checked before each prompt
- **One-way doors** bypass auto-decision logic; classification relies on the `door_type` field and fallback heuristics in [`scripts/one-way-doors.ts`](https://github.com/garrytan/gstack/blob/main/scripts/one-way-doors.ts)
- **Security** requires `source: "inline-user"` for all preference writes, enforced by exit code 2 on validation failures
- All interactions are logged as JSON-L via `bin/gstack-question-log` for audit trails and psychographic profiling

## Frequently Asked Questions

### How does gstack determine whether to auto-answer an AskUserQuestion?

The agent queries `bin/gstack-question-preference --check <question_id>` before prompting. If the returned preference is `never-ask` and the registry entry's `door_type` is not `"one-way"`, the system automatically selects the recommended option. One-way door questions—identified by registry metadata or destructive pattern matching in [`scripts/one-way-doors.ts`](https://github.com/garrytan/gstack/blob/main/scripts/one-way-doors.ts)—always require explicit user confirmation regardless of preferences.

### What happens when I type "tune: never-ask" after answering a question?

When you include `tune: <preference>` in your chat response, the agent invokes `gstack-question-preference --write` with your specified preference and `source` set to `"inline-user"`. The binary validates that the source is explicitly `"inline-user"`; if the source field contains any other value (such as tool output or injected text), the binary exits with code 2 and refuses to write, preventing profile poisoning.

### Where are question definitions and metadata stored?

All AskUserQuestion definitions reside in [`scripts/question-registry.ts`](https://github.com/garrytan/gstack/blob/main/scripts/question-registry.ts) as a typed TypeScript object. Each entry includes the stable `question_id`, owning skill, category, `door_type` classification, available options, optional psychographic `signal_key`, and human-readable description. This registry serves as the source of truth for validation, logging, and preference lookups.

### Can I configure question tuning for any skill, or are there requirements?

Question tuning injection only activates for skills with `preambleTier >= 2`. The resolver `generateQuestionTuning` in [`scripts/resolvers/question-tuning.ts`](https://github.com/garrytan/gstack/blob/main/scripts/resolvers/question-tuning.ts) generates the necessary check, log, and inline-tune code blocks that get prepended to the skill's template. Skills below this tier level do not receive the preamble injection and will not support the `tune:` workflow or preference checking.