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 becaus...
Scanned 5/27/2026
Install via CLI
openskills install synaptiai/synapti-marketplace---
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:
1. **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.
2. **Scope** — `repo`, `branch`, optionally `issue` and/or `pr`, optionally a `journal` path (`.decisions/issue-{N}.md`).
3. **Source** — typically the GitHub issue body (parsed for AC) or the PR description (parsed for review/address scope).
4. **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
1. **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.
2. **Compose `metadata`**:
```yaml
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>
```
3. **Compose `scope`** — from inputs. Set `journal` to the linked decision journal path. Leave `run_id` empty until `run-state-management` wires FlowRun creation.
4. **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."
5. **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.
6. **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).
7. **Compose `evaluator`**:
```yaml
evaluator:
type: flow_verdict_judge # hybrid for fuzzy criteria; deterministic for command-only
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
```
8. **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>`.
9. **Compose `lifecycle`** — initial state:
```yaml
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>
```
10. **Write atomically** — call `bin/flow-goal-record.sh` with the composed YAML. Verify exit 0; surface stderr on any failure.
11. **Record journal artifact** — `bin/journal-record.sh --issue {N} --type goal-created --metadata goal_id=<id> --metadata source=<src>`.
12. **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.
No comments yet. Be the first to comment!