Question Tuning with gstack's AskUserQuestion Preferences: Complete Configuration Guide
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, 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.
// 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) injects three code blocks into the skill's template. The orchestrator in scripts/resolvers/preamble.ts triggers this injection:
// 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 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:
- Skill template receives preamble injection via
generateQuestionTuning - Pre-check queries
gstack-question-preference --check <question_id> - Decision gate: If preference is
never-askanddoor_typeis notone-way, the agent auto-selects the recommended option and annotates the response withAuto-decided <question_id> → <option> (your preference) - Interaction: If asking, the agent presents the question and captures the answer
- Logging:
gstack-question-logwrites a JSON-L record containingskill,question_id,question_summary,category,door_type,options_count,user_choice,recommended, andsession_id - 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:
# 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:
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:
gstack-question-preference --write '{
"question_id":"ship-new-feature-review",
"preference":"never-ask",
"source":"inline-user"
}'
Summary
- Question tuning in
garrytan/gstackcontrols AskUserQuestion behavior through persistent preferences stored inscripts/question-registry.ts - The
/plan-tuneskill injects preamble code blocks viascripts/resolvers/question-tuning.tswhenpreambleTier >= 2 - Preferences (
never-ask,always-ask,ask-only-for-one-way) are managed bybin/gstack-question-preferenceand checked before each prompt - One-way doors bypass auto-decision logic; classification relies on the
door_typefield and fallback heuristics inscripts/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-logfor 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—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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →