goal-lifecycle — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited goal-lifecycle (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You own the FlowGoal state machine. Every lifecycle.status transition is mediated through this skill — no exceptions, no shortcuts, no "I'll just edit the YAML directly."
No transition without an audit-trail entry. The decision journal MUST receive a `goal-evaluation` artifact (or `goal-created` for the initial draft→active) on every transition. A `lifecycle.last_evaluation` block without a matching journal entry is a bug.
┌────────────────────────────────────────────────────────┐
▼ │
┌───────┐ │
│ draft │──┐ │
└───────┘ │ │
▼ │
┌──────────┐ │
│ active │────────────────────────────┐ │
└──────────┘ │ │
│ │ │ │ │ │
│ │ │ └─→ waiting_for_ci ────────┤ │
│ │ └────→ waiting_for_user ────────┤ │
│ └───────→ blocked ────────┤ │
│ ▼ │
├──────────────────────────────→ achieved │
├──────────────────────────────→ failed │
└──────────────────────────────→ cancelled ───────────┘
Terminal: {achieved, failed, cancelled}
Resumable: {waiting_for_user, waiting_for_ci, blocked}Allowed transitions:
| From | To | Trigger |
|---|---|---|
draft | active | goal-contract-capture completes; /flow:goal create returns |
active | waiting_for_user | judge verdict needs_human_review; AskUserQuestion mid-evaluation |
active | waiting_for_ci | CI run pending; goal waits on external signal |
active | blocked | judge verdict blocked (with blocker_type); path-boundary violation |
active | achieved | deterministic all-pass + (no fuzzy OR judge achieved) |
active | failed | budget exhausted (max_iterations or max_runtime); stuck pass-set ≥ N turns; deterministic must_pass FAIL with no fix path |
active | cancelled | user invokes /flow:goal clear <id> |
waiting_for_user | active | AskUserQuestion resolves; user runs /flow:goal resume |
waiting_for_ci | active | CI status transitions to terminal |
blocked | active | blocker resolved (manual or /flow:goal resume after fix) |
Disallowed transitions (the helper rejects these):
terminal → any — once achieved/failed/cancelled, the goal is immutable. New work requires a new goal id.active → draft — no going back to draft.blocked → achieved direct — must transition through active first (forces an evaluation step).The invoking command/skill MUST pass:
.flow/goals/<id>.goal.yaml.evaluator | command | hook | user. Affects which journal artifact type is written..flow/goals/<id>.goal.yaml with new lifecycle.status, lifecycle.last_evaluation, and (optionally) new lifecycle.current_phase / current_activity.goal-created if from=draft to=activegoal-evaluation for all other transitions.flow/runs/<run-id>/events.jsonl (when run_id is set).Read the current .flow/goals/<id>.goal.yaml. Compare lifecycle.status with the caller's from parameter:
Check the transition is allowed (per the table above). Reject disallowed transitions with stderr explanation and exit 1.
lifecycle:
status: <to>
current_phase: <preserved or updated by caller>
current_activity: <preserved or updated by caller>
turns_evaluated: <incremented if from active and to in {active, waiting_*, blocked}>
last_evaluation:
result: <maps to status: pass→achieved, incomplete→active, fail→active (with failing AC), blocked→blocked, needs_human_review→waiting_for_user>
reason: <caller-provided>
at: <ISO-8601 UTC now>Invoke bin/flow-goal-record.sh --update-lifecycle with the new block. The helper:
O_NOFOLLOW)schemas/v1/goal.schema.json (when jsonschema available)For draft → active:
bin/journal-record.sh --issue {N} --type goal-created \
--metadata goal_id=<id> \
--metadata source=<e.g., github_issue:42>For all other transitions:
bin/journal-record.sh --issue {N} --type goal-evaluation \
--metadata goal_id=<id> \
--metadata result=<to-state> \
--metadata reason=<short, comma-safe>When the journal-issue link is unavailable (ad-hoc goals from /flow:goal create with no issue), write to a session-scoped journal (.decisions/session-{YYYY-MM-DD}.md) per the existing convention.
# Conceptually — actual call goes through bin/flow-record-activity.sh
# or a future bin/flow-record-event.sh
event = {
"at": <now>,
"type": "lifecycle_transition",
"goal_id": <id>,
"from": <from>,
"to": <to>,
}
append_jsonl(f".flow/runs/{run_id}/events.jsonl", event).flow/goals/<id>.goal.yaml outside bin/flow-goal-record.sh — race conditions, no audit trail.terminal goal back to active — by design impossible. New goal id required.last_evaluation.reason as a free-form essay — keep it < 200 chars, comma-safe; full reasoning lives in the journal artifact body.plugins/flow/bin/flow-goal-record.sh — atomic lifecycle writer.plugins/flow/bin/journal-record.sh — manifest artifact recorder.plugins/flow/references/decision-journal-schema.md — goal-created and goal-evaluation artifact-type rows.plugins/flow/references/escalation-format.md — six-field escalation for race-condition mismatches.plugins/flow/schemas/v1/goal.schema.json — lifecycle.status enum.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.