Grill With UI
jasonku09/grill-with-ui
Moves a design-grilling interview from the terminal to a local web page, where each question, recommendation and discussion thread can be handled in any order.
Turns an underspecified do-something request into a typed IntentSpec by looking things up, asking only necessary questions or halting, before any planning or coding.
$ npx skills add angel291592/Intent-Router --skill intent-router -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install angel291592/Intent-Router intent-router --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/angel291592/Intent-Router.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/intent-router .claude/skills/intent-router && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "intent-router" agent skill from https://github.com/angel291592/Intent-Router/tree/main/skills/intent-router into .claude/skills/intent-router/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "intent-router", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/angel291592/Intent-Router/tree/main/skills/intent-routerType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add angel291592/Intent-Router --skill intent-router -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install angel291592/Intent-Router intent-router --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/angel291592/Intent-Router.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/intent-router .agents/skills/intent-router && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "intent-router" agent skill from https://github.com/angel291592/Intent-Router/tree/main/skills/intent-router into .agents/skills/intent-router/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "intent-router", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add angel291592/Intent-Router --skill intent-router -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install angel291592/Intent-Router intent-router --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/angel291592/Intent-Router.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/intent-router .cursor/skills/intent-router && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "intent-router" agent skill from https://github.com/angel291592/Intent-Router/tree/main/skills/intent-router into .cursor/skills/intent-router/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "intent-router", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/angel291592/Intent-Router.git --path skills/intent-router--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add angel291592/Intent-Router --skill intent-router -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install angel291592/Intent-Router intent-router --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/angel291592/Intent-Router.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/intent-router .gemini/skills/intent-router && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "intent-router" agent skill from https://github.com/angel291592/Intent-Router/tree/main/skills/intent-router into .gemini/skills/intent-router/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "intent-router", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install angel291592/Intent-Router intent-routerInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add angel291592/Intent-Router --skill intent-router -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/angel291592/Intent-Router.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/intent-router .github/skills/intent-router && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "intent-router" agent skill from https://github.com/angel291592/Intent-Router/tree/main/skills/intent-router into .github/skills/intent-router/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "intent-router", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add angel291592/Intent-Router --skill intent-router -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install angel291592/Intent-Router intent-router --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/angel291592/Intent-Router.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/intent-router .opencode/skills/intent-router && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "intent-router" agent skill from https://github.com/angel291592/Intent-Router/tree/main/skills/intent-router into .opencode/skills/intent-router/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "intent-router", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
intent-routerTurns an underspecified do-something request into a typed IntentSpec by looking things up, asking only necessary questions or halting, before any planning or coding.
Intent-router works one step ahead of planning. It parses the request into a draft spec, resolves each open question by checking what its sources already hold (code, history, decision records, tickets, policies) or by asking you, then type-checks the spec and either routes it onward, asks, or halts. It does not implement anything itself.
It starts only when the request asks for action and a quick scan finds at least one unknown that would change the files touched, the approach, how failures behave or what counts as done. Questions are limited to preference or irreversible choices, asked one at a time with a recommended default. Saved contracts in a .intent folder are reused by source: asked answers carry over, probed facts are re-checked, and inferences are decided again.
Bundled files include reference notes (ask protocol, domains, the IntentSpec format, probe surfaces, harness compatibility) and a JSON schema with example specs for route, ask and halt outcomes. The skill stays silent on fully stated tasks and on requests that only ask for an explanation of existing state.
9 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 00b54f2. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are yaml).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Intent Router loads about 7.9k tokens when it runs, and up to ~20k if it reads all its reference files. Until then it costs about 258 tokens; SKILL.md has 4,423 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from angel291592/Intent-Router at commit 00b54f2, republished under its MIT licence (© angel291592). 4,423 words, ~7,890 tokens.
.claude/skills/intent-router/SKILL.md (or your agent's skills folder). This skill also uses 11 other files; get the full folder from GitHub.A compiler does not guess the address of an undefined symbol. Do not guess the user's intent.
This runs one layer before planning, routing or coding. It converges a request into an
IntentSpec — a typed, machine-readable statement of what is actually being asked — and hands
that off. It does not implement anything itself.
Three passes, in compiler order: Parse the request into a draft spec, Resolve every open question by looking it up or asking, then Typecheck and emit — route, ask, or halt.
Start when both hold:
Do not start when: the request asks you to explain existing state ("what does X do", "why is Y slow") rather than to find something out and produce a deliverable; the silence check below passes and its premise check finds no contradiction — every decision-bearing item is already stated, so there is nothing to converge; or the request is trivially scoped and reversible (fix a typo).
Look for a saved contract first. Before probing, look for earlier work on this same request:
<workspace>/.intent/<intent>.intent.yaml, stem = the intent slug, matching on
request/objects. Its verification_status decides:
asked — its source: asked constraints are settled decisions: carry them in and never ask
those questions again; only answers received now count in resolution.asked.routed — premise-check it (below), carry it out, then verify it. verified — carried out
already: do not reopen unless the user asks for a redo, which marks the old file superseded
and starts a new intent. superseded, or absent on an older file — ignore it, or use it only
to know what was asked and done.Inherit by source, never wholesale: the file is not a probe surface (section 2). asked carries
over; probed is re-checked at its evidence pointer and drops to unknown (kind: probe) when it
no longer holds; inferred is never inherited — decide it again, and if it is still an inference
keep source: inferred and mark it visibly again. Never relabel an inherited value explicit or
probed.
The silence check. Run it once, against the request text alone, before probing anything. The request is fully specified when all four hold:
If all four hold, make one premise check before staying out of the way: at most two lookups at
the sources most likely to rule out what the request states — a decision record or history entry
about the named approach, the manifest entry for a named dependency, the definition of a named
object. If nothing you open contradicts the request, do not run: emit no spec, no fence, no
announcement that you considered this skill — carry the request out as ordinary. A spec emitted
after a passed silence check is a false positive, costing more than this skill saves. If a source
does contradict it (tried and reverted, pinned or removed, does not exist), run, with that
contradiction as a premise issue (section 3); an approach you merely prefer is never one.
If any one of the four is unstated, run — and do not downgrade an unstated item to "inferable" because a plausible default exists: if the user had to be trusted with the outcome, or the spec could be wrong without contradicting the request, it is unstated.
No-ask mode. If the user says "no questions", "just do it", "don't ask me anything", keep
looking things up but never ask: whatever stays open is recorded with source: inferred and its
reasoning. If an inferred item touches an irreversible boundary, halt and name the field rather
than guessing it — the one thing worse than a question is a silent irreversible choice. Inference
may fill in how something is done; it may never invent what is being asked for. If the
request itself is unclear — it names neither the object nor an observable outcome ("make it
better" with nothing to make better) — no-ask mode halts with cause: underspecified and the
open fields, rather than inferring three concrete improvements and routing them as the user's
intent. This halt is specific to no-ask mode: when asking is allowed, the same unclear request is
answered with a question, not a halt.
Explicit invocation. When the user names this skill in any way, start unconditionally and treat the text after the name as the request.
intent, objects, and every
constraint needed to act without guessing.path, path:line, path:line-line,
path#heading, git:<short-sha>, git:#<pr-number>, user:delegated (a decision handed back),
record:<system>/<id>, doc:<slug>#<section>. Not evidence: the repository root (.), anything
under .git/, .claude/, .agents/ or .intent/, the harness config file, and above all a
reasoning sentence — that goes in text. Anything else is a defect, even if it exists.Produce a draft spec. Do not emit it, do not act on it.
request, truncated to 500 characters. Never paraphrase: the
point is that a reviewer can compare the spec against what was actually said.intent, a snake_case verb-object identifier: add_caching,
migrate_auth, rate_limit_signup.objects — files, endpoints, modules, jobs, records. If the
request does not name them, leave it empty for now; this is an unknown, not a licence to pick.constraints with source: explicit. A stated
constraint is never re-derived, and is questioned for one of two reasons only — it collides with
another stated constraint, or a source you opened contradicts it (the conflict and premise
issues below).field name, a category from the table below, and
a judgement: decision-bearing or not. In the emitted spec an unknown item carries exactly
field, kind, and optionally category, issue and note — never a decision_bearing
flag, a free-form detail, or any other key; the judgement itself is expressed by keeping the
item out of unknown when it is not decision-bearing.| category | the question it asks | example in code | example outside code |
|---|---|---|---|
scope | what is acted on, and what is explicitly out | which endpoints get cached | which orders in this account are in scope |
approach | which method or dependency; what is mandatory or forbidden | existing Redis client or a new in-process cache | goodwill credit, or a carrier claim |
data_compatibility | data shape, interface contract, backward compatibility | may the response shape change | may the reply change the date already promised |
failure_behavior | behaviour on error, degradation or empty state | on invalidation failure, serve stale or uncached | if the refund is declined, hold the ticket or escalate |
acceptance | what counts as done, measurably | which TTL matches the repository's convention | what closes the ticket — customer confirmation, or the SLA timer |
non_goals_constraints | explicit exclusions, hard limits on time, cost, compliance | no new dependencies | no commitment beyond the policy in force |
When the request touches any step that can fail, be rejected, or half-complete — a cache write, a
refund, a backfill, a notification, an approval — and states no rule for that failure, enumerate
the failure path as its own unknown: not "what should the feature do" but "what should happen when
the feature's own step fails" — a cache write that errors, an invalidation that misses, a dependency
that times out. Skipping it while emitting a happy-path spec is the guess this pass exists to
prevent; and when the request does state the failure rule, that is an explicit constraint,
never an unknown — re-opening it to split sub-cases the user did not distinguish is the over-asking
this skill exists to remove.
Three defects that filling in cannot fix. Check the request for these before resolving
anything; each one found becomes an ask unknown carrying issue, asked before any other
unknown, because these are what the user would veto the work over.
ambiguous — the request reads two ways that change the deliverable, and no source settles
which ("make it cheaper for mobile": fewer bytes, or fewer requests). Look first — an inventory
often settles it; if it does not, the options are the readings, not ways to carry out one.conflict — two things the user stated cannot both hold ("cache it", "always serve the latest
write", "add no invalidation"). The options say which one yields.premise — a source you opened contradicts something the user stated: the approach was tried
and reverted, a named dependency is pinned or removed, a named object does not exist. It
surfaces while probing. Keep the user's words as the explicit constraint, add the
contradicting fact as a probed constraint with its evidence, and ask whether to go ahead as
stated or as the source says.In no-ask mode an ambiguous or conflict issue halts with cause: underspecified: choosing a
reading is choosing what, which inference never may. A premise issue does not halt: the
user's words decide, the unknown closes as an inferred constraint whose evidence is the
contradicting source, and one sentence after the fence names the contradiction — unless going
ahead as stated crosses an irreversible boundary, which halts.
Unknowns that are not decision-bearing do not enter Pass 2. Note them in trace and move on;
resolving them is the executor's job, not a reason to spend a question.
This pass is the whole point. Everything else is bookkeeping.
If an objective answer exists and you have any means to reach it, PROBE. Never ASK. ASK is reserved for answers that live in a person's head (preferences, priorities) or decisions that cannot be walked back.
Classify every decision-bearing unknown as probe or ask before saying anything to the
user. A question whose answer was sitting in the workspace is a defect, not a courtesy.
Name the sources first. A code workspace → the surfaces below; anything else (a ticket queue, a
records system, a policy archive, a notes collection, a candidate registry) → load
references/domains.md and use that domain's table. Use whatever file-reading, search, or shell
capability your environment provides, version-control history included; if it exposes none, see
degraded below: an absent capability is a fact about the environment, never a gap in the request.
Work the probe surfaces in this order, stopping as soon as the unknown is settled:
trace; with no shell, read the history files on disk (reference log, stored commit
message). Evidence is git:<short-sha> or git:#<number>, never a path in the history store.Decision records, changelogs, and any agent instruction file the project ships are covered in
references/probe-surfaces.md, together with the surfaces for other ecosystems.
Budget: at most 3 probe actions per unknown, plus the one reserved history query below, which
does not count against it. Do not read the whole repository. If an unknown survives its budget,
escalate it: to ask if a person could answer it, otherwise leave it in unknown with
kind: probe so the halt names it.
A dangling reference is not a settled unknown. A what-only answer — a changelog line, comment,
config value or record field naming a pull-request number, "revert", "pin" or "workaround" with no
reason — has not settled it. Follow the reference once as the reserved history query, outside
the 3-action budget, then stop; if the reason is still missing, reclassify it ask.
Every probed value carries evidence. A probed or inferred constraint needs an evidence
pointer — one per field, never two comma-joined (the second gets its own constraint or trace entry).
Record facts you were not looking for when they constrain the work, and point at every probed object.
Degraded. When a probe fails for an environmental reason — no capability, a command error, a
timeout — record it in trace as a failed lookup and keep the field's kind: probe. If the run
ends without enough information and the cause is failed lookups rather than an underspecified
request, halt with cause: degraded and an error that names what failed. Never present a broken
environment as a vague request, or the reverse.
An empty probe surface is not a failed lookup. degraded means a lookup was attempted and
failed; an empty repository, or a request naming no existing code, failed nothing. Reclassify the
affected unknown as kind: ask and ASK: a person can still say what this should become.
Only for answers that live in a person's head, or decisions that cannot be walked back.
Ask order. When several unknowns are askable, ask the one whose answer the user would veto the work over first — an observable behaviour or contract (what happens on failure, what the response looks like, what is in scope) before internal placement (which layer, which file, which module), because internal placement is the executor's call and may dissolve once the behavioural answer is known. Never pick a question for being easy to answer. The section 3 issues come before all of these.
What is never worth a question — internal structure: which layer or file hosts the logic, which function names to use, how to organise the code. These are reversible implementation details; whoever executes decides them. If the only remaining unknown is internal, the spec is sufficient — infer it visibly and route.
Eliminating options is not resolving the unknown. If only one option remains because you ruled the others out by reasoning — "stale reads are unacceptable, so fall through is the only choice" — the surviving option is itself the preference the user should confirm (fail fast with 5xx, serve uncached, queue and retry…). Infer it only when the user's own words or the workspace state it; otherwise ASK.
Budget: 3 questions per request by default. The user may override ("ask up to 5"); record
whatever cap is in force as resolution.ask_budget. In no-ask mode the budget is 0.
One question at a time. Wait for the answer before asking the next; do not preview what else you might ask, and do not batch — a list puts the sorting work back on the user.
Each question has exactly this structure:
<option id> — <reason> — the option you would take if the user delegates.A, B, C. Not
restatements of the question, and not "other".Delegation. On "you decide", "whatever", "your call", take the recommended option and record
it with source: inferred and evidence: user:delegated — unless it is irreversible: true:
then restate the risk in one sentence and ask once more, which counts against the budget.
Language. Ask in the language the user wrote in — a hard rule, whatever language the workspace or your runtime instructions use (section 6, check 3). Spec keys stay English.
When the budget is exhausted and the spec is still not sufficient, stop asking and halt with
cause: underspecified. Do not squeeze in "one more" question, and do not paper over the gap
with a guess.
Templates, worked good-versus-bad questions, and the delegation and override rules in full are in
references/ask-protocol.md.
The stopping condition is computed, not felt:
sufficient ⟺
unknownis empty ∧ no constraint has bothsource: inferredandirreversible: true.
Then exactly one of three outcomes:
decision.state: ROUTE and a
target: implement, plan, research, respond, escalate, prototype, or whatever the
user named. Name the saved spec file in the hand-off and ask for every constraint to be checked
before the work is called done, then stop — do not implement inside this skill. When the
handed-off work is carried out in this conversation, verify it and report (below).decision.state: ASK and decision.question set to the one question you are asking, then
the question itself, then wait. The unresolved field stays in unknown and resolution.asked
still counts only answers received, not questions sent. Nothing inferred in an ASK snapshot may
depend on the pending answer: "done means the chosen remedy is executed" is the open decision
itself, not an inference — it belongs to the question's options, not to constraints.cause: underspecified when the request is not
yet decidable, with open_fields naming what is still dangling; cause: degraded when lookups
failed, with error naming the failure. The two causes are mutually exclusive and must never be
merged: one is the user's next move, the other is an operations signal. Underspecified is not
a halt while a question is still possible: if an askable unknown remains and the budget allows
a question, the outcome is ASK, not HALT. HALT underspecified is reserved for when asking is
impossible — no-ask mode, or the budget spent. An empty workspace is ASK, never HALT (see 4.2).A spec that reaches ROUTE with an inferred constraint in it is fine — that is the design. One that
reaches ROUTE with an inferred irreversible constraint is a bug.
When the work a ROUTEd spec handed off is carried out in this same conversation, verify it before
reporting it done. Reread the saved spec — or the fenced block, if it could not be saved — and check
the finished work against every constraint on what it must or must not do. Report one line per
constraint, after the work summary, under a line reading exactly Intent check, which stays in
English whatever the language; the lines under it use the user's language:
path:line) where the delivered work satisfies it;Never mark a constraint met without a pointer into the delivered work — and the pointer must be the
line that satisfies that constraint, not a neighbouring branch or a similar handler. Work that
does not implement the constraint is not met, however plausible the file looks. The check reads
the spec; it does not reopen it — a decided constraint is checked, not asked again.
Write the result back into the same .intent/ file, replacing its earlier snapshot:
verification_status: verified, plus verification with its status, a checked_at, and one
results line per constraint carrying constraint, verdict and — when met — pointer. The reply
keeps the same lines under Intent check: the file is for the next session, not a substitute for
telling this user. A delegated check carries the spec path and runs in a fresh context — a check
sharing the implementer's is not a check.
Lead with the human part. Before the fence, 3–6 lines of prose: what you looked up, above all the
finding that changed the approach; what you decided for the user, one line each, so any line can be
vetoed; and the one question, if any. Then the fenced yaml block, whole spec, in field order.
The fence stays. Some environments keep only a turn's final message, and the eval reads the spec from the reply, so the block is never dropped in favour of the prose; a workspace that cannot be written to still gets one sentence after it (below).
Quote every dirty scalar. Any value containing :, #, {, }, [, ], ,, " or ',
or starting with a character that is not a letter, must be wrapped in single quotes — an inner
' is written ''. Multi-line text uses the block scalar > instead. Single quotes, not double:
the offending characters are usually double quotes themselves ("ioredis": "^5.4.1"), and
single-quoting needs no escaping. The dangerous case is a # after a space (a reference like
reverted in #412): unquoted, YAML reads it as an inline comment and silently truncates the
value — the fence still parses, so a corrupted spec survives a review a hard error would catch.
spec_version: "0.1"
request: add rate limiting to the public endpoints
intent: add_rate_limiting
objects:
- POST /api/login
- POST /api/signup
constraints:
- source: explicit
text: apply it to the public endpoints only
category: scope
- source: probed
text: 'the entry point already registers a rate-limit middleware: mounted before the routes'
evidence: src/app.ts:24
category: approach
- source: asked
text: 'reject over-limit requests with 429 and the body { error: "rate_limited" }, not by queueing them'
irreversible: true
category: failure_behavior
unknown: []
decision:
state: ROUTE
confidence: 0.82
target: implement
resolution:
unknowns_found: 2
resolved_by_probe: 1
asked: 1
inferred: 0
ask_budget: 3
trace:
- step: parse
detail: two decision-bearing unknowns — middleware choice and over-limit behaviour
- step: probe
detail: the entry point already registers a rate-limit middleware, so no new dependency
evidence: src/app.ts:24
- step: ask
detail: asked the one irreversible choice; the user chose rejection over queueing
- step: emit
detail: unknown is empty and no inferred constraint is irreversible — sufficient; handing offconfidence is a self-reported ordinal, not a calibrated probability; resolution is a diagnostic,
not a score to push up. Before emitting, reread the block and check it against these three:
unknowns_found, which counts
the closed ones too, so unknowns_found = resolved_by_probe + asked + inferred + len(unknown)
must hold. Count unknowns, not constraints: two probed constraints settling one unknown add 1,
not 2, and a fact recorded because it constrains the work but closing no unknown adds nothing to
any counter — it is still a constraint with its evidence. A probe that settled something unlisted
does count, in both resolved_by_probe and unknowns_found; the attributed unknowns belong in
the parse and probe trace steps, so the scorecard can be checked rather than trusted.probed and inferred constraint carries an evidence token; one missing
pointer invalidates the spec — an unsourced claim is indistinguishable from a guess.why_human and every option in the user's language (4.3).Every trace step is exactly one of parse, probe, ask, typecheck, emit — there is no
infer, resolve or decide step; an unknown closed by inference is a constraint with
source: inferred, not a new trace step.
For the other two states, decision carries different fields and nothing else changes:
decision:
state: ASK
confidence: 0.55
question:
text: <the question, in the user's language>
why_human: <why this cannot be looked up>
recommended: A
options:
- id: A
text: <concrete option>
- id: B
text: <concrete option>decision:
state: HALT
confidence: 0.2
cause: underspecified # open_fields required; error forbidden
open_fields: [scope, acceptance]Every emitted spec is also saved. Before replying, write it to .intent/<intent>.intent.yaml
— on ASK, ROUTE and HALT alike, replacing this request's earlier snapshot, with
verification_status: asked on ASK and HALT and routed on ROUTE — and touch no other file for it.
Nothing is written when you stay silent (section 1); a workspace you cannot write to gets one
sentence after the fence, never a halt. The field reference and the .intent/ convention are in
references/intentspec.md; the machine-checkable contract is schema/intentspec.schema.json.
Some questions cannot be resolved by probing or asking, because the user cannot answer them in
the abstract either ("make it feel modern", "make the onboarding delightful"): the signature is an
aesthetic or experiential target with no observable acceptance criterion, which no conceivable
file in the workspace could name. Recognise this in Pass 1, before spending probe budget —
probing it never converges, and it is not worth a question either. Name the ungrillable field, say
it needs something to react to rather than more discussion, and hand off to a throwaway artifact as
the target — a prototype or mock, a draft reply, one sample record — or halt with the field in
open_fields. Never quietly pick a direction and present it as the user's intent.
probed or inferred constraint with no evidence.Load on demand; each is self-contained.
references/probe-surfaces.md — probe surfaces per ecosystem, evidence formats, degraded cases.references/ask-protocol.md — question templates and examples, delegation, budgets, language.references/intentspec.md — every field, the invariants, the worked examples, .intent/ files.references/domains.md — probe surfaces and questions outside code, routing-registry criteria.references/harness-compat.md — which environments load this skill, from where, how to invoke.© angel291592, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 11 other files (references) in skills/intent-router of angel291592/Intent-Router.
Open the folder on GitHubat commit 00b54f2
Intent Router next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Intent Router this skillangel291592/Intent-Router | 1k | — | ~7.9k | Automated safety check: Pass | MIT | |
| Grill With UIjasonku09/grill-with-ui | 258 | — | ~7.9k | Automated safety check: Pass | MIT | |
| Interview Meaddyosmani/agent-skills | 104k | 6 repos | ~3.8k | Automated safety check: Pass | MIT | |
| Ask User QuestionMemTensor/MemOS | 12k | — | ~1k | Automated safety check: Pass | Apache-2.0 | |
| Brainstorming Before BuildingjnMetaCode/superpowers-zh | 8.3k | — | ~1.8k | Automated safety check: Pass | MIT | |
| Plannotator Planning Analysisbacknotprop/plannotator | 9.3k | — | ~6.7k | Automated safety check: Pass | Apache-2.0 |
jasonku09/grill-with-ui
Moves a design-grilling interview from the terminal to a local web page, where each question, recommendation and discussion thread can be handled in any order.
addyosmani/agent-skills
Asks one question at a time, each with a best guess attached, until the agent is about 95 percent sure what you really want, before any plan, spec or code.
MemTensor/MemOS
Shows a question as a modal in the interface to clarify a task, collect a preference or get approval, since the user cannot see terminal output.
jnMetaCode/superpowers-zh
Turns a rough idea into an approved design before any code is written, sorting the request into spike, bounded or architectural and enforcing an approval gate.
backnotprop/plannotator
Mines a Plannotator archive of denied plans for feedback patterns and prompt improvements, then writes an HTML dashboard report, with a Claude Code fallback.
code-yeongyu/oh-my-openagent
Explore-first planning that turns a vague or large request into one decision-complete work plan, written only after your approval and executed by a separate worker.
Categories
Turns an underspecified do-something request into a typed IntentSpec by looking things up, asking only necessary questions or halting, before any planning or coding. Intent-router works one step ahead of planning. It parses the request into a draft spec, resolves each open question by checking what its sources already hold (code, history, decision records, tickets, policies) or by asking you, then type-checks the spec and either routes it onward, asks, or halts.
Intent Router fits situations like: A request leaves open which approach or which objects to change; A ticket or task contradicts itself or allows two readings; before planning a migration whose failure behavior is unspecified; when you want the agent to clarify the intent before it starts.
Run `npx skills add angel291592/Intent-Router --skill intent-router -a claude-code`. Or copy the skill folder (skills/intent-router in angel291592/Intent-Router) into .claude/skills/intent-router in your project. Claude Code loads it when a task matches its description.
Run `npx skills add angel291592/Intent-Router --skill intent-router -a codex`. Or copy the skill folder (skills/intent-router in angel291592/Intent-Router) into .agents/skills/intent-router in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add angel291592/Intent-Router --skill intent-router -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/intent-router, .gemini/skills/intent-router, .github/skills/intent-router and .opencode/skills/intent-router in your project.
SKILL.md names no scripts, command-line tools or credentials: Intent Router is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Intent Router is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 7.9k tokens (SKILL.md is roughly 32k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 12k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Intent Router: Grill With UI (jasonku09/grill-with-ui, 258 stars), Interview Me (addyosmani/agent-skills, 104k stars), Ask User Question (MemTensor/MemOS, 12k stars) and Brainstorming Before Building (jnMetaCode/superpowers-zh, 8.3k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
angel291592 (a GitHub user) maintains it in angel291592/Intent-Router, which has 1,048 GitHub stars. The repository was last updated on October 9, 2026.
Source: angel291592/Intent-Router on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.