Quest Orchestration Skill
SkillAI & modelsMulti-agent quest orchestration. Plans, reviews, builds, and fixes features through coordinated agent handoffs. Use when the user invokes $quest or asks to run/resume Quest workflow.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Quest Orchestration Skill skill
What this skill tells your AI
The instructions your AI receives, as published by kjellkod/quest in .skills/quest/SKILL.md and read by ahel’s review.
Multi-agent workflow for planning, reviewing, building, and fixing features through coordinated agent handoffs.
Usage
/quest "Add a loading skeleton to the candidate list"
$quest "Add a loading skeleton to the candidate list"
/quest "Implement the transparency audit plan"
/quest transparency-v2_2026-02-02__1831
/quest transparency-v2_2026-02-02__1831 "now review the code"
/quest status
Procedure
When starting, say: "Now I understand the Quest." Then proceed.
Step 1: Resume Check
If the user provides a quest ID matching either supported Quest ID format (<slug>_YYYY-MM-DD__HHMM or YYYY-MM-DD_HHMM__<slug>):
- Read
.quest/<id>/state.jsonand resume from the recorded phase. If that file does not exist but.quest/archive/<id>/does, the quest is complete and archived — tell the user so (pointing at the journal entry indocs/quest-journal/) instead of failing; archived quests are not resumable. 1a. Orchestration config migration. On resume, runquest_runtime.orchestration.migrate_from_snapshotbefore dispatch (it is tested; keep the behavior in one place):- Missing
orchestration.json→ it is written from.quest/<id>/logs/allowlist_snapshot.json(models). Only explicitly legacy-compatible newly-introduced roles (LEGACY_COMPAT_BACKFILL_ROLES, currentlyreview-arbiter) are backfilled fromDEFAULT_MODELS; a snapshot missing any other canonical role (e.g.builder) is malformed — fail closed, never invent a default (that would bypass the saved per-quest model contract). A structurally invalid snapshot (unreadable, not valid JSON, or nomodelsobject) is also malformed. - Existing
orchestration.json→ it is backfilled in place with any newly-introduced canonical roles at their default and with the Claude transport keys (claude_role_transport: "auto",claude_transport_resolved: null,claude_transport_downgraded: false) when missing, preserving every existing value/metadata field, and left byte-identical when nothing is missing — so an in-flight quest that predates a new required role or the transport keys does not fail validation/dispatch on resume. - Never prompt the chooser on resume.
- Missing
- Delegate to
delegation/workflow.md
If the user says /quest status or $quest status, handle as a utility command (see delegation/workflow.md Utility Commands).
Step 2: Classify Input (New Quest)
If no quest ID is provided:
- Read
delegation/router.md - Evaluate the user's input against the 7 substance dimensions
- Produce the routing decision JSON:
{route, confidence (0.0-1.0), risk_level, complexity, ui_work, ui_work_evidence, reason, missing_information}
Step 2b: Second Model Availability Probe (New Quest Only)
MANDATORY — run before Step 3. From the repository root, execute the preflight check:
./scripts/quest_preflight.sh --orchestrator claude # if you are Claude
./scripts/quest_preflight.sh --orchestrator codex # if you are Codex
The script is at the repository root (scripts/quest_preflight.sh), NOT inside the skill directory.
- Parse the JSON output. Cache
availableas a boolean for the session. - If
availableis false:- Display every line of the
warningarray from the JSON output as a blockquote before route options. The array contains the heading, setup commands, and instructions — show them all. - Then pause quest startup and offer these choices:
Second-model setup is not currently available. Options: 1. Fix it now and rerun preflight (recommended) 2. Use the Claude bridge for this run (API-metered) — Codex-led sessions only 3. Continue with a single-model quest for this run 4. Cancel - Option 2 applies only to Codex-led sessions. There,
available: falsemeans the Claude background-agent transport could not be proven, and the bridge is the alternate (API-metered) Claude transport. In a Claude-led session,available: falseinstead means Codex MCP is unavailable — the bridge is irrelevant, so omit option 2, renumber the remaining choices, and route the user to Codex MCP remediation (fix), single-model, or cancel. - If the user selects "fix it now", do not create the quest folder yet. Let them complete the remediation, then rerun Step 2b.
- If this is a Codex-led session with
claude_role_transportunset orauto, the common remediation is:claude --dangerously-skip-permissions; accept the prompt; exit Claude; return here and rerun preflight. - If the user selects "Use the Claude bridge" (Codex-led sessions only), make the bridge opt-in explicit for this run before creating the quest folder: rerun preflight with
QUEST_CLAUDE_ROLE_TRANSPORT=bridge ./scripts/quest_preflight.sh --orchestrator codex, show the API-metering warning, and carry that bridge preflight result into orchestration writing (claude_role_transport: "bridge",claude_transport_resolved: "bridge"). If that bridge probe fails too, return to these options. - For Codex-led sessions, prefer
claude auth loginas the default interactive fix when Claude CLI auth is missing. If the warning indicates a restricted sandbox may be hiding auth state, rerun the preflight with whatever permissions are needed to read the real Claude CLI auth state. - For Claude-led sessions, use the warning lines to guide Codex MCP install/auth remediation before rerunning Step 2b.
- Append "(Claude-only)" or "(Codex-only)" to solo/full quest option labels.
- Display every line of the
- If
availableis true, proceed normally. - For Codex-led sessions, if the JSON includes
runtime_requirement: "host_context", treat that as authoritative:- Claude bridge probing and Claude-designated role execution must use the same host-visible context that can see Claude CLI auth.
- Do not assume a sandbox-local
claude auth statusresult is enough. - The script retains a successful probe in
.quest/cache/claude_bridge_codex.jsonby default, so a recent host-verified success can be reused across quest starts without repeating browser login.
This result carries into workflow.md — do not re-probe there.
Step 3: Route
Based on the router decision:
If route = "questioner":
- Read
delegation/questioner.md - Follow the questioning procedure (1-3 questions at a time, max 10 total)
- Collect the structured summary
- Re-run router (Step 2) with enriched input (original prompt + summary)
- If route is now "workflow", "solo", or "manual": proceed to the matching handler below
- If route is still "questioner": allow one more short questioning pass (10-question total cap still applies), then proceed to workflow regardless
If route = "manual":
- Present the routing classification with override options:
Quest Assessment: Risk: <risk_level> Complexity: <complexity> Recommended: manual (no pipeline) Options: 1. Just do it (recommended) — no quest pipeline 2. Run as solo quest — single reviewer, lightweight 3. Run as full quest — dual reviews, arbiter 4. Cancel - If user selects "just do it": exit quest system. No quest folder is created. The user works directly.
- If user selects "solo" or "full": proceed to the matching handler below with the overridden route.
- If user selects "cancel": exit quest system immediately. No quest folder, journaling, or celebration.
If route = "solo":
- Present the routing classification with override options:
Quest Assessment: Risk: <risk_level> Complexity: <complexity> Recommended route: solo (lightweight quest) Options: 1. Run as solo quest (recommended) — single plan review, single code review 2. Run as full quest — dual reviews, arbiter, the works 3. Cancel - If user selects "solo": create quest folder with
quest_mode: "solo", proceed to workflow - If user selects "full": create quest folder with
quest_mode: "workflow", proceed to workflow - If user selects "cancel": exit quest system immediately. No quest folder, journaling, or celebration.
If route = "workflow":
- Present the routing classification with override options:
Quest Assessment: Risk: <risk_level> Complexity: <complexity> Recommended route: full quest Options: 1. Run as full quest (recommended) 2. Run as solo quest (lighter) — single reviewer 3. Cancel - If user selects "full": create quest folder with
quest_mode: "workflow", proceed to workflow - If user selects "solo": create quest folder with
quest_mode: "solo", proceed to workflow - If user selects "cancel": exit quest system immediately. No quest folder, journaling, or celebration.
After route selection (solo or workflow):
- Present the routing classification to the user (see Risk Visibility below)
- Create quest folder (see Quest Folder Creation below)
- Read
delegation/workflow.md - Begin at workflow Step 1 (Precondition Check)
Risk Visibility
Before creating the quest folder, present the routing classification to the user:
- Display the risk level and confidence:
- If
risk_levelis "high": "Risk: HIGH — " - If
risk_levelis "medium": "Risk: MEDIUM — " - If
risk_levelis "low": "Risk: low — "
- If
- Display the UI classification:
- If
ui_workistrue: "UI work: yes — <ui_work_evidence>" - If
ui_workisfalse: "UI work: no" - If
ui_workis missing or not a boolean: "UI work: malformed router data — treating as no until corrected"
- If
- If the quest went through the questioner path, note this: "Questioning phase completed — gaps addressed before planning."
- Wait for user acknowledgment before proceeding (for high risk only). For medium and low, display and continue.
Quest Folder Structure
.quest/ contains:
- Active quest directories (created per-run)
archive/— completed quests moved here after journaling (see Step 7 in workflow.md)audit.log— persistent log across all quest runs
Quest Folder Creation
-
Generate a slug (lowercase, hyphenated, 2-5 words) and inform the user
-
Ask the user which workspace mode to use for this quest. Present these options:
- branch — create a
quest/<slug>feature branch (switches away from current branch) - worktree — create a
quest/<slug>branch in a separate worktree (current branch stays checked out) - none — stay on the current branch as-is
If already on a non-default branch, inform the user and skip the prompt — the quest will use the current branch. If the current workspace is not inside a git repository, skip the prompt — Quest must stay in the current workspace with
vcs_available: false. - branch — create a
-
Run quest startup branch preparation with the user's choice:
- Execute:
python3 scripts/quest_startup_branch.py --slug <slug> --mode <choice> - Parse the JSON result
- If
statusis"blocked": show the returnedmessage, do NOT create the quest folder yet, and stop for the user to resolve the git state or config - If
statusis"created"or"skipped": continue and surface the returnedmessageto the user - Surface the returned
quest_symlinkoutcome after startup:created: note that the worktree.quest/symlink was created.present: note that the worktree.quest/symlink was already present.migrated: tell the user that an existing worktree.quest/was safely migrated into the shared store.conflict: warn the user that same-name.quest/entries were preserved under.quest_conflicts/and need manual review.n/a: no linked-worktree symlink action was needed.
- Record these fields for
state.jsoninitialization:vcs_availablebranchbranch_modeworktree_path(if present)quest_symlink
- Execute:
-
Read
quest_id_formatfrom.ai/allowlist.jsonusingquest_runtime.quest_ids.load_quest_id_format; missing config defaults toslug-first. -
Create the Quest ID with
quest_runtime.quest_ids.format_quest_id(slug, datetime.now(), quest_id_format). Pass adatetime.datetimeobject, not a preformatted timestamp string; the helper formats date/time internally.- Default slug-first:
<slug>_YYYY-MM-DD__HHMM - Optional date-first:
YYYY-MM-DD_HHMM__<slug>
- Default slug-first:
-
Create
.quest/<id>/with subfolders:phase_01_plan/,phase_02_implementation/,phase_03_review/,logs/ -
Write quest brief to
.quest/<id>/quest_brief.mdincluding:- User input (original prompt)
- Questioner summary (if questioning occurred)
- Router classification JSON (the final routing decision that sent the quest to workflow). This is the classification produced by the most recent router evaluation — if the router ran twice (once before questioning, once after), record the second (final) classification.
-
Copy
.ai/allowlist.jsonto.quest/<id>/logs/allowlist_snapshot.json8.5. Per-quest orchestration chooser. Display the activemodelsblock from.ai/allowlist.json. For each role unused in the chosenquest_mode(e.g.,plan-reviewer-b,arbiter,code-reviewer-b, andreview-arbiterin solo mode), append(unused in this mode)after the model name. Then prompt:Quest orchestration for `<slug>` (<mode>): planner <model> plan-reviewer-a <model> plan-reviewer-b <model> (unused in this mode) [solo only] arbiter <model> (unused in this mode) [solo only] builder <model> code-reviewer-a <model> code-reviewer-b <model> (unused in this mode) [solo only] review-arbiter <model> (unused in this mode) [solo only] fixer <model> Use these defaults? [Y/n]On Y (default; single Enter): before writing, validate every active-role model from the expanded default block against the Step 2b preflight result using the same availability rules as overrides below. If Step 2b was healthy, reject any unavailable active-role model as malformed config and stop before dispatch. If the user explicitly chose the single-model continuation after Step 2b failed, remap unavailable active-role models to this orchestrator's native runtime (
claudefor Claude-led sessions,CODEX_NATIVE_FALLBACK_MODELfromquest_runtime.orchestrationfor Codex-led sessions) before writing soorchestration.jsononly contains runnable active-role assignments. Then write.quest/<id>/orchestration.jsonwith:version: 1models:.ai/allowlist.json.modelsexpanded to all 9 canonical keys byquest_runtime.orchestration.build_default_models; omitted keys use the shippedDEFAULT_MODELSfallback generated from the source allowlist. The allowlist is the repo-configured startup default; do not restate the literal fallback matrix in this procedural skill.claude_role_transport: the transport policy selected in Step 2b —"bridge"when the user explicitly chose the bridge option (including a per-runQUEST_CLAUDE_ROLE_TRANSPORT=bridgeselection that was not written to.ai/allowlist.json), otherwise from.ai/allowlist.json(default"auto"). Persist the resolved opt-in so a bridge choice survives resume; never record"auto"alongsideclaude_transport_resolved: "bridge".claude_transport_resolved: thetransportfield from the Step 2b preflight result (Codex-led sessions;nullotherwise)claude_transport_downgraded: compatibility field; writefalsefor new runs (Codex-led preflight also emitsfalse)codex_reasoning_effort: copy the optional allowlist value verbatim and pass it towrite_default_from_allowlist; validate withvalidate_codex_reasoning_effort. Omit it for older allowlists with no setting. Show the selected effort beside the model table before accepting defaults.source: "default"overridden_roles: []preflight_validated_at: <ISO8601 now>
On N: present the shorthand override prompt:
Enter overrides as comma- or newline-separated role=model pairs or a JSON models object. Roles: planner, plan-reviewer-a, plan-reviewer-b, arbiter, builder, code-reviewer-a, code-reviewer-b, review-arbiter, fixer Models: any model name your preflight reports as available (use the IDs displayed above or supported by your account) Pair example: planner=<codex-model-id>, builder=<claude-model-id> JSON example: {"models":{"planner":"<codex-model-id>","builder":"<claude-model-id>"}} (empty input = no overrides, equivalent to Y) Overrides:If the override submission is empty after trimming, follow the On Y default writer above. Do not write
source: "overridden", do not addoverridden_roles, and do not count the empty submission as a rejected attempt.Parse contract (each full override submission is one attempt; cap re-prompts at 3, abort on the 4th rejection): Run
python3 scripts/quest_parse_overrides.py, send the complete submission unchanged on stdin, and consume its JSON envelope. Exit0returns{"ok": true, "overrides": [...]}; exit2returns{"ok": false, "error": "..."}on stderr and counts as one rejected attempt. Do not manually parse or rewrite JSON into pairs.quest_runtime.orchestration.parse_override_inputis the canonical API;parse_override_lineremains a compatibility wrapper.- Detect format. Input beginning with
{is JSON. A copied"models": {...}fragment without outer braces is also accepted. JSON may be either{"models": {<role>: <model>}}or a direct{<role>: <model>}map. All JSON role keys and model values must be strings; model values must be non-empty. Amodelswrapper cannot have sibling top-level keys. Other input uses the pair format below. - Tokenize pairs. Split pair input on commas, LF newlines, or CRLF newlines and trim each piece. Empty pieces are silently skipped, so trailing separators and blank lines are allowed. Each non-empty piece must contain exactly one
=character. Reject pieces with zero or multiple=characters usingOverride syntax error: '<piece>' (expected role=model). Re-enter overrides. - Role name. Trim, normalize to lowercase, then exact-match against the canonical role list (
planner,plan-reviewer-a,plan-reviewer-b,arbiter,builder,code-reviewer-a,code-reviewer-b,review-arbiter,fixer). Reject unknown names withUnknown role: <input> (valid: planner, plan-reviewer-a, plan-reviewer-b, arbiter, builder, code-reviewer-a, code-reviewer-b, review-arbiter, fixer). Reject duplicate normalized roles in either syntax withDuplicate role: <role>. Re-enter overrides.rather than silently choosing the last value. - Model name. Trim the pair RHS or JSON string value. It must be non-empty and cannot contain commas,
=, or line breaks in either syntax, so JSON and pair inputs accept the same model tokens. Example:codex-fake-model,claude-fake-model,gemini-fake-modeland similar tokens are accepted at the parser level. - Unused-in-mode roles (
plan-reviewer-b,arbiter,code-reviewer-b, andreview-arbiterin solo). WarnRole <name> is unused in <mode> mode — override ignored.and skip the override; do not record it inoverridden_roles. - Availability check. Classify Claude-family model names as
claudeandclaude-*(including concrete Claude model IDs); Gemini-family model names (gemini,gemini-*) as Antigravity-backed; every other model name is Codex-backed. Antigravity-backed models requireantigravity_availablefromscripts/quest_preflight.sh --probe antigravity(see the workflow's Antigravity preflight section) in either session type. In Claude-led sessions, Claude-family models are available and Codex-backed models require Codex MCP availability from the Step 2b preflight result. In Codex-led sessions, Codex-backed models are available and Claude-family models require the top-levelavailableboolean from the Step 2b preflight result, which represents Claude transport availability (background-agent or bridge — thetransportfield says which). If the relevant cache/result is missing or stale (older than the preflight TTL), rerun the matching preflight once and reuse the fresh result:scripts/quest_preflight.sh --orchestrator <self>for Claude/Codex availability,scripts/quest_preflight.sh --probe antigravityforantigravity_available(they are separate modes and cannot be combined). Reject unavailable models with the preflightwarningtext and re-prompt the override submission. - Re-prompt cap. An "attempt" is one full override submission, not one role=model pair. Three rejected attempts in a row abort startup with
Override validation failed after 3 attempts — quest startup cancelled.
Once all overrides pass validation, build the merged
modelsblock (the expanded startup block returned bybuild_default_models, overlaid with the validated overrides —overridden_rolesexcludes ignored-because-unused entries) and write.quest/<id>/orchestration.jsonwith:version: 1models: merged block (all 9 keys present; unused-in-mode roles still carry the default value)claude_role_transport/claude_transport_resolved: same sourcing as the Y path above;claude_transport_downgraded: falsefor compatibilitycodex_reasoning_effort: same allowlist sourcing as the Y path; pass it towrite_orchestration_json. Model-only overrides do not change effort; validate model support before dispatch.source: "overridden"overridden_roles: list of role names that were actually overriddenpreflight_validated_at: <ISO8601 now>
-
Initialize
state.json:{ "quest_id": "<id>", "slug": "<slug>", "phase": "plan", "status": "pending", "quest_mode": "workflow", "vcs_available": true, "branch": "quest/<slug> or current branch", "branch_mode": "branch | worktree | none", "worktree_path": "/absolute/path/to/worktree (worktree mode only)", "quest_symlink": "created | present | migrated | conflict | n/a", "plan_iteration": 0, "fix_iteration": 0, "created_at": "<timestamp>", "updated_at": "<timestamp>" }Set
quest_modeto the user's final selection:"workflow"(default) or"solo". This field is read byworkflow.mdto determine agent dispatch and byquest_validate-quest-state.shfor artifact checks.vcs_availablemust be copied directly fromscripts/quest_startup_branch.pyoutput. Do not infer it frombranch_mode.branch_moderecords the actual startup mode used for this quest run after no-op handling. If Quest starts on an existing feature branch, setbranch_modeto"none"and record that branch inbranch.quest_symlinkmust be copied directly fromscripts/quest_startup_branch.pyoutput. Do not infer it frombranch_modeorworktree_path.
UI Work Propagation
When the recorded router classification has ui_work: true, downstream dispatch must load the UX skills:
- Planner, builder, fixer agents auto-load
.skills/ux-context/SKILL.md - Plan-reviewer and code-reviewer agents auto-load
.skills/ux-review/SKILL.md
The agent files in .skills/quest/agents/ enforce this — the orchestrator's job is to preserve the full router JSON in the brief so each agent can read it.
Signals
- GitHub stars
- 37
- Forks
- 6
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
quest-kjellkod- Source
- github.com/kjellkod/quest