goalify
Compose and lint a /goal stop-condition from the current conversation, catching known termination-failure patterns before showing it to the user. Use when the user wants to turn the current task into a /goal loop, asks to "goalify this", wants a stop condition for autonomous work, says "write a goal condition", "make this a /goal", "turn this into a goal", or asks for help wording a condition for /goal.
Run this procedure yourself, in the current conversation. Do not delegate it to a sub-agent or forked session — Phase 1 reads the live transcript.
$ARGUMENTS
If the user supplied focus text above, use it to scope Phase 1. If empty, extract from conversation alone — do not ask the user to restate what they already said.
Phase 1 — Extract
From the conversation so far, determine:
- The target end state. What does "finished" concretely look like? It must be a state that can be checked, not an activity that can be performed indefinitely. ("a usable app" is checkable; "finish building the project" is not — there is no test for "finished building".)
- What is already done. Re-read the transcript for completed sub-tasks, passing tests, merged changes, or resolved questions. These become candidates for the KNOWN section (Phase 2) or for narrowing scope (SCOPE-OUTS).
- What is explicitly NOT required. Anything the user has ruled out, deferred, or said isn't needed. This is the raw material for SCOPE-OUTS.
If the end state genuinely cannot be determined from context (not merely effortful to determine), ask one direct question. Otherwise proceed — guessing and then showing your extraction for correction is faster than front-loading a question the transcript already answers.
Phase 2 — Compose
Emit a candidate condition using this structure. Every element is required unless marked optional.
- One-sentence outcome naming a checkable end state (not an activity).
- Disjunctive exit: the condition must be satisfiable by either reaching the end state or conclusively demonstrating it cannot be reached (naming the blocker). Never phrase a condition with only one exit.
- Per-item negative terminal, if the condition lists multiple items (tasks, sites, phases, experiments). Each item must be able to resolve to its own PASS / FAIL / BLOCKED-with-named-reason — a blocker on one item converts that item to a residual; it must not block the whole goal.
- SCOPE-OUTS section — an explicit list of what is not required. Write this by directly converting anything from Phase 1's "not required" list into a plain negative statement (e.g. "No production soak time required." / "Uniformity across all N items is NOT the goal.").
- Reachable terminal verb, whenever finishing depends on an external system that can refuse — a work-tracker claim or resolution, a merge, a deploy, a publish. Name the primary verb AND the verb to use when the primary refuses. A terminal verb with no reachable fallback is a missing disjunctive exit one layer down: the actor can reach the end state and still be unable to record it, which reads to the evaluator as "not done" forever. See L7 for the work-tracker case, which is mandatory.
- KNOWN section (optional) — facts already established, so the actor doesn't re-derive them. Label it explicitly as a speed aid: it prevents wasted turns, it does not by itself prevent stalls, so it never replaces items 1–5.
Phase 3 — Lint
Check the full composed document against every rule below. Work through all BLOCKERS first; a document with any BLOCKER triggered is not ready to show. Then check WARNINGS, which are advisory and do not block presentation.
Read the whole document for each check. Several of these rules are only detectable by considering the document as one system — a single clause elsewhere can silently defeat a correct-looking rule everywhere else. Do not scan for keywords in isolation and stop at the first clean-looking match.
BLOCKERS — fix all before presenting
-
L1 — Ordering/provenance constraint on the transcript's own history. Any phrasing that requires evidence to precede, or be produced independent of, events that already exist in the transcript (e.g. "verify it yourself, then state what you verified", "proof must precede the claim", "evidence you produced yourself" applied to something already reported by a sub-agent or prior turn). This class of requirement is unrepairable — no later turn can change what already happened earlier in the transcript, so it cannot be fixed by adding more work. If the condition constrains ordering, it must constrain only future actions, never re-litigate what is already in the history.
-
L2 — Universal quantifier over a set with possibly-exempt members. "all N", "every X", "each of the Y", "uniform/uniformity", "complete parity", applied to a set, is a blocker unless each item individually carries a negative terminal (see Compose #3) or the condition names which members are exempt and why. Without one of those, a single member that cannot structurally produce the required evidence makes the whole condition permanently unsatisfiable.
-
L3 — Elapsed wall-clock requirement. Anything that requires real time to pass beyond the current session: "production soak", "after N days of use", "monitor over time", "verify in real-world use". A single session cannot advance wall-clock time; this can never be satisfied in-session.
-
L4 — Human-in-the-loop or external-actor dependency mid-loop. "stop and ask me if you need a decision", "once a reviewer merges this", "wait for approval before continuing". This directly conflicts with unattended continuation — the loop will halt waiting on an event that a condition-checking loop cannot itself produce.
-
L5 — Open enumeration. Scope phrased as an unbounded or unenumerated set: "all editing features of X", "complete parity with Y", "everything needed to fully support Z". An evaluator can always name one more item under this phrasing, so it never terminates. Convert to a closed, named list, or to a single representative artifact.
-
L7 — Work-tracker terminal verb that can refuse. Any condition whose completion requires
work_resolveorwork_releaseis a blocker unless the condition also nameswork_erratumas the terminal verb for the case where the item is already resolved, or held by another session. Bothwork_resolveandwork_releaserefuse a session that does not hold the item, and no amount of further work makes them succeed — so a condition that ends only in those verbs has no reachable terminal state from the moment a sibling session resolves the item.work_erratumis append-only, requires no claim, and any actor may call it at any time, which is exactly why it is the fallback.This applies to EVERY lane targeting a shared or many-lanes work item, not only the lane that happens to discover the problem. Write the fallback in; do not leave each lane to rediscover it.
Required wording in the composed condition (adapt the names, keep the structure and keep it as a plain instruction, per W4):
TERMINAL VERBS. Record the outcome with work_resolve(id=<item>, reason=<user-readable summary>) when this session holds the item. If work_claim refused, or the item is already resolved, or another session holds it: record the outcome with work_erratum(project=<project>, item_id=<item>, text=<same summary>) instead — append-only, no claim required — and treat that as the terminal step, complete. Do NOT retry work_resolve or work_release in that state; both refuse a session that never held the item. -
L0 — Cross-clause consistency (meta-rule). An escape hatch is only as strong as the strictest other clause in the same document. After confirming L1–L7 pass individually and a disjunctive exit exists, re-read the document once more asking only: is there any other sentence, anywhere in the document, that is stricter than the stated exit and would override it? A document can have a textbook-perfect exit clause and still be unsatisfiable because one unrelated sentence elsewhere re-imposes an L1–L7 style constraint the exit clause doesn't cover. Confirming an exit clause exists is not sufficient — confirm nothing else in the document is stricter than it.
-
L7 — Infrastructure provisioned without teardown or handoff in DONE. This one is not about whether the condition can terminate, but about the state it leaves behind when it does. If the goal stands up anything that outlives the run — containers, VMs, background servers, external environments — the condition must make teardown-complete, or an explicit named handoff to an owner, part of DONE. A goal whose satisfied state leaves resources running and unowned is abandoned, not finished. Does not fire for goals that provision nothing.
WARNINGS — advisory, do not block presentation
-
L6 — Missing disjunctive exit. The document should state achievement or a way to conclusively end in "not achievable, here is why" (see Compose #2). Flag and fix its absence where practical, but do not block presentation on it alone.
-
W1 — Multiple items are listed but not all of them carry their own negative terminal (some do, some don't).
-
W2 — No clause asking the actor to show evidence inline in the transcript as it's produced, rather than only asserting a result.
-
W3 — Scope reads like more than one session's worth of work (multi-week rollout language, coordination across many independent repos/teams, phased production deployment).
-
W4 — The condition contains a cautionary anecdote or narrative about a failure mode (e.g. "don't repeat what went wrong last time", "make sure this doesn't stall like before") rather than a plain instruction. Any such narrative addressed to the actor is read by the evaluator too, and can silently become a criterion the evaluator judges against instead of guidance the actor merely follows. State requirements as plain criteria, never as stories.
This applies to the condition you are composing right now. Write every clause as a direct instruction to the actor, never as a story about a past run. If you catch yourself writing "so that we don't repeat X", rewrite it as the direct requirement it implies, with no reference to the incident.
If a BLOCKER cannot be cleared
Rewrite and re-check. Allow up to three rewrite passes. If a BLOCKER still fires after three passes, stop and surface the specific tension to the user by name (e.g. "the user's own request requires enumerating an open-ended set — L5 fires no matter how I phrase it; how would you like to bound this?"). Do not present a condition that still fails a BLOCKER.
Output format
Produce output in this exact order:
- Write the file. Write the condition text to
.amplifier/goals/<slug>.md(create the directory if it does not exist), where<slug>is a kebab-case slug (≤ 40 chars) of the one-sentence outcome. Overwrite if the file already exists. State the path on its own line, e.g.Wrote: .amplifier/goals/usable-checkout-flow.md. - Render inline. Immediately after, show the same condition inside a fenced code block — terminal reflow will otherwise destroy its multi-line structure.
- Lint table. Follow with the lint report as a table.
- Next step, last. End the entire response with the recommended next
step and nothing after it: offer (do not auto-run)
/goal @<path>using the path from step 1, framed as what to run once any edits to the file are made and saved.
Wrote: .amplifier/goals/<slug>.md
<the condition text>
| Rule | Result | Note |
|---|---|---|
| L0 | no known pattern detected | ... |
| L1 | no known pattern detected | ... |
| L2 | no known pattern detected | ... |
| L3 | no known pattern detected | ... |
| L4 | no known pattern detected | ... |
| L5 | no known pattern detected | ... |
| L7 | no known pattern detected | ... |
| L6, W1–W4 | (list only the ones that fired) | ... |
A clean table means no known failure pattern was detected — not that the condition is validated. Say so if the user reads it as a guarantee.
Edit .amplifier/goals/<slug>.md directly for any changes. Then, as the
last line of the response: "Once you're happy with the file, run /goal @.amplifier/goals/<slug>.md to start the loop — want me to run it now, or
would you like to adjust anything first?"
microsoft/amplifier-app-cli · MIT · Revision 53d8833bbe9d
Be the first to comment
Share what worked or leave a question for the creator.