agentsclimarketplace

Phase sdd rules

Skill zig999/siegard-code/dist/.claude/skills/phase-sdd-rules

Most AI coding tools help you write code. Siegard Code manages the entire development lifecycle — it writes specifications, plans backlogs, implements features, runs QA, and delivers tested code. All autonomously, all traceable, all through Claude Code.

Install
npx -y skills add zig999/siegard-code --skill phase-sdd-rules

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 9 stars9 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Exit criteria checkers and worker routing table for the sdd (Specification-Driven Development) phase. Consumed by orchestrator-sdd.md to dispatch spec workers via select_worker.py and evaluate phase transition gates (check_handoff_manifest_approved, check_all_domains_validated, check_error_codes_synced). Includes check_structural_diff.py to determine if spec changes require domain worker dispatch during improve flows. Not user-invocable — orchestrators call scripts directly.

SKILL.md

14.8 KB, as published. Nobody here has run it

phase-sdd-rules

Phase rules skill for the sdd (Specification-Driven Development) phase. Provides exit criteria checkers and worker routing table consumed by orchestrator-sdd.md.

Contract

The orchestrator calls this skill's scripts directly. No inter-skill communication envelope needed. Every script returns a JSON object to stdout and exits 0 on success or 1 on error.


Phase identity

FieldValue
phase_namesdd
order1
requiredtrue
worker_defaultu-spec-writer

Concurrency ceiling (RESOURCE_LIMITS)

The orchestrator MUST enforce these per-batch ceilings before each dispatch in Step 5.1:

effective_modeMax concurrent workers per batch
standard2
targeted1

The ceiling is enforced as a hard cap — the orchestrator may dispatch FEWER than the cap (e.g., if only one task is ready) but MUST NOT exceed it. Violation is a protocol violation per RESOURCE_LIMITS.


Worker routing table

Maps task.type to worker sub-agent. Consumed by the orchestrator dispatcher.

task.typeworker subagent_type
spec-triageu-spec-triage
spec-writeru-spec-writer
spec-revieweru-spec-reviewer
spec-backu-spec-back
spec-frontu-spec-front
spec-validatoru-spec-validator
spec-complianceu-spec-compliance
* (default)u-spec-writer

scripts/select_worker.py

Returns the worker sub-agent name for a given task type.

Usage

python3 .claude/skills/phase-sdd-rules/scripts/select_worker.py \
  --task-type <type>

Output (exit 0)

{"worker": "u-spec-writer", "task_type": "spec-writer", "phase": "sdd"}

Error (exit 1, stderr)

{"status": "error", "reason": "internal_error", "detail": "<message>"}

Exit criteria

All three criteria must be met before the sdd phase can transition. Evaluated by orchestrator-sdd.md at the end of each cycle.

CriterionScriptDescription
handoff_manifest_approvedscripts/check_handoff_manifest_approved.pyhandoff-manifest.yaml exists and Status: approved
all_domains_validatedscripts/check_all_domains_validated.pyNo INVALID status in _validation/ (scoped to the change's domains on /u-improve via --workflow-id)
error_codes_syncedscripts/check_error_codes_synced.pyAll error.code values in in-scope specs are in error-codes.md (scoped to touched domains on /u-improve via --workflow-id)
spec_drift_reviewedscripts/check_spec_drift_reviewed.pyOpt-in (R04d). With sdd_policy.drift_check = warn/required in .orch/config.json, a current /u-drift report must exist for the approved specs. OFF by default — vacuously met

See exit-criteria.json for the machine-readable declaration.

Environment variables

VariableDefaultDescription
ORCH_PROJECT_DIR.Project root
SPECS_DIRspecsSpecs directory, relative to ORCH_PROJECT_DIR

scripts/check_handoff_manifest_approved.py

Criterion: handoff-manifest.yaml exists in SPECS_DIR and contains Status: approved.

python3 .claude/skills/phase-sdd-rules/scripts/check_handoff_manifest_approved.py

Output schema:

{
  "criterion": "handoff_manifest_approved",
  "met": true,
  "evidence": {
    "file": "specs/handoff-manifest.yaml",
    "exists": true,
    "status_found": "approved"
  }
}

scripts/check_all_domains_validated.py

Criterion: no INVALID status in any in-scope .yaml or .md file under SPECS_DIR/_validation/.

python3 .claude/skills/phase-sdd-rules/scripts/check_all_domains_validated.py [--workflow-id <wid>]

Scope (fix F1): with --workflow-id, an /u-improve gates only the domains the change touched (scope.py). Untouched domains inherit their last verdict, so a stale INVALID in an unrelated domain does not block the change — it is reported under out_of_scope_invalid for audit. For u-spec / greenfield / un-derivable scope the check stays global (every domain must be VALID). Without --workflow-id it is global (prior behavior).

Output schema:

{
  "criterion": "all_domains_validated",
  "met": true,
  "evidence": {
    "validation_dir": "specs/_validation",
    "exists": true,
    "total": 5,
    "passing": 5,
    "failing": [],
    "out_of_scope_invalid": [],
    "scoped": false,
    "scope_domains": null
  }
}

met is false if the _validation/ directory does not exist or contains no in-scope files.


scripts/scope.py

Derives the set of domains a change actually touches, so the gate, the handoff scan, and the orchestrator dispatch can restrict work to them (fix F1). Reads triage.json.

python3 .claude/skills/phase-sdd-rules/scripts/scope.py --workflow-id <wid>
# → {"scoped": true,  "domains": ["<affected>", ...]}   /u-improve
# → {"scoped": false, "domains": null}                  u-spec / greenfield / un-derivable

scoped: false (domains null) always means "no scoping — evaluate every domain" (never "empty scope"), keeping greenfield and legacy triage on prior behavior. Also exposes domain_of_validation_file(filename) used by the gate and the handoff scan to map a _validation/ artifact back to its domain.


scripts/check_spec_entry.py

Entry guard for /u-spec (R10). Answers one question — does {SPECS_DIR}/domains/ already hold a spec? — and projects what a full fan-out would cost. Consumed by the /u-spec command in Initial Validation, before any event is appended.

python3 .claude/skills/phase-sdd-rules/scripts/check_spec_entry.py \
  --specs-dir <dir> [--project-dir <dir>]
# exit 0 → {"entry":"greenfield",     "domain_count":0, "domains":[], "projected":{...}}
# exit 3 → {"entry":"non_greenfield", "domain_count":N, "domains":[...], "projected":{...}}

Pairs with scope.py: that script returns scoped: false for the u-spec trigger by design, so orchestrator-sdd dispatches the pipeline for every scanned domain. Correct on an empty repository; on a populated one it turns an addition into a full re-spec that outruns the per-session subagent spawn budget. This guard is what distinguishes the two cases, and it is the only thing that did.

projected.wall_clock_minutes uses WALL_CLOCK_MINUTES_PER_WORKER = 6 — measured across three real workflows (5.6 / 5.9 / 6.9 min per dispatched worker, over differing modes, domain counts and change sizes). Its purpose is to make the price visible before it is paid rather than after.


scripts/check_error_codes_synced.py

Criterion: every error.code / code: Exxx value found in an in-scope spec YAML/MD file is registered in SPECS_DIR/error-codes.md. Trivially met if no error codes are defined in specs.

With --workflow-id, an /u-improve gates only the codes referenced by touched domains (scope.py, fix F1) — an unregistered code living exclusively in untouched domains is reported under out_of_scope_missing and does not block. Files outside domains/<slug>/ are always in scope. Without --workflow-id (or for u-spec / greenfield) the check is global.

python3 .claude/skills/phase-sdd-rules/scripts/check_error_codes_synced.py [--workflow-id <wid>]

Output schema:

{
  "criterion": "error_codes_synced",
  "met": true,
  "evidence": {
    "error_codes_file": "specs/error-codes.md",
    "error_codes_file_exists": true,
    "spec_codes_found": ["E001", "E002"],
    "registered_codes_count": 10,
    "missing_codes": [],
    "out_of_scope_missing": [],
    "files_scanned": ["domain-auth.yaml", "domain-billing.yaml"],
    "scoped": false,
    "scope_domains": null
  }
}

scripts/identify_invalid_domains.py

Utility (repair loop Step R2): lists domains whose validation report in {SPECS_DIR}/_validation/ is INVALID and derives each one's defect origin from the machine-readable {domain}-validation-result.yaml (blocking_issues[].responsible). Feeds the SM's stage-granular repair (S16): origin "back" (all blocking issues belong to u-spec-back) routes a reduced ["spec-back", "spec-validator"] repair pipeline; any other origin (mixed, front, writer, missing or unparseable companion) returns null and keeps the full pipeline — mis-attribution degrades to redundant work, never to under-repair.

Usage

ORCH_PROJECT_DIR=<path> SPECS_DIR=<specs> python3 .claude/skills/phase-sdd-rules/scripts/identify_invalid_domains.py [--workflow-id <wid>]

With --workflow-id, an /u-improve restricts the repair-target set to the touched domains (scope.py, fix F1): a stale INVALID report in an untouched domain goes to out_of_scope_invalid and never enters invalid_domains — the repair loop must not dispatch workers for domains this workflow did not touch. Without --workflow-id (or for u-spec / greenfield) the scan is global.

Output (exit 0)

{
  "invalid_domains": ["chat", "ingestion"],
  "defect_origins": {"chat": "back", "ingestion": null},
  "out_of_scope_invalid": [],
  "scoped": false
}

scripts/check_structural_diff.py

Utility (not an exit criterion): determines whether a spec change requires dispatching a domain worker. Used by orchestrator-sdd.md during improve flows to decide if structural sections were modified (endpoints, schemas, auth_rules, data_models, etc.) and a domain worker must run.

Safe fallback: if improve-scope.json is missing or the spec is not listed in scope, returns domain_worker_required: true to avoid skipping required work.

Usage

ORCH_PROJECT_DIR=<path> python3 .claude/skills/phase-sdd-rules/scripts/check_structural_diff.py \
  --workflow-id <wid> \
  --spec-path <relative-path-to-spec>

Output (exit 0)

{
  "domain_worker_required": true,
  "changed_sections": ["endpoints", "schemas"],
  "structural_sections_found": ["endpoints", "schemas"]
}

Structural sections that trigger domain_worker_required: true: endpoints, schemas, error_codes, component_props, state_contracts, data_models, auth_rules, event_types, api_contracts


scripts/generate_handoff_manifest.py

Utility (not an exit criterion): deterministically produces SPECS_DIR/handoff-manifest.yaml from the validated specs on disk plus triage.json. Closes the gap where no pipeline worker produced the manifest the SDD exit gate requires (the phase previously dead-ended at E08).

Invoked by orchestrator-sdd.md in Step 6 after check_all_domains_validated.py (or check_all_improve_reviewers_completed.py in targeted mode) and check_error_codes_synced.py pass, and before check_handoff_manifest_approved.py. Deterministic (no LLM): sha256 must be exact and the output must round-trip through lib/minimal_yaml.py, which validate.py uses.

Usage

ORCH_PROJECT_DIR=<path> SPECS_DIR=<rel> \
  python3 .claude/skills/phase-sdd-rules/scripts/generate_handoff_manifest.py \
  --workflow-id <wid>

Behavior

  • Enumerates domains via glob domains/*/openapi.yaml; builds domains[], backend_package[] (openapi + back-spec per domain are required by FLOW-037; error-codes / conventions added when present), and — only if front/front.md exists — frontend_artifacts + frontend_package[]. Omitting the frontend blocks lets the Dev orchestrator infer stack=be (back-only handoff).
  • handoff.delivered_by is the const u-spec-orchestrator (required by FLOW-030); handoff.type is derived from triage (new_domain / major_evolution / fast_track). change_summary is emitted only for evolution handoffs.
  • sha256 of every package file is computed at generation time; paths are stored relative to ORCH_PROJECT_DIR so validate.py (--specs-dir = ORCH_PROJECT_DIR) resolves them.

Output (exit 0 when status=ok, exit 1 when status=blocked)

{"status": "ok", "check": "handoff_manifest_generated",
 "manifest_path": "specs/handoff-manifest.yaml", "manifest_id": "HANDOFF-20260601-120000",
 "domains": ["auth"], "stack_implied": "be", "reason": "triage_loaded"}

Fail-closed: no domains, a missing required backend artifact, a handoff_allowed: false in _validation/*-validation-result.yaml, a block_handoff / non_compliant in _validation/*-compliance.yaml, or a triage stack/front mismatch (triage.stack ∈ {fullstack, fe} but no front artifacts on disk — stack_mismatch_front_expected_but_missing, fix P0-1) yields status: blocked without writing the manifest. The orchestrator treats a blocked generation as criterion-not-met (Validation Repair Loop / E08).


scripts/check_spec_drift_reviewed.py

Exit criterion spec_drift_reviewed (R04d) — connects /u-drift to the phase boundary.

/u-drift does what the spec pipeline structurally cannot: it matches approved specs against the code by exact keys and reports what diverged, with evidence per finding. It runs standalone and has to be remembered, which is why a spec once declared three method signatures that do not exist and another cited a grep nobody ran.

python3 .claude/skills/phase-sdd-rules/scripts/check_spec_drift_reviewed.py [--workflow-id <wid>]

Policy in .orch/config.json:

{"sdd_policy": {"drift_check": "off" | "warn" | "required"}}
PolicyMissing / stale reportCritical findings
off (default)criterion vacuously metnot evaluated
warnreported, does not blockreported, does not block
requiredblocks the phase exitblocks the phase exit

Opt-in by design, not as a shortcut. /u-drift costs an LLM code-inventory pass. Making it mandatory on every sdd phase would add an agent and several minutes to every workflow — including the ones whose measured problem already is that the pipeline costs more than the change it specifies. A gate that worsens that gets switched off wholesale; one the operator enables for the handoffs that matter gets used.

"Reviewed" means the report exists and its spec_content_hash still matches the specs on disk. A report generated before the specs changed describes a state that no longer exists — the same staleness class R08 handles for validation verdicts.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.