| name | goal-contract-capture |
| description | Capture a FlowGoal contract as a project-local `.flow/goals/<id>.goal.yaml` file with outcome, acceptance criteria (with verification commands), specification elements (non-goals, failure modes, interface contracts), constraints, evaluator binding, continuation policy, and lifecycle frontmatter. Use when /flow:start passes the Spec Validation Gate, when /flow:goal create is invoked, or when /flow:review and /flow:address need a completion contract for a PR. This skill MUST be consulted because acceptance criteria alone do not constitute a contract — without an evaluator binding, boundaries, and lifecycle state, downstream phases cannot detect premature completion, the Stop hook cannot enforce evidence, and goals cannot resume across sessions. |
| allowed-tools | Bash, Read, Write, Edit, AskUserQuestion |
| agent | general-purpose |
Goal Contract Capture
You produce a FlowGoal contract — a durable completion contract that turns acceptance criteria + specification into a machine-readable, file-backed artifact. This skill is the 5th invoker of the existing specification-capture pattern; it wraps that skill (does NOT replace it) and adds the goal-specific fields needed for evaluator/Stop-hook enforcement.
Iron Law
No /flow:goal create without a complete contract. No .flow/goals/<id>.goal.yaml without an evaluator binding. The contract is the source of truth for the Stop hook and /flow:goal evaluate; gaps here cascade into silent premature completion.
Relationship to existing skills
This skill is a wrapper, not a fork:
| Existing skill | What it gives us | What this skill adds |
|---|
specification-capture | non-goals, failure modes, interface contracts | the specification block in the goal YAML |
criterion-verification-map | per-AC verification commands + expected evidence | the objective.acceptance_criteria[].verification_command field |
evidence-based-development | ASSERTION/EVIDENCE/VERIFIED discipline | the evidence_ref linking the AC back to a FlowEvidence sidecar |
If those skills have already produced their outputs (decision journal manifest entries), this skill reads from them rather than re-asking the user.
Inputs
The invoking command MUST pass:
- Goal id — typically
issue-{N}, pr-{N}-review, pr-{N}-address, or an ad-hoc slug. Validated against the schema's ^[a-z0-9][a-z0-9-]{0,63}$ pattern.
- Scope —
repo, branch, optionally issue and/or pr, optionally a journal path (.decisions/issue-{N}.md).
- Source — typically the GitHub issue body (parsed for AC) or the PR description (parsed for review/address scope).
- Invocation reason —
start | goal-create | review | address. Used to choose the right outcome template and the right evaluator.type.
Outputs
Single file: .flow/goals/<id>.goal.yaml conforming to plugins/flow/schemas/v1/goal.schema.json. Written via bin/flow-goal-record.sh (atomic, O_NOFOLLOW-defended).
Plus: one goal-created artifact appended to the linked decision journal via bin/journal-record.sh --type goal-created --metadata goal_id=<id> --metadata source=<src>.
Workflow
-
Pre-flight check — refuse if .flow/goals/<id>.goal.yaml already exists and lifecycle.status is not in {cancelled, failed}. Surface the existing goal to the user via the six-field escalation; never silently overwrite an active goal.
-
Compose metadata:
metadata:
id: <derived-from-invocation>
created_at: <ISO-8601 UTC now>
created_by: <invoking command, e.g. /flow:start>
owner: <git user.email or @me>
-
Compose scope — from inputs. Set journal to the linked decision journal path. Leave run_id empty until run-state-management wires FlowRun creation.
-
Compose objective — pull AC text + verification commands from the existing criterion-verification-map output. Each AC is one entry with status: pending and evidence_ref: null initially. The outcome is a one-sentence statement derived from invocation reason:
start → "Issue #{N} is implemented and verified."
goal-create → user-supplied via AskUserQuestion.
review → "PR #{N} review completed with findings posted or no-finding evidence recorded."
address → "All unresolved findings on PR #{N} are resolved, commented, or escalated."
-
Compose specification — lift from specification-capture's journal entries:
non_goals from the ## Specification > ### Non-goals body
failure_modes from ### Failure modes
interface_contracts from ### Interface contracts
If any block is empty, raise the six-field escalation per references/escalation-format.md — do NOT silently fill with placeholders.
-
Compose constraints — default to tdd_required: true, require_all_pass: true, no_calendar_estimates: true, no_tier3_without_confirmation: true. Add denied_paths from settings (flow.goals.denied_paths cascade key); add allowed_paths only if the goal narrows the tier model (e.g., a focused refactor).
-
Compose evaluator:
evaluator:
type: flow_verdict_judge
command: /flow:goal evaluate
judge_agent: goal-evaluator-judge
evidence_bundle_format: plugins/flow/references/evidence-bundle-format.md
denied_context:
- implementation_rationale
- self_review_findings
-
Compose continuation — defaults: mode: flow_managed, on_incomplete: continue_next_activity, on_blocked: six_field_escalation, on_complete: mark_achieved, max_iterations: <from settings, default 20>.
-
Compose lifecycle — initial state:
lifecycle:
status: active
current_phase: <derived; start→explore, review→fan-out, address→categorize>
current_activity: <first activity id>
turns_evaluated: 0
last_evaluation:
result: incomplete
reason: "Goal created; evidence not yet collected."
at: <now>
-
Write atomically — call bin/flow-goal-record.sh with the composed YAML. Verify exit 0; surface stderr on any failure.
-
Record journal artifact — bin/journal-record.sh --issue {N} --type goal-created --metadata goal_id=<id> --metadata source=<src>.
-
Verify the artifact — read back .flow/goals/<id>.goal.yaml and validate against the schema (Python jsonschema if available). A schema mismatch here means the skill or the schema is broken; fail hard.
Per-invoker scope
| Invoker | Captures | Skips |
|---|
start | All blocks; outcome derived from issue title | nothing |
goal-create | All blocks; outcome from AskUserQuestion | journal manifest if no issue |
review | Outcome + AC (= review checklist) + constraints | specification (use issue's existing capture) |
address | Outcome + AC (= one per unresolved PR comment) + constraints | specification (inherit from review goal) |
Anti-patterns
- ❌ Silently overwriting an active goal — always surface and escalate.
- ❌ Filling in empty specification blocks with placeholders — escalate via six-field.
- ❌ Bypassing
bin/flow-goal-record.sh for "speed" — atomicity + symlink defense matters.
- ❌ Setting
lifecycle.status: achieved at creation — the only way to achieved is through /flow:goal evaluate.
Reuse map
plugins/flow/skills/specification-capture/SKILL.md — read the per-invoker scope table; this skill adds row 5 (goal-create).
plugins/flow/skills/criterion-verification-map/SKILL.md — read for the AC verification-command shape.
plugins/flow/schemas/v1/goal.schema.json — the canonical schema this skill writes against.
plugins/flow/bin/flow-goal-record.sh — atomic writer.
plugins/flow/bin/journal-record.sh — for the goal-created manifest artifact.
plugins/flow/references/escalation-format.md — six-field escalation for any empty/ambiguous block.