codegen

package
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package codegen — agent definition generation.

This file ports gen_agents.py to Go. It generates agents/{role}.md files from schema data for roles that have tools defined. Output files are fully generated (no marker-based partial replacement) and overwritten on each run.

GenerateOptions is declared in skills.go and shared with GenerateSkill. ownedPhaseDetails, buildPhaseSlug, buildFuncMap, and unifiedDiff are declared in skills.go and reused here.

Package codegen generates protocol documentation from canonical Go type definitions.

This package ports the Python codegen tooling (gen_skills.py, gen_schema.py, gen_agents.py, context_injection.py) to Go, using text/template for Markdown generation and encoding/xml for schema.xml.

Generated outputs:

  • schema.xml: Protocol schema definition
  • skills/{role}/SKILL.md: Role-level skill headers (marker-bounded)
  • agents/{role}.md: Agent definition files (fully generated)

Package codegen — context injection for role- and phase-specific constraint prompting.

This file ports context_injection.py to Go. It provides static constraint mappings (role → constraint IDs, phase → constraint IDs) and builder functions that construct RoleContext and PhaseContext values for use by downstream codegen generators (schema.xml, SKILL.md, agent definitions).

Key types:

  • RoleContext — populated by GetRoleContext(role)
  • PhaseContext — populated by GetPhaseContext(phase)

Static maps:

  • generalConstraints — applies to ALL roles and ALL phases
  • roleConstraints — hand-authored: RoleId → set of constraint IDs
  • phaseConstraints — hand-authored: PhaseId → set of constraint IDs

Package codegen — shared embed FS for all Go text/template files.

This file declares the single embed.FS that all generator functions in this package share (agents.go, skills.go, etc.). Keeping the embed directive here avoids duplicate //go:embed declarations across multiple files.

Package codegen — global-ID uniqueness enforcement (SLICE-2, URD R5+R7).

ValidateGlobalIds checks that every ID-bearing spec in the codegen registries is globally unique across ALL namespaces:

  • SkillBodySpecs inline section / behavior IDs (skip FragRef-only markers)
  • SharedFragmentSpecs fragment IDs
  • agent IDs (RoleSpecs map keys, e.g. "supervisor", "worker")
  • role-behavior IDs (RoleSpec.Behaviors[*].Id, e.g. "B-arch-elicit")
  • handoff IDs (HandoffSpecs map keys, e.g. "h1" … "h6")
  • command IDs (CommandSpecs map keys, e.g. "cmd-worker")

It also verifies structural validity of SharedFragmentSpecs entries:

  • every FragRef placement marker in SkillBodySpecs resolves
  • every fragment has exactly one payload (Prose XOR Behavior)

Parity check (AMENDMENT-2): set(AllFragmentIds) must equal set(keys(SharedFragmentSpecs)), catching both orphan directions (a declared constant with no spec, or a spec with no constant).

Call site: tools/codegen/main.go — wired after the generators so that go generate hard-fails on the first violation before writing any file.

Package codegen — goldmark-based markdown structure validation and extraction.

This file provides two production functions for validating and querying generated SKILL.md documents via goldmark's AST:

  • ValidateSkillStructure — checks heading hierarchy for common errors
  • ExtractSection — extracts content under a heading by title

These complement the unified skill generation pipeline by providing post-render structural validation.

Package codegen provides utilities for code generation over SKILL.md files.

It ports the marker parsing and replacement logic from gen_skills.py (Python) to Go, enabling the pasture codegen pipeline to operate on SKILL.md files that contain BEGIN/END marker pairs delimiting generated sections.

Package codegen — schema.xml generation.

This file ports gen_schema.py to Go. It generates schema.xml from the canonical Go spec data maps (ConstraintSpecs, PhaseSpecs, etc.) using manual XML building (bytes.Buffer + fmt.Fprintf) to achieve CDATA sections for <code> elements and fine-grained indentation control matching the Python output.

15 of 17 section builders use encoding/xml struct marshalling (SLICE-B). The remaining 2 (buildConstraints, buildProcedureSteps) use manual fmt.Fprintf because they contain CDATA sections that encoding/xml cannot produce.

Public API:

GenerateSchema(w io.Writer) error
GenerateSchemaToFile(path string, opts GenerateOptions) (string, error)

Package codegen — encoding/xml annotated structs for schema.xml sections.

These structs define the canonical XML shapes for all 17 sections of the Pasture Protocol schema. They are used by SLICE-B to replace manual fmt.Fprintf calls with encoding/xml marshalling for 15 of the 17 sections.

ConstraintsSection and ProcedureStepsSection are defined here for type safety and documentation purposes but are NOT used for xml.Marshal: those sections contain CDATA elements that encoding/xml cannot emit, so buildConstraints and buildProcedureSteps remain manual fmt.Fprintf builders.

Package codegen — SKILL.md header generation via text/template.

This file ports gen_skills.py to Go. It provides GenerateSkill and GenerateSubSkill which render the generated section of SKILL.md files using Go text/template with Option("missingkey=error") for StrictUndefined parity.

Templates are embedded via go:embed so the binary is fully self-contained. The template context is built from GetRoleContext() + spec data lookups.

Package codegen provides types and canonical data maps for the Pasture protocol codegen system. These types are internal to the codegen package and are NOT exported outside of internal/codegen.

They mirror the Python types.py spec dataclasses for use by Go template generators (schema.xml generation, SKILL.md generation, agent definitions).

Import paths for referenced types:

  • github.com/dayvidpham/pasture/internal/types — RoleId, Domain
  • github.com/dayvidpham/pasture/pkg/protocol — PhaseId

Canonical data maps for the Pasture protocol codegen system.

These are package-level vars that mirror the Python canonical dicts in aura_protocol/types.py. They are the single source of truth for code generation (schema.xml, SKILL.md, agent definitions).

Integration with Python: test_schema_types_sync.py verifies the Python dicts match schema.xml; Go tests in specs_test.go verify Go maps are structurally complete (every RoleId, every PhaseId has an entry).

Canonical body content for all skill SKILL.md files.

This file consolidates body data for all 7 skills that have hand-authored body sections (rendered inside the BEGIN/END marker region by the unified templates). Each var encodes the body content for one skill directory.

SkillBodySpecs maps skill directory names to their body content. Keys are directory names (not types.RoleId) because sub-skills like "supervisor-plan-tasks" have no RoleId equivalent.

Body content for the architect-handoff skill SKILL.md. Ported from aura-plugins/skills/architect-handoff/SKILL.md.

Body content for the architect-propose-plan skill SKILL.md. Ported from aura-plugins/skills/architect-propose-plan/SKILL.md.

Body content for the architect-ratify skill SKILL.md. Ported from aura-plugins/skills/architect-ratify/SKILL.md.

Body content for the architect-request-review skill SKILL.md. Ported from aura-plugins/skills/architect-request-review/SKILL.md.

Body content for the epoch role SKILL.md. Ported from aura-plugins/skills/epoch/SKILL.md.

Body content for the explore skill SKILL.md. Ported from aura-plugins/skills/explore/SKILL.md.

Body content for the impl-slice command SKILL.md. Ported from aura-plugins/skills/impl-slice/SKILL.md.

Body content for the research skill SKILL.md. Ported from aura-plugins/skills/research/SKILL.md.

Body content for the reviewer-comment skill SKILL.md. Ported from aura-plugins/skills/reviewer-comment/SKILL.md.

Body content for the reviewer-review-code skill SKILL.md. Ported from aura-plugins/skills/reviewer-review-code/SKILL.md.

Body content for the reviewer-review-plan skill SKILL.md. Ported from aura-plugins/skills/reviewer-review-plan/SKILL.md.

Body content for the reviewer-vote skill SKILL.md. Ported from aura-plugins/skills/reviewer-vote/SKILL.md.

Body content for the status skill SKILL.md. Ported from aura-plugins/skills/status/SKILL.md.

Body content for the supervisor-commit skill SKILL.md. Ported from aura-plugins/skills/supervisor-commit/SKILL.md.

Body content for the supervisor-track-progress skill SKILL.md. Ported from aura-plugins/skills/supervisor-track-progress/SKILL.md.

Body content for the swarm command SKILL.md. Ported from aura-plugins/skills/swarm/SKILL.md.

Body content for the user-elicit skill SKILL.md. Ported from aura-plugins/skills/user-elicit/SKILL.md.

Body content for the user-request skill SKILL.md. Ported from aura-plugins/skills/user-request/SKILL.md.

Body content for the user-uat command SKILL.md. Ported from aura-plugins/skills/user-uat/SKILL.md.

Body content for the worker-blocked skill SKILL.md. Ported from aura-plugins/skills/worker-blocked/SKILL.md.

Body content for the worker-complete skill SKILL.md. Ported from aura-plugins/skills/worker-complete/SKILL.md.

Body content for the worker-implement skill SKILL.md. Ported from aura-plugins/skills/worker-implement/SKILL.md.

Canonical SharedFragment registry and helper constructors.

This file declares the SharedFragmentSpecs map, fragRef/behaviorRef marker constructors, and FragmentToOwnerRefs, which inverts the consumer-keyed SkillBodySpecs to produce a map from FragmentId to sorted owner skill-dir keys.

Mirror: ConstraintToRoleRefs() at context.go inverts the consumer-keyed roleConstraints map; FragmentToOwnerRefs mirrors that pattern exactly, operating over SkillBodySpecs instead.

Package codegen — 3-layer schema.xml validator.

This file provides the full implementation of the 3-layer schema.xml validator ported from scripts/validate_schema.py. It parses an XML document into a generic XMLNode tree and runs three validation passes:

  1. Structural (buildIndex) — required attributes, integer attrs, duplicate IDs.
  2. Referential (checkRefs) — all cross-references resolve to known IDs.
  3. Semantic (checkSemantics) — logical protocol-level rules (sequential phase numbers, domain consistency, label uniqueness, etc.).

Public API:

ValidateSchema(r io.Reader) ([]ValidationError, error)
ValidateTree(root *XMLNode) []ValidationError

Index

Constants

View Source
const GeneratedBegin = "<!-- BEGIN GENERATED FROM pasture schema -->"

GeneratedBegin is the opening marker that delimits the generated section.

View Source
const GeneratedEnd = "<!-- END GENERATED FROM pasture schema -->"

GeneratedEnd is the closing marker that delimits the generated section.

Variables

AllFragmentIds lists every declared FragmentId constant. It is maintained in sync with the constant declarations below and validated by ValidateGlobalIds (parity check: AllFragmentIds ↔ SharedFragmentSpecs keys). Mirrors AllRoleIds in internal/types/enums.go.

View Source
var ChecklistSpecs = map[string]Checklist{
	"worker-completion": {
		RoleRef: types.RoleWorker,
		Gate:    "completion",
		Items: []ChecklistItem{
			{Id: "CL-worker-no-todos", Text: "No TODO placeholders in CLI/API actions", Required: true},
			{Id: "CL-worker-real-deps", Text: "Real dependencies wired (not mocks in production code)", Required: true},
			{Id: "CL-worker-test-import", Text: "Tests import production code (not test-only export)", Required: true},
			{Id: "CL-worker-no-dual-export", Text: "No dual-export anti-pattern (one code path for tests and production)", Required: true},
			{Id: "CL-worker-quality-gates", Text: "Quality gates pass (typecheck + tests)", Required: true},
			{Id: "CL-worker-production-path", Text: "Production code path verified end-to-end via code inspection", Required: true},
		},
	},
	"worker-slice-closure": {
		RoleRef: types.RoleWorker,
		Gate:    "slice-closure",
		Items: []ChecklistItem{
			{Id: "CL-worker-notified-supervisor", Text: "Supervisor notified via bd comments add (not bd close)", Required: true},
			{Id: "CL-worker-completion-done", Text: "All completion-gate items passed", Required: true},
			{Id: "CL-worker-close-on-review-wave", Text: "Can only close on a review wave, not a worker wave", Required: true},
			{Id: "CL-worker-review-eligible", Text: "Eligible to close only after review by independent agents with no BLOCKERS or IMPORTANT findings", Required: true},
		},
	},
	"supervisor-review-ready": {
		RoleRef: types.RoleSupervisor,
		Gate:    "review-ready",
		Items: []ChecklistItem{
			{Id: "CL-sup-all-slices-notified", Text: "All workers have notified completion via bd comments add", Required: true},
			{Id: "CL-sup-reviewers-assigned", Text: "Ephemeral reviewers spawned for all slices", Required: true},
			{Id: "CL-sup-severity-groups-created", Text: "Severity groups (BLOCKER/IMPORTANT/MINOR) eagerly created per slice", Required: true},
		},
	},
	"supervisor-landing": {
		RoleRef: types.RoleSupervisor,
		Gate:    "landing",
		Items: []ChecklistItem{
			{Id: "CL-sup-all-accept", Text: "Fix-free clean re-review: 0 BLOCKER + 0 IMPORTANT + 0 MINOR from all 3 reviewers", Required: true},
			{Id: "CL-sup-followup-created", Text: "FOLLOWUP epic created at UAT only if user-DEFER'd items exist (never from review severities)", Required: true},
			{Id: "CL-sup-agent-commit", Text: "git agent-commit used (not git commit -m)", Required: true},
			{Id: "CL-sup-tasks-closed", Text: "All upstream tasks closed or dependency-resolved", Required: true},
			{Id: "CL-sup-close-on-review-wave", Text: "Can only close on a review wave, not a worker wave", Required: true},
			{Id: "CL-sup-review-eligible", Text: "Eligible to close only after review by independent agents with 0 BLOCKER + 0 IMPORTANT + 0 MINOR findings", Required: true},
		},
	},
}

ChecklistSpecs maps "{role}-{gate}" keys to completion checklists. Mirrors Python CHECKLIST_SPECS dict.

View Source
var CommandSpecs = map[string]CommandSpec{
	"cmd-epoch": {
		Id:          "cmd-epoch",
		Name:        "pasture:epoch",
		Description: "Master orchestrator for full 12-phase workflow",
		RoleRef:     types.RoleEpoch,
		Phases: []protocol.PhaseId{
			protocol.PhaseRequest, protocol.PhaseElicit, protocol.PhasePropose,
			protocol.PhaseReview, protocol.PhasePlanReview, protocol.PhaseRatify,
			protocol.PhaseHandoff, protocol.PhaseImplPlan, protocol.PhaseWorkerSlices,
			protocol.PhaseCodeReview, protocol.PhaseImplUAT, protocol.PhaseLanding,
		},
		File: "skills/epoch/SKILL.md",
	},
	"cmd-status": {
		Id:          "cmd-status",
		Name:        "pasture:status",
		Description: "Project status and monitoring via Beads queries",
		Title:       "Pasture Status",
		File:        "skills/status/SKILL.md",
	},
	"cmd-user-request": {
		Id:            "cmd-user-request",
		Name:          "pasture:user:request",
		Description:   "Capture user feature request verbatim (Phase 1)",
		Title:         "User Request (Phase 1)",
		RoleRef:       types.RoleArchitect,
		Phases:        []protocol.PhaseId{protocol.PhaseRequest},
		File:          "skills/user-request/SKILL.md",
		CreatesLabels: []string{"L-p1s1_1"},
	},
	"cmd-user-elicit": {
		Id:            "cmd-user-elicit",
		Name:          "pasture:user:elicit",
		Description:   "User Requirements Elicitation survey (Phase 2)",
		Title:         "User Requirements Elicitation (Phase 2)",
		RoleRef:       types.RoleArchitect,
		Phases:        []protocol.PhaseId{protocol.PhaseElicit},
		File:          "skills/user-elicit/SKILL.md",
		CreatesLabels: []string{"L-p2s2_1", "L-p2s2_2", "L-urd"},
	},
	"cmd-user-uat": {
		Id:            "cmd-user-uat",
		Name:          "pasture:user:uat",
		Description:   "User Acceptance Testing with demonstrative examples",
		Title:         "User Acceptance Test (UAT)",
		Phases:        []protocol.PhaseId{protocol.PhasePlanReview, protocol.PhaseImplUAT},
		File:          "skills/user-uat/SKILL.md",
		CreatesLabels: []string{"L-p5s5", "L-p11s11"},
	},
	"cmd-architect": {
		Id:          "cmd-architect",
		Name:        "pasture:architect",
		Description: "Specification writer and implementation designer",
		RoleRef:     types.RoleArchitect,
		Phases: []protocol.PhaseId{
			protocol.PhaseRequest, protocol.PhaseElicit, protocol.PhasePropose,
			protocol.PhaseReview, protocol.PhasePlanReview, protocol.PhaseRatify,
			protocol.PhaseHandoff,
		},
		File: "skills/architect/SKILL.md",
	},
	"cmd-arch-propose": {
		Id:            "cmd-arch-propose",
		Name:          "pasture:architect:propose-plan",
		Description:   "Create PROPOSAL-N task with full technical plan",
		Title:         "Architect: Propose Plan",
		RoleRef:       types.RoleArchitect,
		Phases:        []protocol.PhaseId{protocol.PhasePropose},
		File:          "skills/architect-propose-plan/SKILL.md",
		CreatesLabels: []string{"L-p3s3"},
	},
	"cmd-arch-review": {
		Id:            "cmd-arch-review",
		Name:          "pasture:architect:request-review",
		Description:   "Spawn 3 axis-specific reviewers (A/B/C)",
		Title:         "Architect: Request Review",
		RoleRef:       types.RoleArchitect,
		Phases:        []protocol.PhaseId{protocol.PhaseReview},
		File:          "skills/architect-request-review/SKILL.md",
		CreatesLabels: []string{"L-p4s4"},
	},
	"cmd-arch-ratify": {
		Id:            "cmd-arch-ratify",
		Name:          "pasture:architect:ratify",
		Description:   "Ratify proposal, mark old proposals pasture:superseded",
		Title:         "Architect: Ratify Plan",
		RoleRef:       types.RoleArchitect,
		Phases:        []protocol.PhaseId{protocol.PhaseRatify},
		File:          "skills/architect-ratify/SKILL.md",
		CreatesLabels: []string{"L-p6s6", "L-superseded"},
	},
	"cmd-arch-handoff": {
		Id:            "cmd-arch-handoff",
		Name:          "pasture:architect:handoff",
		Description:   "Create handoff document and transfer to supervisor",
		Title:         "Architect: Handoff to Supervisor",
		RoleRef:       types.RoleArchitect,
		Phases:        []protocol.PhaseId{protocol.PhaseHandoff},
		File:          "skills/architect-handoff/SKILL.md",
		CreatesLabels: []string{"L-p7s7"},
	},
	"cmd-supervisor": {
		Id:          "cmd-supervisor",
		Name:        "pasture:supervisor",
		Description: "Task coordinator, spawns workers, manages parallel execution",
		RoleRef:     types.RoleSupervisor,
		Phases: []protocol.PhaseId{
			protocol.PhaseHandoff, protocol.PhaseImplPlan, protocol.PhaseWorkerSlices,
			protocol.PhaseCodeReview, protocol.PhaseImplUAT, protocol.PhaseLanding,
		},
		File: "skills/supervisor/SKILL.md",
	},
	"cmd-sup-plan": {
		Id:            "cmd-sup-plan",
		Name:          "pasture:supervisor:plan-tasks",
		Description:   "Decompose ratified plan into vertical slices (SLICE-N)",
		Title:         "Supervisor Plan Tasks",
		RoleRef:       types.RoleSupervisor,
		Phases:        []protocol.PhaseId{protocol.PhaseImplPlan},
		File:          "skills/supervisor-plan-tasks/SKILL.md",
		CreatesLabels: []string{"L-p8s8", "L-p9s9"},
	},
	"cmd-sup-spawn": {
		Id:            "cmd-sup-spawn",
		Name:          "pasture:supervisor:spawn-worker",
		Description:   "Launch a worker agent for an assigned slice",
		Title:         "Supervisor Spawn Worker",
		RoleRef:       types.RoleSupervisor,
		Phases:        []protocol.PhaseId{protocol.PhaseWorkerSlices},
		File:          "skills/supervisor-spawn-worker/SKILL.md",
		CreatesLabels: []string{"L-p9s9"},
	},
	"cmd-sup-track": {
		Id:          "cmd-sup-track",
		Name:        "pasture:supervisor:track-progress",
		Description: "Monitor worker status via Beads",
		Title:       "Supervisor: Track Progress",
		RoleRef:     types.RoleSupervisor,
		Phases:      []protocol.PhaseId{protocol.PhaseWorkerSlices, protocol.PhaseCodeReview},
		File:        "skills/supervisor-track-progress/SKILL.md",
	},
	"cmd-sup-commit": {
		Id:            "cmd-sup-commit",
		Name:          "pasture:supervisor:commit",
		Description:   "Atomic commit per completed layer/slice",
		Title:         "Supervisor: Commit",
		RoleRef:       types.RoleSupervisor,
		Phases:        []protocol.PhaseId{protocol.PhaseLanding},
		File:          "skills/supervisor-commit/SKILL.md",
		CreatesLabels: []string{"L-p12s12"},
	},
	"cmd-worker": {
		Id:          "cmd-worker",
		Name:        "pasture:worker",
		Description: "Vertical slice implementer (full production code path)",
		RoleRef:     types.RoleWorker,
		Phases:      []protocol.PhaseId{protocol.PhaseWorkerSlices},
		File:        "skills/worker/SKILL.md",
	},
	"cmd-work-impl": {
		Id:            "cmd-work-impl",
		Name:          "pasture:worker:implement",
		Description:   "Implement assigned vertical slice following TDD layers",
		Title:         "Worker: Implement Vertical Slice",
		RoleRef:       types.RoleWorker,
		Phases:        []protocol.PhaseId{protocol.PhaseWorkerSlices},
		File:          "skills/worker-implement/SKILL.md",
		CreatesLabels: []string{"L-p9s9"},
	},
	"cmd-work-complete": {
		Id:          "cmd-work-complete",
		Name:        "pasture:worker:complete",
		Description: "Signal slice completion after quality gates pass",
		Title:       "Worker: Signal Completion",
		RoleRef:     types.RoleWorker,
		Phases:      []protocol.PhaseId{protocol.PhaseWorkerSlices},
		File:        "skills/worker-complete/SKILL.md",
	},
	"cmd-work-blocked": {
		Id:          "cmd-work-blocked",
		Name:        "pasture:worker:blocked",
		Description: "Report a blocker to supervisor via Beads",
		Title:       "Worker: Handle Blockers",
		RoleRef:     types.RoleWorker,
		Phases:      []protocol.PhaseId{protocol.PhaseWorkerSlices},
		File:        "skills/worker-blocked/SKILL.md",
	},
	"cmd-reviewer": {
		Id:          "cmd-reviewer",
		Name:        "pasture:reviewer",
		Description: "End-user alignment reviewer for plans and code",
		RoleRef:     types.RoleReviewer,
		Phases:      []protocol.PhaseId{protocol.PhaseReview, protocol.PhaseCodeReview},
		File:        "skills/reviewer/SKILL.md",
	},
	"cmd-rev-plan": {
		Id:            "cmd-rev-plan",
		Name:          "pasture:reviewer:review-plan",
		Description:   "Evaluate proposal against one axis (binary ACCEPT/REVISE)",
		Title:         "Review Plan",
		RoleRef:       types.RoleReviewer,
		Phases:        []protocol.PhaseId{protocol.PhaseReview},
		File:          "skills/reviewer-review-plan/SKILL.md",
		CreatesLabels: []string{"L-p4s4"},
	},
	"cmd-rev-code": {
		Id:            "cmd-rev-code",
		Name:          "pasture:reviewer:review-code",
		Description:   "Review implementation slices with EAGER severity tree",
		Title:         "Review Code Implementation",
		RoleRef:       types.RoleReviewer,
		Phases:        []protocol.PhaseId{protocol.PhaseCodeReview},
		File:          "skills/reviewer-review-code/SKILL.md",
		CreatesLabels: []string{"L-p10s10", "L-sev-blocker", "L-sev-import", "L-sev-minor"},
	},
	"cmd-rev-comment": {
		Id:          "cmd-rev-comment",
		Name:        "pasture:reviewer:comment",
		Description: "Leave structured review comment via Beads",
		Title:       "Leave Structured Review Comment",
		RoleRef:     types.RoleReviewer,
		Phases:      []protocol.PhaseId{protocol.PhaseReview, protocol.PhaseCodeReview},
		File:        "skills/reviewer-comment/SKILL.md",
	},
	"cmd-rev-vote": {
		Id:          "cmd-rev-vote",
		Name:        "pasture:reviewer:vote",
		Description: "Cast ACCEPT or REVISE vote (binary only)",
		Title:       "Cast Review Vote",
		RoleRef:     types.RoleReviewer,
		Phases:      []protocol.PhaseId{protocol.PhaseReview, protocol.PhaseCodeReview},
		File:        "skills/reviewer-vote/SKILL.md",
	},
	"cmd-impl-slice": {
		Id:            "cmd-impl-slice",
		Name:          "pasture:impl:slice",
		Description:   "Vertical slice assignment and tracking",
		Title:         "Implementation Slice (Phase 9)",
		RoleRef:       types.RoleSupervisor,
		Phases:        []protocol.PhaseId{protocol.PhaseWorkerSlices},
		File:          "skills/impl-slice/SKILL.md",
		CreatesLabels: []string{"L-p9s9"},
	},
	"cmd-impl-review": {
		Id:            "cmd-impl-review",
		Name:          "pasture:impl:review",
		Description:   "Code review coordination across all slices (Phase 10)",
		Title:         "Implementation Code Review (Phase 10)",
		RoleRef:       types.RoleSupervisor,
		Phases:        []protocol.PhaseId{protocol.PhaseCodeReview},
		File:          "skills/impl-review/SKILL.md",
		CreatesLabels: []string{"L-p10s10", "L-sev-blocker", "L-sev-import", "L-sev-minor"},
	},
	"cmd-explore": {
		Id:            "cmd-explore",
		Name:          "pasture:explore",
		Description:   "Codebase exploration — find integration points, existing patterns, and related code",
		Title:         "Explore",
		Phases:        []protocol.PhaseId{protocol.PhaseRequest, protocol.PhaseImplPlan},
		File:          "skills/explore/SKILL.md",
		CreatesLabels: []string{"L-p1s1_3"},
	},
	"cmd-research": {
		Id:            "cmd-research",
		Name:          "pasture:research",
		Description:   "Domain research — find standards, prior art, and competing approaches",
		Title:         "Research",
		Phases:        []protocol.PhaseId{protocol.PhaseRequest},
		File:          "skills/research/SKILL.md",
		CreatesLabels: []string{"L-p1s1_2"},
	},
	"cmd-swarm": {
		Id:          "cmd-swarm",
		Name:        "pasture:swarm",
		Description: "Launch worktree-based or intree agent workflows using aura-swarm",
		Title:       "Swarm — Unified Agent Orchestration",
		File:        "skills/swarm/SKILL.md",
	},
}

CommandSpecs maps command IDs to their full specifications. Mirrors Python COMMAND_SPECS dict.

View Source
var ConstraintSpecs = map[string]ConstraintSpec{
	"C-audit-never-delete": {
		Id:        "C-audit-never-delete",
		Given:     "any task or label",
		When:      "modifying",
		Then:      "add labels and comments only",
		ShouldNot: "delete or close tasks prematurely, remove labels",
	},
	"C-audit-dep-chain": {
		Id:        "C-audit-dep-chain",
		Given:     "any phase transition",
		When:      "creating new task",
		Then:      "chain dependency: bd dep add parent --blocked-by child",
		ShouldNot: "skip dependency chaining or invert direction",
		Command:   "bd dep add <parent> --blocked-by <child>",
		Examples: []Example{
			{
				Id:    "C-audit-dep-chain-full",
				Lang:  "bash",
				Label: "correct",
				Code: "# Full dependency chain: work flows bottom-up, closure flows top-down\n" +
					"bd dep add request-id --blocked-by ure-id\n" +
					"bd dep add ure-id --blocked-by proposal-id\n" +
					"bd dep add proposal-id --blocked-by impl-plan-id\n" +
					"bd dep add impl-plan-id --blocked-by slice-1-id\n" +
					"bd dep add slice-1-id --blocked-by leaf-task-a-id",
			},
		},
	},
	"C-review-consensus": {
		Id:        "C-review-consensus",
		Given:     "review cycle (p4 or p10)",
		When:      "evaluating",
		Then:      "all 3 reviewers must ACCEPT before proceeding",
		ShouldNot: "proceed with any REVISE vote outstanding",
	},
	"C-review-binary": {
		Id:        "C-review-binary",
		Given:     "a reviewer",
		When:      "voting",
		Then:      "use ACCEPT or REVISE only",
		ShouldNot: "use APPROVE, APPROVE_WITH_COMMENTS, REQUEST_CHANGES, or REJECT",
	},
	"C-severity-eager": {
		Id:        "C-severity-eager",
		Given:     "code review round (p10 only)",
		When:      "starting review",
		Then:      "ALWAYS create 3 severity group tasks (BLOCKER, IMPORTANT, MINOR) immediately",
		ShouldNot: "lazily create severity groups only when findings exist",
		Examples: []Example{
			{
				Id:    "C-severity-eager-create",
				Lang:  "bash",
				Label: "correct",
				Code: "# Create all 3 severity groups immediately (even if empty)\n" +
					"bd create --title \"SLICE-1-REVIEW-A-1 BLOCKER\" \\\n" +
					"  --labels \"pasture:severity:blocker,pasture:p10-impl:s10-review\"\n" +
					"bd create --title \"SLICE-1-REVIEW-A-1 IMPORTANT\" \\\n" +
					"  --labels \"pasture:severity:important,pasture:p10-impl:s10-review\"\n" +
					"bd create --title \"SLICE-1-REVIEW-A-1 MINOR\" \\\n" +
					"  --labels \"pasture:severity:minor,pasture:p10-impl:s10-review\"\n\n" +
					"# Close empty groups immediately\n" +
					"bd close <empty-important-id>\n" +
					"bd close <empty-minor-id>",
			},
			{
				Id:    "C-severity-eager-anti",
				Lang:  "bash",
				Label: "anti-pattern",
				Code: "# WRONG: only creating groups when findings exist\n" +
					"# This skips empty groups and breaks the audit trail\n" +
					"if blocker_findings:\n" +
					"    bd create --title \"BLOCKER\" ...",
			},
		},
	},
	"C-severity-not-plan": {
		Id:        "C-severity-not-plan",
		Given:     "plan review (p4)",
		When:      "reviewing",
		Then:      "use binary ACCEPT/REVISE only",
		ShouldNot: "create severity tree for plan reviews",
	},
	"C-blocker-dual-parent": {
		Id:        "C-blocker-dual-parent",
		Given:     "a BLOCKER finding in code review",
		When:      "recording",
		Then:      "add as child of BOTH the severity group AND the slice it blocks",
		ShouldNot: "add to severity group only",
	},
	"C-followup-timing": {
		Id:    "C-followup-timing",
		Given: "UAT (Phase 5 or Phase 11) produces one or more user-DEFER'd items",
		When:  "creating the FOLLOWUP epic",
		Then: "create the FOLLOWUP epic at UAT when user-DEFER'd items exist; " +
			"the FOLLOWUP epic is fed ONLY by user-DEFER'd UAT items",
		ShouldNot: "trigger FOLLOWUP from any review severity (BLOCKER/IMPORTANT/MINOR) — " +
			"all review findings must reach 0 before wave close, no severity is deferrable to FOLLOWUP",
	},
	"C-vertical-slices": {
		Id:        "C-vertical-slices",
		Given:     "implementation decomposition",
		When:      "assigning work",
		Then:      "each production code path owned by exactly ONE worker (full vertical)",
		ShouldNot: "assign horizontal layers or same path to multiple workers",
	},
	"C-supervisor-no-impl": {
		Id:        "C-supervisor-no-impl",
		Given:     "supervisor role",
		When:      "implementation phase",
		Then:      "spawn workers for all code changes",
		ShouldNot: "implement code directly",
	},
	"C-supervisor-explore-ephemeral": {
		Id:    "C-supervisor-explore-ephemeral",
		Given: "supervisor needs codebase exploration",
		When:  "starting Phase 8 (IMPL_PLAN)",
		Then: "spawn ephemeral Explore subagents via Task tool for scoped codebase queries; " +
			"each subagent is short-lived and returns findings; no standing team overhead",
		ShouldNot: "explore the codebase directly as supervisor; " +
			"maintain a standing explore team",
	},
	"C-clean-review-exit": {
		Id:    "C-clean-review-exit",
		Given: "per-slice code review",
		When:  "evaluating review results",
		Then: "iterate review -> fix -> re-review up to the chosen review-effort budget until a fix-free clean round " +
			"confirms 0 BLOCKER + 0 IMPORTANT + 0 MINOR within budget; " +
			"a clean round is one where the re-review applies no fixes and finds nothing across all three severities; " +
			"on budget exhaustion without a clean round, SURFACE the outstanding findings to the user at a gate for a decision",
		ShouldNot: "close a wave on a fix-applying round; " +
			"proceed with ANY finding (BLOCKER, IMPORTANT, or MINOR) outstanding without surfacing it to the user; " +
			"hardcode the budget; proceed past the chosen budget without surfacing to the user; " +
			"batch review across multiple slices",
	},
	"C-review-effort-budget": {
		Id:    "C-review-effort-budget",
		Given: "the start of Phase 8 (IMPL_PLAN), like the Phase-1 research-depth gate",
		When:  "deciding how much review-and-fix effort to spend per slice",
		Then: "request a configurable review-effort budget from the user — defaults: " +
			"(1) three rounds, (2) one round, (3) zero rounds, (4) unlimited, (5) custom; " +
			"the review->fix->re-review loop iterates up to the chosen budget; " +
			"on budget exhaustion WITHOUT a clean 0/0/0 round, surface the outstanding findings to the user for a decision",
		ShouldNot: "hardcode the review-cycle budget (e.g. an unconditional fixed cap baked into the prose instead of asked); " +
			"proceed past the chosen budget without surfacing outstanding findings to the user; " +
			"loop forever when a finite budget was chosen",
	},
	"C-autonomous-progression": {
		Id:    "C-autonomous-progression",
		Given: "supervisor orchestrating phases",
		When:  "deciding whether to proceed",
		Then: "5 user-gated phases only: (1) research depth decision, (2) URE survey, " +
			"(3) Plan UAT, (4) Phase 8 implementation-effort / review-effort budget request, " +
			"(5) Impl UAT; all other phase transitions are auto-ratified " +
			"by the supervisor; after Plan UAT ACCEPT, proceed directly to ratification " +
			"without user gate",
		ShouldNot: "add additional user gates beyond the 5 defined; " +
			"require user approval for ratification after UAT ACCEPT",
	},
	"C-integration-points": {
		Id:    "C-integration-points",
		Given: "multiple vertical slices share types, interfaces, or data flows",
		When:  "decomposing IMPL_PLAN in Phase 8",
		Then: "identify horizontal Layer Integration Points and document them in IMPL_PLAN; " +
			"each integration point specifies: owning slice, consuming slices, shared contract, merge timing; " +
			"include integration points in slice descriptions so workers know what to export and import",
		ShouldNot: "leave cross-slice dependencies implicit; " +
			"assume workers will discover contracts on their own",
	},
	"C-slice-review-before-close": {
		Id:    "C-slice-review-before-close",
		Given: "workers complete their implementation slices",
		When:  "slice implementation is done",
		Then: "workers notify supervisor with bd comments add (not bd close); " +
			"slices must be reviewed at least once by reviewers before closure; " +
			"only the supervisor closes slices, after review passes",
		ShouldNot: "close slices immediately upon worker completion; " +
			"allow workers to close their own slices",
	},
	"C-slice-leaf-tasks": {
		Id:    "C-slice-leaf-tasks",
		Given: "vertical slice created",
		When:  "decomposing slice into implementation units",
		Then: "create one or more Beads leaf tasks per slice, named after the real work units they represent, " +
			"with bd dep add slice-id --blocked-by leaf-task-id; a slice may have ANY number of leaves " +
			"(the L1: types / L2: tests / L3: impl triple is ONE illustrative shape, not a required count)",
		ShouldNot: "create slices without leaf tasks — " +
			"a slice with no children is undecomposed and cannot be tracked; " +
			"force every slice into a fixed L1/L2/L3 triple when the real work units differ",
		Command: "bd dep add <slice-id> --blocked-by <leaf-task-id>",
	},
	"C-handoff-skill-invocation": {
		Id:    "C-handoff-skill-invocation",
		Given: "an agent is launched for a new phase (especially p7 to p8 handoff)",
		When:  "composing the launch prompt",
		Then: "prompt MUST start with Skill(/pasture:{role}) invocation directive " +
			"so the agent loads its role instructions",
		ShouldNot: "launch agents without skill invocation — " +
			"they skip role-critical procedures like ephemeral exploration and leaf task creation",
	},
	"C-dep-direction": {
		Id:        "C-dep-direction",
		Given:     "adding a Beads dependency",
		When:      "determining direction",
		Then:      "parent blocked-by child: bd dep add stays-open --blocked-by must-finish-first",
		ShouldNot: "invert (child blocked-by parent)",
		Command:   "bd dep add <stays-open> --blocked-by <must-finish-first>",
		Examples: []Example{
			{
				Id:              "C-dep-direction-correct",
				Lang:            "bash",
				Label:           "correct",
				Code:            "bd dep add request-id --blocked-by ure-id",
				AlsoIllustrates: "C-audit-dep-chain",
			},
			{
				Id:    "C-dep-direction-anti",
				Lang:  "bash",
				Label: "anti-pattern",
				Code:  "bd dep add ure-id --blocked-by request-id",
			},
		},
	},
	"C-frontmatter-refs": {
		Id:        "C-frontmatter-refs",
		Given:     "cross-task references (URD, request, etc.)",
		When:      "linking tasks",
		Then:      "use description frontmatter references: block",
		ShouldNot: "use bd dep relate (buggy) or blocking dependencies for reference docs",
	},
	"C-agent-commit": {
		Id:        "C-agent-commit",
		Given:     "code is ready to commit",
		When:      "committing",
		Then:      "use git agent-commit -m ...",
		ShouldNot: "use git commit -m ...",
		Command:   "git agent-commit -m ...",
		Examples: []Example{
			{
				Id:    "C-agent-commit-correct",
				Lang:  "bash",
				Label: "correct",
				Code:  `git agent-commit -m "feat: add login"`,
			},
			{
				Id:    "C-agent-commit-anti",
				Lang:  "bash",
				Label: "anti-pattern",
				Code:  `git commit -m "feat: add login"`,
			},
		},
	},
	"C-proposal-naming": {
		Id:        "C-proposal-naming",
		Given:     "a new or revised proposal",
		When:      "creating task",
		Then:      "title PROPOSAL-{N} where N increments; mark old as pasture:superseded",
		ShouldNot: "reuse N or delete old proposals",
	},
	"C-review-naming": {
		Id:        "C-review-naming",
		Given:     "a review task",
		When:      "creating",
		Then:      "title {SCOPE}-REVIEW-{axis}-{round} where axis=A|B|C, round starts at 1",
		ShouldNot: "use numeric reviewer IDs (1/2/3) instead of axis letters",
	},
	"C-ure-verbatim": {
		Id:    "C-ure-verbatim",
		Given: "user interview (Request, URE, or UAT), URD update, or mid-implementation design decision",
		When:  "recording in Beads",
		Then: "capture full question text, ALL option descriptions, AND user's verbatim response, " +
			"INCLUDING any code, snippets, or examples shown inside AskUserQuestion option labels, descriptions, " +
			"or definition blocks (the preview/stimulus the user actually saw); " +
			"the URD is the living document of ALL user requests, URE, UAT, and mid-implementation " +
			"design decisions and feedback — update it via bd comments add whenever user intent is captured",
		ShouldNot: "summarize options as (1)/(2)/(3) without option text, paraphrase user responses, " +
			"or omit code/snippets shown inside option previews",
		Examples: []Example{
			{
				Id:    "C-ure-verbatim-correct",
				Lang:  "bash",
				Label: "correct",
				Code: "# Full question, all options with descriptions, verbatim response\n" +
					"bd create --title \"UAT: Plan acceptance for feature-X\" \\\n" +
					"  --description \"## Component: Verbose fields\n" +
					"**Question:** Which verbose fields are useful?\n" +
					"**Options:**\n" +
					"- backupDir (full path): Shows where the backup landed\n" +
					"- session ID: Enables log correlation across events\n" +
					"- repo path + hash: Confirms which git repo was detected\n" +
					"**User response:** backupDir (full path), session ID\n" +
					"**Decision:** ACCEPT\"",
			},
			{
				Id:    "C-ure-verbatim-anti",
				Lang:  "bash",
				Label: "anti-pattern",
				Code: "# WRONG: options summarized as numbers, response paraphrased\n" +
					"bd create --title \"UAT: Plan acceptance\" \\\n" +
					"  --description \"Asked about verbose fields (1-4). User picked 1 and 2. Accepted.\"",
			},
		},
	},
	"C-followup-lifecycle": {
		Id:    "C-followup-lifecycle",
		Given: "follow-up epic created",
		When:  "starting follow-up work",
		Then: "run same protocol phases with FOLLOWUP_* prefix: " +
			"FOLLOWUP_URE → FOLLOWUP_URD → FOLLOWUP_PROPOSAL → FOLLOWUP_IMPL_PLAN → FOLLOWUP_SLICE",
		ShouldNot: "skip the follow-up lifecycle or treat the follow-up epic as a flat task list",
	},
	"C-followup-leaf-adoption": {
		Id:    "C-followup-leaf-adoption",
		Given: "supervisor creates FOLLOWUP_SLICE-N",
		When:  "assigning user-DEFER'd UAT-item leaf tasks to follow-up slices",
		Then: "add leaf task as child of follow-up slice " +
			"(dual-parent: leaf blocks both the DEFER'd-items tracking group AND follow-up slice)",
		ShouldNot: "remove the leaf task from its original DEFER'd-items tracking parent",
	},
	"C-worker-gates": {
		Id:        "C-worker-gates",
		Given:     "worker finishes implementation",
		When:      "signaling completion",
		Then:      "run quality gates (typecheck + tests) AND verify production code path (no TODOs, real deps)",
		ShouldNot: "close with only 'tests pass' as completion gate",
	},
	"C-actionable-errors": {
		Id:    "C-actionable-errors",
		Given: "an error, exception, or user-facing message",
		When:  "creating or raising",
		Then: "make it actionable: describe (1) what went wrong, (2) why it happened, " +
			"(3) where it failed (file location, module, or function), " +
			"(4) when it failed (step, operation, or timestamp), " +
			"(5) what it means for the caller, and (6) how to fix it",
		ShouldNot: "raise generic or opaque error messages (e.g. 'invalid input', 'operation failed') " +
			"that don't guide the user toward resolution",
	},
	"C-validation-cases": {
		Id:    "C-validation-cases",
		Given: "any REQUEST (every request, not only fix-intent ones)",
		When:  "eliciting (URE), acceptance-testing (UAT), or implementing",
		Then: "elicit concrete validation cases for the request — a definition of done plus correct and " +
			"incorrect behaviours (inputs/behaviors that must pass or must fail), " +
			"confirm the case set with the user in UAT, evaluate the implementation against them, " +
			"and store failing real-data cases as test fixtures",
		ShouldNot: "ship without validation cases; " +
			"treat validation cases as applying to fix-intent requests only; " +
			"introduce a request-type axis or enum to gate them (recognize what a request needs semantically instead)",
	},
	"C-interview-skill-invocation": {
		Id:    "C-interview-skill-invocation",
		Given: "a user-interview phase (Phase 2 URE, Phase 5 Plan UAT, or Phase 11 Impl UAT)",
		When:  "conducting the phase",
		Then: "the agent MUST invoke the matching interview skill (Skill(/pasture:user-elicit) for URE, " +
			"Skill(/pasture:user-uat) for UAT) so the verbatim-capture and disposition procedures are loaded",
		ShouldNot: "conduct an interview phase without invoking its skill — " +
			"skipping it loses the verbatim-capture and FIX-NOW/DEFER disposition procedures",
	},
	"C-uat-feedback-disposition": {
		Id:    "C-uat-feedback-disposition",
		Given: "any UAT feedback item (Phase 5 or Phase 11) — flagged by the user OR a deferral proposed by the architect/supervisor",
		When:  "recording each item",
		Then: "assign every item an explicit, user-confirmed disposition of FIX-NOW or DEFER; " +
			"deferrals may be agent-proposed, but ALL deferred items — whoever proposed them — MUST be raised to the user " +
			"at the next user gate (URE, Plan UAT, or Impl UAT) for confirmation; " +
			"FIX-NOW items are resolved in the current wave, DEFER'd items are the SOLE source feeding the FOLLOWUP epic",
		ShouldNot: "leave a feedback item without a confirmed disposition; " +
			"silently defer any item without raising it to the user at the next gate; " +
			"route any review severity (BLOCKER/IMPORTANT/MINOR) into FOLLOWUP — only DEFER'd UAT items feed it",
	},
	"C-interface-first-slices": {
		Id:    "C-interface-first-slices",
		Given: "decomposing a RATIFIED plan into vertical slices (Phase 8 IMPL_PLAN)",
		When:  "ordering the slices",
		Then: "prefer an interface-first FOUNDATION slice that exports all shared identifiers " +
			"(types, constraints, fragments) and lands green BEFORE dependent slices (Strong SHOULD); " +
			"if a linear (non-interface-first) decomposition is chosen instead, justify it explicitly in the IMPL_PLAN",
		ShouldNot: "leave cross-slice contracts implicit; " +
			"choose a linear decomposition without recording the justification in the IMPL_PLAN",
	},
}

ConstraintSpecs maps constraint IDs to their full specifications. Mirrors Python CONSTRAINT_SPECS dict.

View Source
var CoordinationCommands = map[string]CoordinationCommand{
	"cmd-coord-show": {
		Id:       "cmd-coord-show",
		Action:   "Check task details",
		Template: "bd show <task-id>",
		Shared:   true,
	},
	"cmd-coord-status": {
		Id:       "cmd-coord-status",
		Action:   "Update status",
		Template: "bd update <task-id> --status=in_progress",
		Shared:   true,
	},
	"cmd-coord-comment": {
		Id:       "cmd-coord-comment",
		Action:   "Add progress note",
		Template: `bd comments add <task-id> "Progress: ..."`,
		Shared:   true,
	},
	"cmd-coord-list": {
		Id:       "cmd-coord-list",
		Action:   "List in-progress",
		Template: "bd list --pretty --status=in_progress",
		Shared:   true,
	},
	"cmd-coord-blocked": {
		Id:       "cmd-coord-blocked",
		Action:   "List blocked",
		Template: "bd blocked",
		Shared:   true,
	},
	"cmd-coord-assign": {
		Id:       "cmd-coord-assign",
		Action:   "Assign task",
		Template: `bd update <task-id> --assignee "<worker-name>"`,
		RoleRef:  types.RoleSupervisor,
	},
	"cmd-coord-label": {
		Id:       "cmd-coord-label",
		Action:   "Label completed slice",
		Template: "bd label add <slice-id> pasture:p9-impl:slice-complete",
		RoleRef:  types.RoleSupervisor,
	},
	"cmd-coord-dep-add": {
		Id:       "cmd-coord-dep-add",
		Action:   "Chain dependency",
		Template: "bd dep add <parent> --blocked-by <child>",
		RoleRef:  types.RoleSupervisor,
	},
	"cmd-coord-close": {
		Id:       "cmd-coord-close",
		Action:   "Report completion",
		Template: "bd close <task-id>",
		RoleRef:  types.RoleWorker,
	},
	"cmd-coord-worker-notes": {
		Id:       "cmd-coord-worker-notes",
		Action:   "Add completion notes",
		Template: `bd update <task-id> --notes="Implementation complete. Production code verified."`,
		RoleRef:  types.RoleWorker,
	},
}

CoordinationCommands maps command IDs to coordination command specs. Mirrors Python COORDINATION_COMMANDS dict.

View Source
var DefaultOptions = GenerateOptions{Diff: true, Write: true}

DefaultOptions is the default GenerateOptions used when the caller does not need to override any field.

View Source
var FigureSpecs = map[string]FigureSpec{
	"layer-cake": {
		Id:           "layer-cake",
		Title:        "Layer Cake — TDD Parallelism Within Vertical Slices",
		Type:         "ascii-diagram",
		RoleRefs:     []types.RoleId{types.RoleWorker},
		SectionRef:   "workflows",
		WorkflowRefs: []string{"layer-cake"},
		CommandRefs:  []string{"cmd-sup-plan"},
	},
	"ride-the-wave": {
		Id:           "ride-the-wave",
		Title:        "Ride the Wave — Coordinated Phase 8-10 Execution",
		Type:         "ascii-diagram",
		RoleRefs:     []types.RoleId{types.RoleSupervisor},
		SectionRef:   "workflows",
		WorkflowRefs: []string{"ride-the-wave"},
		CommandRefs:  []string{"cmd-sup-spawn"},
	},
	"architect-state-flow": {
		Id:           "architect-state-flow",
		Title:        "Architect State Flow — Sequential Planning Phases 1-7",
		Type:         "ascii-diagram",
		RoleRefs:     []types.RoleId{types.RoleArchitect},
		SectionRef:   "workflows",
		WorkflowRefs: []string{"architect-state-flow"},
	},
}

FigureSpecs maps figure IDs to their full specifications. Mirrors Python FIGURE_SPECS dict. Content is loaded at generation time.

View Source
var HandoffSpecs = map[string]HandoffSpec{
	"h1": {
		Id:           "h1",
		SourceRole:   types.RoleArchitect,
		TargetRole:   types.RoleSupervisor,
		AtPhase:      protocol.PhaseHandoff,
		ContentLevel: "full-provenance",
		RequiredFields: []string{
			"request", "urd", "proposal", "ratified-plan",
			"context", "key-decisions", "open-items", "acceptance-criteria",
		},
	},
	"h2": {
		Id:           "h2",
		SourceRole:   types.RoleSupervisor,
		TargetRole:   types.RoleWorker,
		AtPhase:      protocol.PhaseWorkerSlices,
		ContentLevel: "summary-with-ids",
		RequiredFields: []string{
			"request", "urd", "proposal", "ratified-plan", "impl-plan",
			"slice", "context", "key-decisions", "open-items", "acceptance-criteria",
		},
	},
	"h3": {
		Id:           "h3",
		SourceRole:   types.RoleSupervisor,
		TargetRole:   types.RoleReviewer,
		AtPhase:      protocol.PhaseCodeReview,
		ContentLevel: "summary-with-ids",
		RequiredFields: []string{
			"request", "urd", "proposal", "ratified-plan", "impl-plan",
			"context", "key-decisions", "acceptance-criteria",
		},
	},
	"h4": {
		Id:           "h4",
		SourceRole:   types.RoleWorker,
		TargetRole:   types.RoleReviewer,
		AtPhase:      protocol.PhaseCodeReview,
		ContentLevel: "summary-with-ids",
		RequiredFields: []string{
			"request", "urd", "impl-plan", "slice",
			"context", "key-decisions", "open-items",
		},
	},
	"h5": {
		Id:           "h5",
		SourceRole:   types.RoleReviewer,
		TargetRole:   types.RoleSupervisor,
		AtPhase:      protocol.PhaseCodeReview,
		ContentLevel: "summary-with-ids",
		RequiredFields: []string{
			"request", "urd", "proposal",
			"context", "key-decisions", "open-items", "acceptance-criteria",
		},
	},
	"h6": {
		Id:           "h6",
		SourceRole:   types.RoleSupervisor,
		TargetRole:   types.RoleArchitect,
		AtPhase:      protocol.PhasePropose,
		ContentLevel: "summary-with-ids",
		RequiredFields: []string{
			"request", "urd", "followup-epic", "followup-ure", "followup-urd",
			"context", "key-decisions", "findings-summary", "acceptance-criteria",
		},
	},
}

HandoffSpecs maps handoff IDs to their full specifications. Mirrors Python HANDOFF_SPECS dict.

View Source
var LabelSpecs = map[string]LabelSpec{
	"L-p1s1_1":      {Id: "L-p1s1_1", Value: "pasture:p1-user:s1_1-classify", Special: false, PhaseRef: "p1", SubstepRef: "s1_1"},
	"L-p1s1_2":      {Id: "L-p1s1_2", Value: "pasture:p1-user:s1_2-research", Special: false, PhaseRef: "p1", SubstepRef: "s1_2"},
	"L-p1s1_3":      {Id: "L-p1s1_3", Value: "pasture:p1-user:s1_3-explore", Special: false, PhaseRef: "p1", SubstepRef: "s1_3"},
	"L-p2s2_1":      {Id: "L-p2s2_1", Value: "pasture:p2-user:s2_1-elicit", Special: false, PhaseRef: "p2", SubstepRef: "s2_1"},
	"L-p2s2_2":      {Id: "L-p2s2_2", Value: "pasture:p2-user:s2_2-urd", Special: false, PhaseRef: "p2", SubstepRef: "s2_2"},
	"L-p3s3":        {Id: "L-p3s3", Value: "pasture:p3-plan:s3-propose", Special: false, PhaseRef: "p3", SubstepRef: "s3"},
	"L-p4s4":        {Id: "L-p4s4", Value: "pasture:p4-plan:s4-review", Special: false, PhaseRef: "p4", SubstepRef: "s4"},
	"L-p5s5":        {Id: "L-p5s5", Value: "pasture:p5-user:s5-uat", Special: false, PhaseRef: "p5", SubstepRef: "s5"},
	"L-p6s6":        {Id: "L-p6s6", Value: "pasture:p6-plan:s6-ratify", Special: false, PhaseRef: "p6", SubstepRef: "s6"},
	"L-p7s7":        {Id: "L-p7s7", Value: "pasture:p7-plan:s7-handoff", Special: false, PhaseRef: "p7", SubstepRef: "s7"},
	"L-p8s8":        {Id: "L-p8s8", Value: "pasture:p8-impl:s8-plan", Special: false, PhaseRef: "p8", SubstepRef: "s8"},
	"L-p9s9":        {Id: "L-p9s9", Value: "pasture:p9-impl:s9-slice", Special: false, PhaseRef: "p9", SubstepRef: "s9"},
	"L-p10s10":      {Id: "L-p10s10", Value: "pasture:p10-impl:s10-review", Special: false, PhaseRef: "p10", SubstepRef: "s10"},
	"L-p11s11":      {Id: "L-p11s11", Value: "pasture:p11-user:s11-uat", Special: false, PhaseRef: "p11", SubstepRef: "s11"},
	"L-p12s12":      {Id: "L-p12s12", Value: "pasture:p12-impl:s12-landing", Special: false, PhaseRef: "p12", SubstepRef: "s12"},
	"L-urd":         {Id: "L-urd", Value: "pasture:urd", Special: true, Description: "User Requirements Document"},
	"L-superseded":  {Id: "L-superseded", Value: "pasture:superseded", Special: true, Description: "Superseded proposal or plan"},
	"L-sev-blocker": {Id: "L-sev-blocker", Value: "pasture:severity:blocker", Special: true, SeverityRef: "BLOCKER"},
	"L-sev-import":  {Id: "L-sev-import", Value: "pasture:severity:important", Special: true, SeverityRef: "IMPORTANT"},
	"L-sev-minor":   {Id: "L-sev-minor", Value: "pasture:severity:minor", Special: true, SeverityRef: "MINOR"},
	"L-followup":    {Id: "L-followup", Value: "pasture:epic-followup", Special: true, Description: "Follow-up epic for non-blocking findings"},
}

LabelSpecs maps label IDs to their full specifications. Mirrors Python LABEL_SPECS dict.

View Source
var PhaseSpecs = map[protocol.PhaseId]PhaseSpec{
	protocol.PhaseRequest: {
		Id:         protocol.PhaseRequest,
		Name:       "Request",
		Number:     1,
		Domain:     types.DomainUser,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleArchitect},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhaseElicit,
				Condition: "classification confirmed, research and explore complete",
			},
		},
	},
	protocol.PhaseElicit: {
		Id:         protocol.PhaseElicit,
		Name:       "Elicit",
		Number:     2,
		Domain:     types.DomainUser,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleArchitect},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhasePropose,
				Condition: "URD created with structured requirements",
			},
		},
	},
	protocol.PhasePropose: {
		Id:         protocol.PhasePropose,
		Name:       "Propose",
		Number:     3,
		Domain:     types.DomainPlan,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleArchitect},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhaseReview,
				Condition: "proposal created",
			},
		},
	},
	protocol.PhaseReview: {
		Id:         protocol.PhaseReview,
		Name:       "Review",
		Number:     4,
		Domain:     types.DomainPlan,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleArchitect, types.RoleReviewer},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhasePlanReview,
				Condition: "all 3 reviewers vote ACCEPT",
			},
			{
				ToPhase:   protocol.PhasePropose,
				Condition: "any reviewer votes REVISE",
				Action:    "create PROPOSAL-{N+1}, mark current pasture:superseded",
			},
		},
	},
	protocol.PhasePlanReview: {
		Id:         protocol.PhasePlanReview,
		Name:       "Plan UAT",
		Number:     5,
		Domain:     types.DomainUser,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleArchitect},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhaseRatify,
				Condition: "user accepts plan",
			},
			{
				ToPhase:   protocol.PhasePropose,
				Condition: "user requests changes",
				Action:    "create PROPOSAL-{N+1}",
			},
		},
	},
	protocol.PhaseRatify: {
		Id:         protocol.PhaseRatify,
		Name:       "Ratify",
		Number:     6,
		Domain:     types.DomainPlan,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleArchitect},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhaseHandoff,
				Condition: "proposal ratified, IMPL_PLAN placeholder created",
			},
		},
	},
	protocol.PhaseHandoff: {
		Id:         protocol.PhaseHandoff,
		Name:       "Handoff",
		Number:     7,
		Domain:     types.DomainPlan,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleArchitect, types.RoleSupervisor},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhaseImplPlan,
				Condition: "handoff authored in the HANDOFF Beads task body",
			},
		},
	},
	protocol.PhaseImplPlan: {
		Id:         protocol.PhaseImplPlan,
		Name:       "Impl Plan",
		Number:     8,
		Domain:     types.DomainImpl,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleSupervisor},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhaseWorkerSlices,
				Condition: "all slices created with leaf tasks, assigned, and dependency-chained",
			},
		},
	},
	protocol.PhaseWorkerSlices: {
		Id:         protocol.PhaseWorkerSlices,
		Name:       "Worker Slices",
		Number:     9,
		Domain:     types.DomainImpl,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleSupervisor, types.RoleWorker},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhaseCodeReview,
				Condition: "all slices complete, quality gates pass",
			},
		},
	},
	protocol.PhaseCodeReview: {
		Id:         protocol.PhaseCodeReview,
		Name:       "Code Review",
		Number:     10,
		Domain:     types.DomainImpl,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleSupervisor, types.RoleReviewer},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhaseImplUAT,
				Condition: "all 3 reviewers ACCEPT, all BLOCKERs resolved",
			},
			{
				ToPhase:   protocol.PhaseWorkerSlices,
				Condition: "any reviewer votes REVISE",
				Action:    "fix BLOCKERs in affected slices, then re-review",
			},
		},
	},
	protocol.PhaseImplUAT: {
		Id:         protocol.PhaseImplUAT,
		Name:       "Impl UAT",
		Number:     11,
		Domain:     types.DomainUser,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleSupervisor},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhaseLanding,
				Condition: "user accepts implementation",
			},
			{
				ToPhase:   protocol.PhaseWorkerSlices,
				Condition: "user requests changes",
				Action:    "create fix tasks in affected slices",
			},
		},
	},
	protocol.PhaseLanding: {
		Id:         protocol.PhaseLanding,
		Name:       "Landing",
		Number:     12,
		Domain:     types.DomainImpl,
		OwnerRoles: []types.RoleId{types.RoleEpoch, types.RoleSupervisor},
		Transitions: []Transition{
			{
				ToPhase:   protocol.PhaseComplete,
				Condition: "git push succeeds, all tasks closed or dependency-resolved",
			},
		},
	},
}

PhaseSpecs maps each PhaseId to its full specification. Mirrors Python PHASE_SPECS dict.

View Source
var ProcedureSteps = map[types.RoleId][]ProcedureStep{
	types.RoleEpoch:     {},
	types.RoleArchitect: {},
	types.RoleReviewer:  {},
	types.RoleSupervisor: {
		{
			Id:          "S-supervisor-call-skill",
			Order:       1,
			Instruction: "Call Skill(/pasture:supervisor) to load role instructions",
			Command:     "Skill(/pasture:supervisor)",
		},
		{
			Id:          "S-supervisor-read-plan",
			Order:       2,
			Instruction: "Read RATIFIED_PLAN, URD, UAT, and elicit tasks via bd show for full context",
			Command:     "bd show <ratified-plan-id> && bd show <urd-id> && bd show <uat-id> && bd show <elicit-id>",
		},
		{
			Id:          "S-supervisor-explore-ephemeral",
			Order:       3,
			Instruction: "Spawn ephemeral Explore subagents via Task tool for scoped codebase queries",
			Context:     "Each subagent is short-lived and returns findings; no standing team overhead",
		},
		{
			Id:          "S-supervisor-decompose-slices",
			Order:       4,
			Instruction: "Decompose into vertical slices",
			Context: "Vertical slices give one worker end-to-end ownership of a feature path " +
				"(types → tests → impl → wiring) with clear file boundaries",
			NextState: protocol.PhaseImplPlan,
		},
		{
			Id:          "S-supervisor-create-leaf-tasks",
			Order:       5,
			Instruction: "Create leaf tasks (L1/L2/L3) for every slice",
			Command:     `bd create --labels pasture:p9-impl:s9-slice --title "SLICE-{K}-L{1,2,3}: <description>" ...`,
			Examples: []Example{
				{
					Id:    "S-supervisor-create-leaf-tasks-frontmatter",
					Lang:  "bash",
					Label: "template",
					Code: "bd create --labels pasture:p9-impl:s9-slice \\\n" +
						"  --title \"SLICE-1-L1: Types -- <slice name>\" \\\n" +
						"  --description \"---\n" +
						"references:\n" +
						"  slice: <slice-1-id>\n" +
						"  impl_plan: <impl-plan-task-id>\n" +
						"  urd: <urd-task-id>\n" +
						"---\n" +
						"Layer 1: types and interfaces for <slice name>.\"",
					AlsoIllustrates: "C-frontmatter-refs",
				},
			},
		},
		{
			Id:    "S-supervisor-spawn-workers",
			Order: 6,
			Instruction: "Spawn workers via the Agent tool — " +
				"set `name` for a named teammate, leave `name` empty for a backgrounded subagent " +
				"(NOT aura-swarm). " +
				"Choose model: sonnet for non-trivial slices, haiku for trivial changes. " +
				"Set thinking effort to match slice complexity.",
			NextState: protocol.PhaseWorkerSlices,
		},
	},
	types.RoleWorker: {
		{
			Id:          "S-worker-types",
			Order:       1,
			Instruction: "Types, interfaces, schemas (no deps)",
		},
		{
			Id:          "S-worker-tests",
			Order:       2,
			Instruction: "Tests importing production code (will fail initially)",
		},
		{
			Id:          "S-worker-impl",
			Order:       3,
			Instruction: "Make tests pass. Wire with real dependencies. No TODOs.",
			NextState:   protocol.PhaseWorkerSlices,
		},
	},
}

ProcedureSteps maps each RoleId to its ordered startup procedure steps. Mirrors Python PROCEDURE_STEPS dict.

View Source
var ReviewAxisSpecs = map[string]ReviewAxisSpec{
	"axis-correctness": {
		Id:     "axis-correctness",
		Letter: "correctness",
		Name:   "Correctness",
		Short:  "Spirit and technicality",
		KeyQuestions: []string{
			"Does the implementation faithfully serve the user's original request?",
			"Are technical decisions consistent with the rationale in the proposal?",
			"Are there gaps where the proposal says one thing but the code does another?",
		},
	},
	"axis-test_quality": {
		Id:     "axis-test_quality",
		Letter: "test_quality",
		Name:   "Test quality",
		Short:  "Test strategy adequacy",
		KeyQuestions: []string{
			"Favour integration tests over brittle unit tests?",
			"System under test NOT mocked — mock dependencies only?",
			"Shared fixtures for common test values?",
			"Assert observable outcomes, not internal state?",
		},
	},
	"axis-elegance": {
		Id:     "axis-elegance",
		Letter: "elegance",
		Name:   "Elegance",
		Short:  "Complexity matching",
		KeyQuestions: []string{
			"Design the API you know you will need?",
			"No over-engineering (premature abstractions, plugin systems)?",
			"No under-engineering (cutting corners on security or correctness)?",
			"Complexity proportional to innate problem complexity?",
		},
	},
}

ReviewAxisSpecs maps axis IDs to their full specifications. Mirrors Python REVIEW_AXIS_SPECS dict.

View Source
var RoleSpecs = map[types.RoleId]RoleSpec{
	types.RoleEpoch: {
		Id:          types.RoleEpoch,
		Name:        "Epoch",
		Description: "Master orchestrator for full 12-phase workflow",
		Model:       "opus",
		Thinking:    "medium",
		Tools:       []string{"Read", "Glob", "Grep", "Bash", "Skill", "Agent", "Task", "SendMessage"},
		OwnedPhases: []protocol.PhaseId{
			protocol.PhaseRequest, protocol.PhaseElicit, protocol.PhasePropose,
			protocol.PhaseReview, protocol.PhasePlanReview, protocol.PhaseRatify,
			protocol.PhaseHandoff, protocol.PhaseImplPlan, protocol.PhaseWorkerSlices,
			protocol.PhaseCodeReview, protocol.PhaseImplUAT, protocol.PhaseLanding,
		},
		Introduction: "You are the master orchestrator for the full 12-phase epoch lifecycle. " +
			"You delegate planning phases (1-7) to the architect and implementation phases (7-12) " +
			"to the supervisor.",
		OwnershipNarrative: "You own the full 12-phase lifecycle from Request to Landing. " +
			"You delegate phases 1-7 to the architect and phases 7-12 to the supervisor. " +
			"The epoch role coordinates the complete workflow end-to-end and is the only role " +
			"that spans all phases.",
	},
	types.RoleArchitect: {
		Id:          types.RoleArchitect,
		Name:        "Architect",
		Description: "Specification writer and implementation designer",
		Model:       "opus",
		Thinking:    "medium",
		Tools:       []string{"Read", "Glob", "Grep", "Bash", "Skill", "Agent", "Task", "SendMessage"},
		OwnedPhases: []protocol.PhaseId{
			protocol.PhaseRequest, protocol.PhaseElicit, protocol.PhasePropose,
			protocol.PhaseReview, protocol.PhasePlanReview, protocol.PhaseRatify,
			protocol.PhaseHandoff,
		},
		Introduction: "You design specifications and coordinate the planning phases of epochs. " +
			"See the project's AGENTS.md and ~/.claude/CLAUDE.md for coding standards and constraints.",
		OwnershipNarrative: "You own Phases 1-7 of the epoch: " +
			"capture and classify user request (p1), " +
			"run requirements elicitation URE survey (p2), " +
			"create PROPOSAL-N with full technical plan (p3), " +
			"spawn 3 axis-specific reviewers and loop until consensus (p4), " +
			"present plan to user for acceptance test (p5), " +
			"add ratify label to accepted PROPOSAL-N (p6), " +
			"create handoff document and transfer to supervisor (p7).",
		Behaviors: []BehaviorSpec{
			{
				Id:        "B-arch-elicit",
				Given:     "user request captured",
				When:      "starting",
				Then:      "run /pasture:user-elicit for URE survey",
				ShouldNot: "skip elicitation phase",
			},
			{
				Id:        "B-arch-bdd",
				Given:     "a feature request",
				When:      "writing plan",
				Then:      "use BDD Given/When/Then format with acceptance criteria",
				ShouldNot: "write vague requirements",
			},
			{
				Id:        "B-arch-reviewers",
				Given:     "plan ready",
				When:      "requesting review",
				Then:      "spawn 3 axis-specific reviewers (A=Correctness, B=Test quality, C=Elegance)",
				ShouldNot: "spawn reviewers without axis assignment",
			},
			{
				Id:        "B-arch-uat",
				Given:     "consensus reached (all 3 ACCEPT)",
				When:      "proceeding",
				Then:      "run /pasture:user-uat before ratifying",
				ShouldNot: "skip user acceptance test",
			},
			{
				Id:        "B-arch-ratify",
				Given:     "UAT passed",
				When:      "ratifying",
				Then:      "add pasture:p6-plan:s6-ratify label to PROPOSAL-N",
				ShouldNot: "close or delete the proposal task",
			},
		},
	},
	types.RoleReviewer: {
		Id:          types.RoleReviewer,
		Name:        "Reviewer",
		Description: "End-user alignment reviewer for plans and code",
		Model:       "sonnet",
		Tools:       []string{"Read", "Glob", "Grep", "Bash", "Skill", "SendMessage"},
		OwnedPhases: []protocol.PhaseId{
			protocol.PhaseReview, protocol.PhaseCodeReview,
		},
		Introduction: "You review from an end-user alignment perspective. " +
			"See the project's protocol/CONSTRAINTS.md for coding standards.",
		OwnershipNarrative: "You participate in two phases: " +
			"Phase 4 (plan review) — evaluate PROPOSAL-N against one axis using binary ACCEPT/REVISE, " +
			"NO severity tree; " +
			"Phase 10 (code review) — review ALL implementation slices against your axis using " +
			"full severity tree (BLOCKER/IMPORTANT/MINOR), EAGER creation of all 3 severity groups.",
		Behaviors: []BehaviorSpec{
			{
				Id:        "B-rev-end-user",
				Given:     "a review assignment",
				When:      "reviewing",
				Then:      "apply end-user alignment criteria",
				ShouldNot: "focus only on technical details",
			},
			{
				Id:        "B-rev-revise-feedback",
				Given:     "issues found",
				When:      "voting",
				Then:      "vote REVISE with specific actionable feedback",
				ShouldNot: "vote REVISE without suggestions",
			},
			{
				Id:        "B-rev-accept",
				Given:     "all criteria met",
				When:      "voting",
				Then:      "vote ACCEPT with brief rationale",
				ShouldNot: "delay consensus unnecessarily",
			},
			{
				Id:        "B-rev-all-slices",
				Given:     "impl review (Phase 10)",
				When:      "assigned",
				Then:      "review ALL slices (not just one)",
				ShouldNot: "skip any slice",
			},
		},
	},
	types.RoleSupervisor: {
		Id:          types.RoleSupervisor,
		Name:        "Supervisor",
		Description: "Task coordinator, spawns workers, manages parallel execution",
		Model:       "opus",
		Thinking:    "medium",
		Tools:       []string{"Read", "Glob", "Grep", "Bash", "Skill", "Agent", "Task", "SendMessage"},
		OwnedPhases: []protocol.PhaseId{
			protocol.PhaseHandoff, protocol.PhaseImplPlan, protocol.PhaseWorkerSlices,
			protocol.PhaseCodeReview, protocol.PhaseImplUAT, protocol.PhaseLanding,
		},
		Introduction: "You coordinate parallel task execution. " +
			"See the project's AGENTS.md and ~/.claude/CLAUDE.md for coding standards and constraints.",
		OwnershipNarrative: "You own Phases 7-12 of the epoch: " +
			"receive handoff from architect (p7), " +
			"create vertical slice decomposition IMPL_PLAN (p8), " +
			"spawn workers for parallel implementation SLICE-N (p9), " +
			"spawn reviewers for per-slice code review with severity tree (p10), " +
			"coordinate user acceptance test (p11), " +
			"commit, push, and hand off (p12). " +
			"You NEVER implement code directly — all implementation is delegated to workers.",
		Behaviors: []BehaviorSpec{
			{
				Id:        "B-sup-read-context",
				Given:     "handoff received",
				When:      "starting",
				Then:      "read ratified plan, URD, UAT, and elicit tasks for full context",
				ShouldNot: "start without reading all four",
			},
			{
				Id:        "B-sup-model-trivial",
				Given:     "trivial changes (single-file edits, config tweaks, typo fixes)",
				When:      "spawning a worker",
				Then:      "use model: haiku to minimize cost and latency",
				ShouldNot: "use a heavyweight model for trivial work",
			},
			{
				Id:        "B-sup-model-nontrivial",
				Given:     "non-trivial changes (multi-file, architectural, logic-heavy)",
				When:      "spawning a worker",
				Then:      "prefer model: sonnet for the Task tool to ensure quality",
				ShouldNot: "default to haiku for complex work",
			},
			{
				Id:    "B-sup-ride-the-wave",
				Given: "Phase 8-10 execution",
				When:  "starting implementation",
				Then: "follow the Ride the Wave cycle: plan tasks with integration points, " +
					"launch the wave of workers, spawn reviewers for per-slice review " +
					"(clean exit = 0 BLOCKER + 0 IMPORTANT + 0 MINOR), workers fix per-slice with atomic commits, " +
					"and iterate review -> fix -> re-review up to the chosen review-effort budget until a fix-free clean round confirms 0/0/0; on budget exhaustion without clean, surface outstanding findings to the user at a gate",
				ShouldNot: "skip any stage; batch review across slices; hardcode the budget; proceed past the chosen budget without surfacing to the user; " +
					"close a wave with any finding silently outstanding",
			},
		},
	},
	types.RoleWorker: {
		Id:          types.RoleWorker,
		Name:        "Worker",
		Description: "Vertical slice implementer (full production code path)",
		Model:       "sonnet",
		Tools:       []string{"Read", "Glob", "Grep", "Bash", "Skill", "Edit", "Write", "SendMessage"},
		OwnedPhases: []protocol.PhaseId{protocol.PhaseWorkerSlices},
		Introduction: "You own a vertical slice (full production code path from CLI/API entry point " +
			"→ service → types). " +
			"See the project's AGENTS.md and ~/.claude/CLAUDE.md for coding standards and constraints.",
		OwnershipNarrative: "NOT: A single file or horizontal layer (e.g., 'all types' or 'all tests'). " +
			"YES: A full vertical slice (complete production code path end-to-end). " +
			"You own the FEATURE end-to-end, not a layer or file. " +
			"Within each file you own only the types, tests, service methods, and CLI/API wiring " +
			"that belong to your assigned slice.",
		Behaviors: []BehaviorSpec{
			{
				Id:        "B-worker-vertical-ownership",
				Given:     "vertical slice assignment",
				When:      "implementing",
				Then:      "own full production code path (types → tests → impl → wiring)",
				ShouldNot: "implement only horizontal layer",
			},
			{
				Id:        "B-worker-plan-backwards",
				Given:     "production code path",
				When:      "planning",
				Then:      "plan backwards from end point to types",
				ShouldNot: "start with types without knowing the end",
			},
			{
				Id:        "B-worker-test-production-code",
				Given:     "tests",
				When:      "writing",
				Then:      "import actual production code (CLI/API users will run)",
				ShouldNot: "create test-only export or dual code paths",
			},
			{
				Id:        "B-worker-verify-production",
				Given:     "implementation complete",
				When:      "verifying before signaling done",
				Then:      "manually trace the production code path end-to-end (entry point → service → types) to confirm wiring, error handling, and no dead code — beyond what automated gates check",
				ShouldNot: "treat passing tests as sufficient verification without a manual walkthrough",
			},
			{
				Id:        "B-worker-blocker",
				Given:     "a blocker",
				When:      "unable to proceed",
				Then:      "use /pasture:worker-blocked with details",
				ShouldNot: "guess or work around",
			},
		},
	},
}

RoleSpecs maps each RoleId to its full specification. Mirrors Python ROLE_SPECS dict.

View Source
var SharedFragmentSpecs = map[FragmentId]SharedFragment{
	FragRevVoteOptions: func() SharedFragment {
		prose := ProseSection{
			Id:    string(FragRevVoteOptions),
			Title: "Vote Options",
			Content: `| Vote | When |
|------|------|
| ACCEPT | All review criteria satisfied; no BLOCKER items |
| REVISE | BLOCKER issues found; must provide actionable feedback |

Binary only. No intermediate levels.`,
		}
		return SharedFragment{
			Id:    FragRevVoteOptions,
			Kind:  FragmentKindProse,
			Prose: &prose,
		}
	}(),

	FragSupReviewAllSlices: {
		Id:   FragSupReviewAllSlices,
		Kind: FragmentKindBehavior,
		Behavior: &BehaviorSpec{
			Id:        string(FragSupReviewAllSlices),
			Given:     "all slices complete",
			When:      "starting review",
			Then:      "spawn 3 reviewers for ALL slices",
			ShouldNot: "assign reviewers to single slices",
		},
	},

	FragSupReviewCheckEach: {
		Id:   FragSupReviewCheckEach,
		Kind: FragmentKindBehavior,
		Behavior: &BehaviorSpec{
			Id:        string(FragSupReviewCheckEach),
			Given:     "reviewer assigned",
			When:      "reviewing",
			Then:      "check each slice against criteria",
			ShouldNot: "skip any slice",
		},
	},

	FragSupReviewSeverityGroups: {
		Id:   FragSupReviewSeverityGroups,
		Kind: FragmentKindBehavior,
		Behavior: &BehaviorSpec{
			Id:        string(FragSupReviewSeverityGroups),
			Given:     "review round",
			When:      "creating severity groups",
			Then:      "ALWAYS create 3 severity groups (BLOCKER, IMPORTANT, MINOR) per round even if empty",
			ShouldNot: "lazily create groups only when findings exist",
		},
	},

	FragSupBlockerDualParent: {
		Id:   FragSupBlockerDualParent,
		Kind: FragmentKindBehavior,
		Behavior: &BehaviorSpec{
			Id:        string(FragSupBlockerDualParent),
			Given:     "BLOCKER finding",
			When:      "wiring dependencies",
			Then:      "add dual-parent: blocks BOTH the severity group AND the slice",
			ShouldNot: "wire BLOCKER to only one parent",
		},
	},

	FragSupDeferredFollowup: {
		Id:   FragSupDeferredFollowup,
		Kind: FragmentKindBehavior,
		Behavior: &BehaviorSpec{
			Id:        string(FragSupDeferredFollowup),
			Given:     "a review finding (BLOCKER, IMPORTANT, or MINOR)",
			When:      "categorizing",
			Then:      "track it in its severity group; ALL severity groups must reach 0 before wave close — the FOLLOWUP epic is fed ONLY by user-DEFER'd UAT items, never by any review severity",
			ShouldNot: "route any review severity (BLOCKER/IMPORTANT/MINOR) to the FOLLOWUP epic; close a wave with any finding outstanding",
		},
	},

	FragSupFollowupEpicTiming: {
		Id:   FragSupFollowupEpicTiming,
		Kind: FragmentKindBehavior,
		Behavior: &BehaviorSpec{
			Id:        string(FragSupFollowupEpicTiming),
			Given:     "UAT (Phase 5 or 11) produces one or more user-DEFER'd items",
			When:      "finishing UAT",
			Then:      "supervisor creates the FOLLOWUP epic from the user-DEFER'd UAT items only",
			ShouldNot: "create a FOLLOWUP epic from any review severity (BLOCKER/IMPORTANT/MINOR)",
		},
	},

	FragSupSeverityTree: func() SharedFragment {

		namingConvention := ProseSection{
			Id:    string(FragSupNamingConvention),
			Title: "Naming Convention",
			Content: "```" + `
SLICE-{N}-REVIEW-{axis}-{round}
` + "```" + `

Where axis = A (Correctness), B (Test quality), C (Elegance).

Examples:
- ` + "`SLICE-1-REVIEW-A-1`" + ` — Reviewer A (Correctness), Round 1, SLICE-1
- ` + "`SLICE-2-REVIEW-C-2`" + ` — Reviewer C (Elegance), Round 2, SLICE-2

Severity groups:
- ` + "`SLICE-1-REVIEW-A-1 BLOCKER`" + `
- ` + "`SLICE-1-REVIEW-A-1 IMPORTANT`" + `
- ` + "`SLICE-1-REVIEW-A-1 MINOR`",
		}
		prose := ProseSection{
			Id:    string(FragSupSeverityTree),
			Title: "Severity Tree (EAGER Creation)",
			Content: `Per [frag--sup-review-severity-groups], create all 3 severity groups immediately:

` + "```" + `bash
# Step 1: Create all 3 severity groups immediately (EAGER)
BLOCKER_ID=$(bd create --title "SLICE-1-REVIEW-A-1 BLOCKER" \
  --labels "pasture:severity:blocker,pasture:p10-impl:s10-review" \
  --description "---
references:
  slice: <slice-1-id>
  review_round: 1
---
BLOCKER findings from Reviewer A (Correctness) on SLICE-1.")

IMPORTANT_ID=$(bd create --title "SLICE-1-REVIEW-A-1 IMPORTANT" \
  --labels "pasture:severity:important,pasture:p10-impl:s10-review" \
  --description "---
references:
  slice: <slice-1-id>
  review_round: 1
---
IMPORTANT findings from Reviewer A (Correctness) on SLICE-1.")

MINOR_ID=$(bd create --title "SLICE-1-REVIEW-A-1 MINOR" \
  --labels "pasture:severity:minor,pasture:p10-impl:s10-review" \
  --description "---
references:
  slice: <slice-1-id>
  review_round: 1
---
MINOR findings from Reviewer A (Correctness) on SLICE-1.")

# Step 2: Wire severity groups to the review round task
bd dep add <review-round-id> --blocked-by $BLOCKER_ID
bd dep add <review-round-id> --blocked-by $IMPORTANT_ID
bd dep add <review-round-id> --blocked-by $MINOR_ID
# NEVER wire severity groups to IMPL_PLAN or slices directly.
# BLOCKER findings block slices via dual-parent (see below).
# IMPORTANT/MINOR must ALSO reach 0 before wave close — they are NOT routed to FOLLOWUP.
# The FOLLOWUP epic is fed ONLY by user-DEFER'd UAT items (see Follow-up Epic section).

# Step 3: Close empty groups immediately
# If a group has no findings, close it right away
bd close $IMPORTANT_ID   # if no IMPORTANT findings
bd close $MINOR_ID        # if no MINOR findings
` + "```",
			Subsections: []ProseSection{namingConvention},
		}
		return SharedFragment{
			Id:    FragSupSeverityTree,
			Kind:  FragmentKindProse,
			Prose: &prose,
		}
	}(),

	FragSupNamingConvention: func() SharedFragment {
		prose := ProseSection{
			Id:    string(FragSupNamingConvention),
			Title: "Naming Convention",
			Content: "```" + `
SLICE-{N}-REVIEW-{axis}-{round}
` + "```" + `

Where axis = A (Correctness), B (Test quality), C (Elegance).

Examples:
- ` + "`SLICE-1-REVIEW-A-1`" + ` — Reviewer A (Correctness), Round 1, SLICE-1
- ` + "`SLICE-2-REVIEW-C-2`" + ` — Reviewer C (Elegance), Round 2, SLICE-2

Severity groups:
- ` + "`SLICE-1-REVIEW-A-1 BLOCKER`" + `
- ` + "`SLICE-1-REVIEW-A-1 IMPORTANT`" + `
- ` + "`SLICE-1-REVIEW-A-1 MINOR`",
		}
		return SharedFragment{
			Id:    FragSupNamingConvention,
			Kind:  FragmentKindProse,
			Prose: &prose,
		}
	}(),

	FragRevPlanVoteOptions: func() SharedFragment {
		prose := ProseSection{
			Id:    string(FragRevPlanVoteOptions),
			Title: "Vote Options",
			Content: `| Vote | When |
|------|------|
| ACCEPT | All review criteria satisfied; no BLOCKER items |
| REVISE | BLOCKER issues found; must provide actionable feedback |

Binary only. No severity tree for plan reviews.`,
		}
		return SharedFragment{
			Id:    FragRevPlanVoteOptions,
			Kind:  FragmentKindProse,
			Prose: &prose,
		}
	}(),

	FragValidationCases: {
		Id:   FragValidationCases,
		Kind: FragmentKindBehavior,
		Behavior: &BehaviorSpec{
			Id:        string(FragValidationCases),
			Given:     "any REQUEST (every request, not only fix-intent ones)",
			When:      "eliciting (URE), acceptance-testing (UAT), or implementing",
			Then:      "elicit concrete validation cases — a definition of done plus correct and incorrect behaviours (inputs/behaviors that must pass or must fail), confirm the case set with the user in UAT, evaluate the implementation against them, and store failing real-data cases as test fixtures",
			ShouldNot: "ship without validation cases; treat validation cases as applying to fix-intent requests only; introduce a request-type axis or enum to gate them",
		},
	},

	FragReviewCleanExit: {
		Id:   FragReviewCleanExit,
		Kind: FragmentKindBehavior,
		Behavior: &BehaviorSpec{
			Id:        string(FragReviewCleanExit),
			Given:     "per-slice code review",
			When:      "evaluating review results",
			Then:      "iterate review -> fix -> re-review up to the chosen review-effort budget; clean = 0 BLOCKER + 0 IMPORTANT + 0 MINOR within budget; on budget exhaustion without clean, SURFACE the outstanding findings to the user at a gate for a decision",
			ShouldNot: "hardcode the budget; proceed past the chosen budget without surfacing outstanding findings to the user; loop forever when a finite budget was chosen",
		},
	},
}

SharedFragmentSpecs is the canonical registry of reusable shared fragments. Keyed by FragmentId typed constant (must match the FragRef field used in placement marker entries).

SLICE-2 adds: FragRevVoteOptions (green-enabler; resolves the sole pre-existing same-id collision between reviewer-vote and reviewer skill bodies). Canonical content per D3 (UAT-ratified): ACCEPT row = "All review criteria satisfied; no BLOCKER items". Both consumer bodies carry fragRef markers. Set keys MUST equal AllFragmentIds (validated by ValidateGlobalIds).

SLICE-3 adds: 6 supervisor review-wave behavior fragments (FragSupReview*, FragSupBlockerDualParent, FragSupDeferredFollowup, FragSupFollowupEpicTiming) and 2 prose fragments (FragSupSeverityTree, FragSupNamingConvention). These replace identical inline definitions in both the supervisor and impl-review skill bodies, eliminating the last same-id collision group. Canonical content = supervisor text.

SLICE-1 (epoch improvements) adds: FragValidationCases (R6, wired into user-elicit/user-uat/worker-implement bodies by SLICE-2) and FragReviewCleanExit (R7, wired into supervisor/impl-review bodies by SLICE-3). It also renames FragSupImportantMinorFollowup -> FragSupDeferredFollowup (R7/A1): review severities no longer feed FOLLOWUP; the FOLLOWUP epic is fed solely by user-DEFER'd UAT items.

View Source
var SkillBodySpecs = map[string]SkillBody{
	"supervisor":              supervisorBody,
	"supervisor-plan-tasks":   supervisorPlanTasksBody,
	"supervisor-spawn-worker": supervisorSpawnWorkerBody,
	"worker":                  workerBody,
	"architect":               architectBody,
	"reviewer":                reviewerBody,
	"impl-review":             implReviewBody,

	"architect-handoff":         architectHandoffBody,
	"architect-propose-plan":    architectProposePlanBody,
	"architect-ratify":          architectRatifyBody,
	"architect-request-review":  architectRequestReviewBody,
	"epoch":                     epochBody,
	"explore":                   exploreBody,
	"impl-slice":                implSliceBody,
	"research":                  researchBody,
	"reviewer-comment":          reviewerCommentBody,
	"reviewer-review-code":      reviewerReviewCodeBody,
	"reviewer-review-plan":      reviewerReviewPlanBody,
	"reviewer-vote":             reviewerVoteBody,
	"status":                    statusBody,
	"supervisor-commit":         supervisorCommitBody,
	"supervisor-track-progress": supervisorTrackProgressBody,
	"swarm":                     swarmBody,
	"user-elicit":               userElicitBody,
	"user-request":              userRequestBody,
	"user-uat":                  userUatBody,
	"worker-blocked":            workerBlockedBody,
	"worker-complete":           workerCompleteBody,
	"worker-implement":          workerImplementBody,
}
View Source
var SubstepDataMap = map[string][]SubstepData{
	"p1": {
		{
			Id: "s1_1", Type: "classify", Execution: "sequential", Order: 1,
			LabelRef:    "L-p1s1_1",
			Description: "Classify request along 4 axes: scope, complexity, risk, domain novelty",
		},
		{
			Id: "s1_2", Type: "research", Execution: "parallel", Order: 2,
			ParallelGroup: "p1-discovery", LabelRef: "L-p1s1_2",
			Description: "Find domain standards, prior art, relevant documentation",
		},
		{
			Id: "s1_3", Type: "explore", Execution: "parallel", Order: 2,
			ParallelGroup: "p1-discovery", LabelRef: "L-p1s1_3",
			Description: "Codebase exploration for integration points",
		},
	},
	"p2": {
		{
			Id: "s2_1", Type: "elicit", Execution: "sequential", Order: 1,
			LabelRef:    "L-p2s2_1",
			Description: "URE survey: structured Q&A with user to capture requirements",
		},
		{
			Id: "s2_2", Type: "urd", Execution: "sequential", Order: 2,
			LabelRef:    "L-p2s2_2",
			Description: "Create URD as single source of truth for requirements",
			ExtraLabel:  "L-urd",
		},
	},
	"p3": {
		{
			Id: "s3", Type: "propose", Execution: "sequential", Order: 1,
			LabelRef:    "L-p3s3",
			Description: "Full technical proposal: interfaces, approach, validation checklist, BDD criteria",
		},
	},
	"p4": {
		{
			Id: "s4", Type: "review", Execution: "parallel", Order: 1,
			LabelRef:    "L-p4s4",
			Description: "Each reviewer assesses one axis (A/B/C). All 3 must ACCEPT.",
			Instances:   &SubstepInstances{Count: "3", Per: "review-axis"},
		},
	},
	"p5": {
		{
			Id: "s5", Type: "uat", Execution: "sequential", Order: 1,
			LabelRef:    "L-p5s5",
			Description: "Present plan to user with demonstrative examples. User approves or requests changes.",
		},
	},
	"p6": {
		{
			Id: "s6", Type: "ratify", Execution: "sequential", Order: 1,
			LabelRef:    "L-p6s6",
			Description: "Add ratify label. Mark prior proposals pasture:superseded. Create placeholder IMPL_PLAN.",
		},
	},
	"p7": {
		{
			Id: "s7", Type: "handoff", Execution: "sequential", Order: 1,
			LabelRef:    "L-p7s7",
			Description: "Create handoff document with full inline provenance. Transfer to supervisor.",
		},
	},
	"p8": {
		{
			Id: "s8", Type: "plan", Execution: "sequential", Order: 1,
			LabelRef:        "L-p8s8",
			Description:     "Identify production code paths. Create SLICE-N tasks with leaf tasks. Assign workers.",
			StartupSequence: true,
		},
	},
	"p9": {
		{
			Id: "s9", Type: "slice", Execution: "parallel", Order: 1,
			LabelRef:    "L-p9s9",
			Description: "Each worker owns full vertical: types, tests, implementation, wiring",
			Instances:   &SubstepInstances{Count: "N", Per: "production-code-path"},
		},
	},
	"p10": {
		{
			Id: "s10", Type: "review", Execution: "parallel", Order: 1,
			LabelRef:    "L-p10s10",
			Description: "Each reviewer reviews ALL slices against their axis. EAGER severity tree.",
			Instances:   &SubstepInstances{Count: "3", Per: "review-axis"},
		},
	},
	"p11": {
		{
			Id: "s11", Type: "uat", Execution: "sequential", Order: 1,
			LabelRef:    "L-p11s11",
			Description: "Present implementation to user. User approves or requests fixes.",
		},
	},
	"p12": {
		{
			Id: "s12", Type: "landing", Execution: "sequential", Order: 1,
			LabelRef:    "L-p12s12",
			Description: "git agent-commit, bd sync, git push. Close upstream tasks.",
		},
	},
}

SubstepDataMap maps phase ID strings to their ordered substep data. Mirrors Python SUBSTEP_DATA dict.

View Source
var TitleConventions = []TitleConvention{
	{Pattern: "REQUEST: {description}", LabelRef: "L-p1s1_1", CreatedBy: "epoch,architect", PhaseRef: "p1"},
	{Pattern: "ELICIT: {description}", LabelRef: "L-p2s2_1", CreatedBy: "architect", PhaseRef: "p2"},
	{Pattern: "URD: {description}", LabelRef: "L-p2s2_2", CreatedBy: "architect", PhaseRef: "p2", ExtraLabelRef: "L-urd"},
	{
		Pattern: "PROPOSAL-{N}: {description}", LabelRef: "L-p3s3", CreatedBy: "architect", PhaseRef: "p3",
		Note: "N increments per revision. Old proposals marked pasture:superseded.",
	},
	{
		Pattern: "PROPOSAL-{N}-REVIEW-{axis}-{round}: {description}", LabelRef: "L-p4s4", CreatedBy: "reviewer", PhaseRef: "p4",
		Note: "axis=A|B|C, round starts at 1",
	},
	{Pattern: "UAT-{N}: {description}", LabelRef: "L-p5s5", CreatedBy: "architect", PhaseRef: "p5"},
	{Pattern: "IMPL_PLAN: {description}", LabelRef: "L-p8s8", CreatedBy: "supervisor", PhaseRef: "p8"},
	{
		Pattern: "SLICE-{N}: {description}", LabelRef: "L-p9s9", CreatedBy: "supervisor", PhaseRef: "p9",
		Note: "N identifies slice within the implementation plan",
	},
	{
		Pattern: "SLICE-{N}-REVIEW-{axis}-{round}: {description}", LabelRef: "L-p10s10", CreatedBy: "reviewer", PhaseRef: "p10",
		Note: "axis=A|B|C, round starts at 1",
	},
	{
		Pattern: "IMPL-REVIEW-{axis}-{round}: {description}", LabelRef: "L-p10s10", CreatedBy: "supervisor", PhaseRef: "p10",
		Note: "When reviewing all slices collectively",
	},
	{
		Pattern: "FOLLOWUP: {description}", LabelRef: "L-followup", CreatedBy: "supervisor",
		Note: "Follow-up epic created at UAT when user-DEFER'd items exist (never from review severities; " +
			"all review findings must reach 0 before wave close). " +
			"Single-parent epic relationship — no followup-of-followup.",
	},
	{
		Pattern: "FOLLOWUP_URE: {description}", LabelRef: "L-p2s2_1", CreatedBy: "supervisor", PhaseRef: "p2",
		Note: "Scoping URE to determine which user-DEFER'd UAT items to address",
	},
	{
		Pattern: "FOLLOWUP_URD: {description}", LabelRef: "L-p2s2_2", CreatedBy: "supervisor", PhaseRef: "p2",
		ExtraLabelRef: "L-urd",
		Note:          "Requirements doc for follow-up scope. References original URD.",
	},
	{
		Pattern: "FOLLOWUP_PROPOSAL-{N}: {description}", LabelRef: "L-p3s3", CreatedBy: "architect", PhaseRef: "p3",
		Note: "Proposal accounting for original URD + FOLLOWUP_URD + outstanding findings",
	},
	{
		Pattern: "FOLLOWUP_IMPL_PLAN: {description}", LabelRef: "L-p8s8", CreatedBy: "supervisor", PhaseRef: "p8",
		Note: "Implementation plan for follow-up slices",
	},
	{
		Pattern: "FOLLOWUP_SLICE-{N}: {description}", LabelRef: "L-p9s9", CreatedBy: "supervisor", PhaseRef: "p9",
		Note: "Follow-up slice. Adopts user-DEFER'd UAT-item leaf tasks as children " +
			"(dual-parent: leaf blocks both the DEFER'd-items tracking group AND follow-up slice).",
	},
}

TitleConventions is the ordered list of task title naming conventions. Mirrors Python TITLE_CONVENTIONS list. Note: In Go we use a slice (not a map) to preserve order, matching Python.

View Source
var WorkflowSpecs = map[string]Workflow{
	"ride-the-wave": {
		Id:      "ride-the-wave",
		Name:    "Ride the Wave",
		RoleRef: types.RoleSupervisor,
		Description: "Coordinated Phase 8-10 execution pattern. The supervisor orchestrates " +
			"the full cycle: plan slices, launch workers, " +
			"spawn reviewers for per-slice review, workers fix, and re-review up to the chosen review-effort budget " +
			"until a fix-free clean round confirms 0 BLOCKER + 0 IMPORTANT + 0 MINOR; on budget exhaustion without clean, surface outstanding findings to the user at a gate.",
		Stages: []WorkflowStage{
			{
				Id:        "rtw-plan",
				Name:      "Plan",
				Order:     1,
				Execution: "sequential",
				PhaseRef:  protocol.PhaseImplPlan,
				Actions: []WorkflowAction{
					{
						Id:          "rtw-plan-read",
						Instruction: "Read RATIFIED_PLAN and URD via bd show",
						Command:     "bd show <ratified-plan-id> && bd show <urd-id>",
					},
					{
						Id:          "rtw-plan-explore",
						Instruction: "Spawn ephemeral Explore subagents (`subagent_type=Explore`) for scoped codebase queries — NOT standing teams",
					},
					{
						Id:          "rtw-plan-decompose",
						Instruction: "Use Explore findings to decompose into vertical slices with integration points",
					},
					{
						Id:          "rtw-plan-leaf-tasks",
						Instruction: "Create leaf tasks (L1/L2/L3) for every slice",
						Command:     "bd dep add <slice-id> --blocked-by <leaf-task-id>",
					},
				},
				OperationalDetail: "",
				ExitConditions: []ExitCondition{
					{
						Type:      "proceed",
						Condition: "All slices created with leaf tasks, dependency-chained, assigned",
					},
				},
			},
			{
				Id:        "rtw-build",
				Name:      "Build",
				Order:     2,
				Execution: "parallel",
				PhaseRef:  protocol.PhaseWorkerSlices,
				Actions: []WorkflowAction{
					{
						Id: "rtw-build-spawn",
						Instruction: "Spawn workers via the Agent tool — " +
							"set `name` for a named teammate, leave `name` empty for a backgrounded subagent " +
							"(NOT aura-swarm). " +
							"Choose model: sonnet for non-trivial slices, haiku for trivial changes. " +
							"Set thinking effort to match slice complexity.",
					},
					{
						Id:          "rtw-build-monitor",
						Instruction: "Monitor worker progress via bd list and bd show",
						Command:     `bd list --labels="pasture:p9-impl:s9-slice" --status=in_progress`,
					},
					{
						Id:          "rtw-build-integrate",
						Instruction: "Supervisor commits at integration points (atomic commits) — commit small, integrate early and often",
					},
				},
				OperationalDetail: "",
				ExitConditions: []ExitCondition{
					{
						Type:      "proceed",
						Condition: "All workers have notified completion via bd comments add",
					},
				},
			},
			{
				Id:        "rtw-review-fix",
				Name:      "Review + Fix Cycles",
				Order:     3,
				Execution: "conditional-loop",
				PhaseRef:  protocol.PhaseCodeReview,
				Actions: []WorkflowAction{
					{
						Id:          "rtw-review-spawn",
						Instruction: "Spawn reviewers via Task tool for per-slice code review",
					},
					{
						Id:          "rtw-review-severity",
						Instruction: "Reviewers create severity groups (BLOCKER/IMPORTANT/MINOR) per slice",
					},
					{
						Id:          "rtw-review-severity-track",
						Instruction: "Track findings in the 3 severity groups; ALL groups must reach 0 before wave close (FOLLOWUP is created later at UAT, fed only by user-DEFER'd items)",
					},
					{
						Id:          "rtw-review-fix",
						Instruction: "Workers fix ALL findings (BLOCKER, IMPORTANT, and MINOR)",
					},
				},
				OperationalDetail: "- Spawn 3 ephemeral reviewer subagents per round (same pattern as Phase 4 plan review)\n" +
					"- **CLEAN REVIEW** = 0 BLOCKER + 0 IMPORTANT + 0 MINOR from ALL reviewers on a fix-free round\n" +
					"- Per-slice fix+review; iterate up to the chosen review-effort budget\n" +
					"- Fix flow: Stage 3 (dirty review) -> Stage 2 (worker fixes) -> Stage 3 (re-review)\n" +
					"- Configurable review-effort budget (chosen at Phase 8: 3 rounds / 1 round / 0 rounds / unlimited / custom) — repeat review -> fix -> re-review until the slice is clean (0/0/0); on budget exhaustion without clean, surface outstanding findings to the user at a gate\n" +
					"- **MUST end on a review wave** — cannot proceed after a worker wave without review\n" +
					"\n" +
					"```text\n" +
					"Stage 3 Flow (per-slice):\n" +
					"\n" +
					"  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n" +
					"  \u2502 Spawn 3 ephemeral reviewers             \u2502\n" +
					"  \u2502 Review slice (severity: BLOCKER/IMP/MIN)\u2502\n" +
					"  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n" +
					"                 \u2502\n" +
					"          CLEAN? \u251c\u2500\u2500 YES (0/0/0) \u2192 slice passes, proceed\n" +
					"                 \u2502\n" +
					"                 \u2514\u2500\u2500 NO (any finding remains)\n" +
					"                       \u2502\n" +
					"                       \u25bc\n" +
					"              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n" +
					"              \u2502 Stage 2: worker    \u2502\n" +
					"              \u2502 fixes ALL findings \u2502\n" +
					"              \u2502 (BLOCK/IMP/MINOR)  \u2502\n" +
					"              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n" +
					"                       \u2502\n" +
					"                       \u25bc\n" +
					"              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n" +
					"              \u2502 Stage 3: re-review \u2502\n" +
					"              \u2502 (new ephemeral     \u2502\n" +
					"              \u2502  reviewers)        \u2502\n" +
					"              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n" +
					"                       \u2502\n" +
					"                 loop (re-review)\n" +
					"                       \u2502\n" +
					"          repeat until clean (0/0/0) \u2014 up to the chosen budget, else surface to user\n" +
					"```",
				ExitConditions: []ExitCondition{
					{
						Type:      "success",
						Condition: "All reviewers report 0 BLOCKER + 0 IMPORTANT + 0 MINOR on a fix-free clean round — proceed to Phase 11 UAT",
					},
					{
						Type:      "continue",
						Condition: "Any finding (BLOCKER, IMPORTANT, or MINOR) remains within budget — workers fix, spawn new ephemeral reviewers (up to the chosen review-effort budget; on exhaustion, surface to the user)",
					},
				},
			},
		},
	},
	"layer-cake": {
		Id:      "layer-cake",
		Name:    "Layer Cake",
		RoleRef: types.RoleWorker,
		Description: "TDD layer-by-layer implementation within a vertical slice. " +
			"Worker implements types first, then tests (will fail), " +
			"then production code to make tests pass.",
		Stages: []WorkflowStage{
			{
				Id:        "lc-types",
				Name:      "Types",
				Order:     1,
				Execution: "sequential",
				PhaseRef:  protocol.PhaseWorkerSlices,
				Actions: []WorkflowAction{
					{
						Id:          "lc-types-read",
						Instruction: "Read slice task and identify required types",
						Command:     "bd show <slice-task-id>",
					},
					{
						Id:          "lc-types-define",
						Instruction: "Define types, interfaces, and schemas (no deps) — only types for YOUR slice",
					},
				},
				ExitConditions: []ExitCondition{
					{
						Type:      "proceed",
						Condition: "All required types defined; file imports without error",
					},
				},
			},
			{
				Id:        "lc-tests",
				Name:      "Tests",
				Order:     2,
				Execution: "sequential",
				PhaseRef:  protocol.PhaseWorkerSlices,
				Actions: []WorkflowAction{
					{
						Id:          "lc-tests-write",
						Instruction: "Write tests importing production code (CLI/API users will run) — tests WILL fail",
					},
					{
						Id:          "lc-tests-verify-import",
						Instruction: "Verify tests import actual production code, not test-only export",
					},
				},
				ExitConditions: []ExitCondition{
					{
						Type:      "proceed",
						Condition: "Tests written and import production code; typecheck passes; tests fail (expected)",
					},
				},
			},
			{
				Id:        "lc-impl",
				Name:      "Implementation + Wiring",
				Order:     3,
				Execution: "sequential",
				PhaseRef:  protocol.PhaseWorkerSlices,
				Actions: []WorkflowAction{
					{
						Id:          "lc-impl-code",
						Instruction: "Implement production code to make Layer 2 tests pass",
					},
					{
						Id:          "lc-impl-wire",
						Instruction: "Wire with real dependencies (not mocks in production code)",
					},
					{
						Id:          "lc-impl-run-tests",
						Instruction: "Run tests — all Layer 2 tests must pass",
					},
					{
						Id:          "lc-impl-commit",
						Instruction: "Commit completed work",
						Command:     "git agent-commit -m ...",
					},
					{
						Id:          "lc-impl-notify",
						Instruction: "Notify supervisor of completion via bd comments add",
						Command:     `bd comments add <slice-id> "Implementation complete"`,
					},
				},
				ExitConditions: []ExitCondition{
					{
						Type: "success",
						Condition: "All tests pass; no TODO placeholders; real deps wired; " +
							"production code path verified via code inspection",
					},
					{
						Type:      "escalate",
						Condition: "Blocker encountered — use /pasture:worker-blocked with details",
					},
				},
			},
		},
	},
	"architect-state-flow": {
		Id:      "architect-state-flow",
		Name:    "Architect State Flow",
		RoleRef: types.RoleArchitect,
		Description: "Sequential planning phases 1-7. The architect captures requirements, " +
			"writes proposals, coordinates review consensus, and hands off to supervisor.",
		Stages: []WorkflowStage{
			{
				Id:        "asf-request",
				Name:      "Request",
				Order:     1,
				Execution: "sequential",
				PhaseRef:  protocol.PhaseRequest,
				Actions: []WorkflowAction{
					{
						Id:          "asf-request-capture",
						Instruction: "Capture user request verbatim via /pasture:user-request",
					},
					{
						Id:          "asf-request-classify",
						Instruction: "Classify request along 4 axes: scope, complexity, risk, domain novelty",
					},
				},
				ExitConditions: []ExitCondition{
					{
						Type:      "proceed",
						Condition: "Classification confirmed, research and explore complete",
					},
				},
			},
			{
				Id:        "asf-elicit",
				Name:      "Elicit",
				Order:     2,
				Execution: "sequential",
				PhaseRef:  protocol.PhaseElicit,
				Actions: []WorkflowAction{
					{
						Id:          "asf-elicit-ure",
						Instruction: "Run URE survey with user via /pasture:user-elicit",
					},
					{
						Id:          "asf-elicit-urd",
						Instruction: "Create URD as single source of truth for requirements",
					},
				},
				ExitConditions: []ExitCondition{
					{
						Type:      "proceed",
						Condition: "URD created with structured requirements",
					},
				},
			},
			{
				Id:        "asf-propose",
				Name:      "Propose",
				Order:     3,
				Execution: "sequential",
				PhaseRef:  protocol.PhasePropose,
				Actions: []WorkflowAction{
					{
						Id:          "asf-propose-write",
						Instruction: "Write full technical proposal: interfaces, approach, validation checklist, BDD criteria",
					},
					{
						Id:          "asf-propose-create",
						Instruction: "Create PROPOSAL-N task via /pasture:architect:propose-plan",
					},
				},
				ExitConditions: []ExitCondition{
					{
						Type:      "proceed",
						Condition: "Proposal created",
					},
				},
			},
			{
				Id:        "asf-review",
				Name:      "Review",
				Order:     4,
				Execution: "conditional-loop",
				PhaseRef:  protocol.PhaseReview,
				Actions: []WorkflowAction{
					{
						Id:          "asf-review-spawn",
						Instruction: "Spawn 3 axis-specific reviewers (A=Correctness, B=Test quality, C=Elegance)",
					},
					{
						Id:          "asf-review-wait",
						Instruction: "Wait for all 3 reviewers to vote",
					},
				},
				ExitConditions: []ExitCondition{
					{
						Type:      "proceed",
						Condition: "All 3 reviewers vote ACCEPT",
					},
					{
						Type:      "continue",
						Condition: "Any reviewer votes REVISE — create PROPOSAL-N+1, mark old as superseded, re-spawn reviewers",
					},
				},
			},
			{
				Id:        "asf-uat",
				Name:      "Plan UAT",
				Order:     5,
				Execution: "sequential",
				PhaseRef:  protocol.PhasePlanReview,
				Actions: []WorkflowAction{
					{
						Id:          "asf-uat-present",
						Instruction: "Present plan to user with demonstrative examples via /pasture:user-uat",
					},
				},
				ExitConditions: []ExitCondition{
					{
						Type:      "proceed",
						Condition: "User accepts plan",
					},
					{
						Type:      "continue",
						Condition: "User requests changes — create PROPOSAL-N+1",
					},
				},
			},
			{
				Id:        "asf-ratify",
				Name:      "Ratify",
				Order:     6,
				Execution: "sequential",
				PhaseRef:  protocol.PhaseRatify,
				Actions: []WorkflowAction{
					{
						Id:          "asf-ratify-label",
						Instruction: "Add ratify label to accepted PROPOSAL-N",
					},
					{
						Id:          "asf-ratify-supersede",
						Instruction: "Mark all prior proposals pasture:superseded",
					},
					{
						Id:          "asf-ratify-placeholder",
						Instruction: "Create placeholder IMPL_PLAN task",
					},
				},
				ExitConditions: []ExitCondition{
					{
						Type:      "proceed",
						Condition: "Proposal ratified, IMPL_PLAN placeholder created",
					},
				},
			},
			{
				Id:        "asf-handoff",
				Name:      "Handoff",
				Order:     7,
				Execution: "sequential",
				PhaseRef:  protocol.PhaseHandoff,
				Actions: []WorkflowAction{
					{
						Id:          "asf-handoff-doc",
						Instruction: "Author the HANDOFF in its Beads task body with full inline provenance (include the HANDOFF task ID)",
					},
					{
						Id:          "asf-handoff-transfer",
						Instruction: "Transfer to supervisor via /pasture:architect:handoff",
					},
				},
				ExitConditions: []ExitCondition{
					{
						Type:      "success",
						Condition: "Handoff authored in the HANDOFF Beads task body, supervisor notified",
					},
				},
			},
		},
	},
}

WorkflowSpecs maps workflow IDs to their full specifications. Mirrors Python WORKFLOW_SPECS dict.

Functions

func AppendMarkers

func AppendMarkers(content string) string

AppendMarkers adds the BEGIN/END marker pair to the end of content when content does not already contain the markers.

Historically this was used by --init mode for sub-skill SKILL.md files when GenerateSubSkill ran with dropPrefix=false (preserving a hand-authored H1 heading before BEGIN). Since D5/SLICE-3, sub-skills run with dropPrefix=true: the generator owns the full header (frontmatter + curated H1), so GenerateSubSkill now uses PrependMarkers (mirroring GenerateSkill for roles). AppendMarkers is retained as a public helper for callers that still want append-after-body marker insertion (e.g. appending a generated section below existing hand-authored content).

If content already contains both markers (as reported by HasMarkers), it is returned unchanged to avoid double-appending.

func ConstraintToPhaseRefs

func ConstraintToPhaseRefs() map[string][]protocol.PhaseId

ConstraintToPhaseRefs returns a map from constraint ID to the sorted list of PhaseIds that reference it in phaseConstraints.

This inversion is used by S5 schema generation to emit phase-ref attributes into schema.xml for each constraint element.

func ConstraintToRoleRefs

func ConstraintToRoleRefs() map[string][]types.RoleId

ConstraintToRoleRefs returns a map from constraint ID to the sorted list of RoleIds that reference it in roleConstraints.

This inversion is used by S5 schema generation to emit role-ref attributes into schema.xml for each constraint element.

func ExtractSection

func ExtractSection(markdown []byte, headingTitle string) ([]byte, error)

ExtractSection extracts a section's content by heading title from rendered markdown.

It returns the content under the matching heading, starting after the heading line and extending up to (but not including) the next heading at the same or higher (lower number) level.

Heading-level ambiguity: if the same title appears at H2 and H3, the H2 match is returned (first highest-level match). More generally, when multiple headings share the same title, the one at the shallowest (lowest-numbered) level wins.

Returns an error if no heading with the given title is found.

func FindMarkerPositions

func FindMarkerPositions(lines []string, path string) (begin, end int, err error)

FindMarkerPositions returns the (beginIdx, endIdx) line indices for the BEGIN/END marker pair within lines.

Indices are 0-based into the lines slice. The marker lines themselves are included (i.e., lines[beginIdx] == GeneratedBegin and lines[endIdx] == GeneratedEnd after stripping trailing newlines).

path is used only for error messages and does not affect parsing.

Returns a *MarkerError for each of the 6 failure cases:

  1. Missing both markers — neither BEGIN nor END is present.
  2. Missing BEGIN — END is present but BEGIN is absent.
  3. Missing END — BEGIN is present but END is absent.
  4. Duplicate BEGIN — BEGIN appears more than once.
  5. Duplicate END — END appears more than once.
  6. END before BEGIN — both markers present but in reversed order.

func FragmentToOwnerRefs

func FragmentToOwnerRefs() map[FragmentId][]string

FragmentToOwnerRefs returns a map from FragmentId to the sorted list of skill-dir keys (SkillBodySpecs keys) whose body sections or behaviors reference that fragment via a placement marker.

It mirrors ConstraintToRoleRefs: iterate the consumer-keyed map, invert to fragment-keyed, sort owner slices for deterministic output.

func GenerateAgent

func GenerateAgent(roleId types.RoleId, agentPath string, figuresDir string, opts GenerateOptions) (string, error)

GenerateAgent generates agents/{role}.md for a role.

Only generates for roles that have Tools defined (non-empty slice). If the role has no tools, GenerateAgent returns an empty string and a nil error — the caller should check the returned string before acting on it.

The output file is fully generated — no marker-based partial replacement.

Parameters:

  • roleId: The role to generate for (must be in RoleSpecs).
  • agentPath: Path to write the generated .md file to.
  • figuresDir: Path to the directory containing figure YAML files (e.g. skills/protocol/figures). When non-empty, figure content is loaded from disk and embedded in the output. When empty, figures are rendered as ID + Title references only.
  • opts: Controls diff output and whether to write to disk. Note: opts.Init is not used by GenerateAgent (agents are fully generated).

Returns:

  • The rendered agent definition content (empty string if role has no tools).
  • An error if rendering or file I/O fails.

Error conditions:

  • Role not found in RoleSpecs → error with diagnostic message.
  • Template parse/execution failure → error with template context.
  • Parent directory creation failure → error with OS error.
  • File write failure → error with OS error and path.

func GenerateSchema

func GenerateSchema(w io.Writer) error

GenerateSchema generates schema.xml from canonical Go spec data and writes the result to w.

The output matches the structure of the Python gen_schema.py output:

  • XML declaration with UTF-8 encoding
  • <pasture-protocol version="2.0"> root element
  • All sections with section-divider comments
  • CDATA sections for <code> element content
  • 2-space indentation throughout

Returns an error only if writing to w fails.

func GenerateSchemaToFile

func GenerateSchemaToFile(path string, opts GenerateOptions) (string, error)

GenerateSchemaToFile generates schema.xml, optionally prints a diff if the file already exists and opts.Diff is true, and writes if opts.Write is true.

Returns the generated XML content as a string, and any error encountered during file I/O. Returns an error if:

  • opts.Write is true and the parent directory does not exist or is not writable
  • reading the existing file for diff comparison fails

func GenerateSkill

func GenerateSkill(roleId types.RoleId, skillPath string, figuresDir string, opts GenerateOptions) (string, error)

GenerateSkill generates the SKILL.md for a role and optionally writes it.

It uses a single-pass pipeline: the unified template (skill.go.tmpl) renders ALL content (header + body) inside the BEGIN/END markers. After marker replacement, any content after the END marker is explicitly truncated when a SkillBody entry exists (R3: nothing after END).

ReplaceMarkerRegion is called with dropPrefix=true — the template owns the full frontmatter and heading (everything before BEGIN is dropped and replaced by the rendered template output which starts with YAML frontmatter).

figuresDir is an optional path to the directory containing figure YAML files. When empty, figures will have no content (useful for testing without figure files).

Returns the complete new file content.

Returns a *MarkerError if skillPath is missing the BEGIN/END marker pair (and Init is false), or if the markers are malformed.

func GenerateSubSkill

func GenerateSubSkill(commandId string, skillPath string, figuresDir string, opts GenerateOptions) (string, error)

GenerateSubSkill generates the SKILL.md for a sub-skill command.

It uses a single-pass pipeline: the unified template (skill_sub.go.tmpl) renders ALL content (YAML frontmatter + curated H1 + figures + body) starting with the frontmatter ABOVE the BEGIN marker. After marker replacement, any content after END is truncated when a SkillBody entry exists (R3: nothing after END).

ReplaceMarkerRegion is called with dropPrefix=true — the template owns the full file header (frontmatter + H1), mirroring GenerateSkill for roles. The frontmatter `name` is the sub-skill directory key (so the skill registers as /pasture:<name>) and `description` is CommandSpec.Description; the curated H1 is CommandSpec.Title, captured statically so the hand-authored title is preserved.

figuresDir is an optional path to the directory containing figure YAML files. When empty, figures will have no content (useful for testing without figure files).

Returns the complete new file content.

Returns a *MarkerError if skillPath is missing the BEGIN/END marker pair (and Init is false), or if the markers are malformed.

func HasMarkers

func HasMarkers(content string) bool

HasMarkers returns true if content contains both the BEGIN and END markers.

This is a fast pre-check used by --init mode to decide whether to prepend markers before calling FindMarkerPositions. It does not validate ordering or uniqueness.

func HeadingTextFromAST

func HeadingTextFromAST(n ast.Node, src []byte) string

HeadingTextFromAST extracts the full text of a heading AST node by concatenating its child Text and String segment values.

func ParseXMLNode

func ParseXMLNode(r io.Reader, out *XMLNode) error

ParseXMLNode decodes a single XML document from r into out using the standard xml.Decoder. This is the same decode step used by ValidateSchema and is exported primarily for testing purposes.

func PrependMarkers

func PrependMarkers(content string) string

PrependMarkers adds the BEGIN/END marker pair to the top of content when content does not already contain the markers.

It is used by --init mode for role SKILL.md files (where GenerateSkill uses dropPrefix=true, so the template owns the full heading and frontmatter). The returned string has the markers on the first two lines, followed by a blank line, followed by the original content.

If content already contains both markers (as reported by HasMarkers), it is returned unchanged to avoid double-prepending.

func ReplaceMarkerRegion

func ReplaceMarkerRegion(oldContent, rendered string, dropPrefix bool) (string, error)

ReplaceMarkerRegion replaces the content between (and including) the BEGIN/END markers in oldContent with rendered.

The dropPrefix parameter controls how the content before the BEGIN marker is handled:

  • dropPrefix=true: everything before BEGIN is dropped. The generated content (rendered) owns the full frontmatter and heading. This matches gen_skill behaviour where the template owns the complete file header.

  • dropPrefix=false: everything before BEGIN is preserved. The content before the BEGIN marker (e.g., a hand-authored h1 heading) is kept verbatim. This matches gen_sub_skill behaviour.

In both modes everything after the END marker is preserved — that is the hand-authored body that lives below the generated section.

rendered must already include the BEGIN and END marker lines themselves (as the Python template renders the full BEGIN…END block).

Returns a *MarkerError if oldContent has malformed markers.

func ValidateGlobalIds

func ValidateGlobalIds() error

ValidateGlobalIds validates global ID uniqueness, structural integrity, and AllFragmentIds↔SharedFragmentSpecs parity across all codegen registries. Returns nil on success; returns the first violation as an error on failure.

Validation order (deterministic):

  1. AllFragmentIds ↔ SharedFragmentSpecs parity
  2. SharedFragmentSpecs: exactly-one-payload rule per fragment
  3. Cross-namespace uniqueness: agent → role-behavior → handoff → command → SharedFragmentSpecs → SkillBodySpecs inline IDs
  4. FragRef marker resolution: every marker resolves in SharedFragmentSpecs

func ValidateSkillStructure

func ValidateSkillStructure(markdown []byte) error

ValidateSkillStructure validates the heading hierarchy of generated markdown.

It parses the markdown into an AST via goldmark and checks for:

  • Duplicate H2 titles (same title text at level 2)
  • Orphan H3 headings (H3 that appear before any H2)

Returns nil if the structure is valid. Returns a *SkillStructureError containing all violations found. Returns a plain error if goldmark parsing fails.

Empty or whitespace-only markdown is considered valid (no headings to validate).

Types

type ActionElem

type ActionElem struct {
	Id          string `xml:"id,attr"`
	Instruction string `xml:"instruction,attr"`
	Command     string `xml:"command,attr,omitempty"`
}

ActionElem is <action id="..." instruction="..." .../> inside a stage.

type AxisRefElem

type AxisRefElem struct {
	Ref string `xml:"ref,attr"`
}

AxisRefElem is <axis-ref ref="..."/>.

type BehaviorElem

type BehaviorElem struct {
	Id        string `xml:"id,attr"`
	Given     string `xml:"given,attr"`
	When      string `xml:"when,attr"`
	Then      string `xml:"then,attr"`
	ShouldNot string `xml:"should-not,attr"`
}

BehaviorElem is a single <behavior id="..." given="..." when="..." then="..." should-not="..."/> element.

type BehaviorSpec

type BehaviorSpec struct {
	Id        string
	Given     string
	When      string
	Then      string
	ShouldNot string
	FragRef   FragmentId // non-zero → marker; resolved pre-render from SharedFragmentSpecs
}

BehaviorSpec is a role-tactical behavior in Given/When/Then/Should-Not format. Distinct from ConstraintSpec: behaviors are role-specific guidance, not formal protocol constraints. Mirrors Python BehaviorSpec dataclass.

A non-zero FragRef marks this entry as a placement MARKER: all other fields are left zero and the entry is resolved to the SharedFragment payload pre-render by the resolution pass in skills.go.

type BehaviorsElem

type BehaviorsElem struct {
	Behaviors []BehaviorElem `xml:"behavior"`
}

BehaviorsElem wraps <behaviors>.

type Checklist

type Checklist struct {
	Gate    string // GateType wire value: "completion", "slice-closure", etc.
	RoleRef types.RoleId
	Items   []ChecklistItem
}

Checklist is a completion checklist for a role at a specific quality gate. Keyed in ChecklistSpecs by "{role}-{gate}". Mirrors Python Checklist dataclass.

type ChecklistElem

type ChecklistElem struct {
	Id      string              `xml:"id,attr"`
	RoleRef string              `xml:"role-ref,attr"`
	Gate    string              `xml:"gate,attr"`
	Items   []ChecklistItemElem `xml:"item"`
}

ChecklistElem is a single <checklist id="..." role-ref="..." gate="..."> element.

type ChecklistItem

type ChecklistItem struct {
	Id       string
	Text     string
	Required bool
}

ChecklistItem is a single item in a completion checklist. Mirrors Python ChecklistItem dataclass.

type ChecklistItemElem

type ChecklistItemElem struct {
	Id       string `xml:"id,attr"`
	Required string `xml:"required,attr"`
	Text     string `xml:",chardata"`
}

ChecklistItemElem is an <item id="..." required="...">text</item> element.

type ChecklistsSection

type ChecklistsSection struct {
	XMLName    xml.Name        `xml:"checklists"`
	Checklists []ChecklistElem `xml:"checklist"`
}

ChecklistsSection is the top-level <checklists> element.

type CommandElem

type CommandElem struct {
	Id            string             `xml:"id,attr"`
	Name          string             `xml:"name,attr"`
	RoleRef       string             `xml:"role-ref,attr,omitempty"`
	Description   string             `xml:"description,attr"`
	Phases        *CommandPhasesElem `xml:"phases"`
	CreatesLabels *CreatesLabelsElem `xml:"creates-labels"`
	File          string             `xml:"file"`
	Note          string             `xml:"note,omitempty"`
}

CommandElem is a single <command id="..." name="..." ...> element.

type CommandPhasesElem

type CommandPhasesElem struct {
	PhaseRefs []PhaseRefElem `xml:"phase-ref"`
}

CommandPhasesElem wraps <phases> inside a <command>.

type CommandSpec

type CommandSpec struct {
	Id          string // CommandId wire value e.g. "cmd-worker"
	Name        string // e.g. "pasture:worker"
	Description string
	// Title is the curated H1 heading text for the command's sub-skill SKILL.md
	// (WITHOUT the leading "# "). It is captured statically from each sub-skill's
	// curated on-disk H1 (e.g. "User Acceptance Test (UAT)" for cmd-user-uat) so
	// that the generator can emit YAML frontmatter ABOVE the heading via
	// skill_sub.go.tmpl while PRESERVING the hand-authored title verbatim.
	//
	// Only sub-skill commands (those listed in commandSkillDirs in
	// tools/codegen/main.go) need Title populated; role-level commands
	// (cmd-supervisor, cmd-worker, etc.) render through skill.go.tmpl which
	// derives its H1 from RoleSpec.Name, so their Title is left empty.
	Title         string
	RoleRef       types.RoleId // may be zero value if unassigned
	Phases        []protocol.PhaseId
	File          string   // relative path to skill file
	CreatesLabels []string // label IDs this command creates
}

CommandSpec is the complete specification for a protocol command (skill). Mirrors Python CommandSpec dataclass.

type CommandsSection

type CommandsSection struct {
	XMLName  xml.Name      `xml:"commands"`
	Commands []CommandElem `xml:"command"`
}

CommandsSection is the top-level <commands> element.

type ConstraintContext

type ConstraintContext struct {
	Id        string
	Given     string
	When      string
	Then      string
	ShouldNot string
}

ConstraintContext is a resolved constraint with its Given/When/Then/ShouldNot fields populated from ConstraintSpecs. Used inside RoleContext and PhaseContext.

type ConstraintElem

type ConstraintElem struct {
	Id        string
	Given     string
	When      string
	Then      string
	ShouldNot string
	RoleRef   string
	PhaseRef  string
	Command   string
	Examples  []Example // see Example in specs.go
}

ConstraintElem documents a single <constraint ...> element. NOT used for xml.Marshal.

type ConstraintSpec

type ConstraintSpec struct {
	Id        string
	Given     string
	When      string
	Then      string
	ShouldNot string
	Command   string    // optional primary command to run
	Examples  []Example // optional code examples
}

ConstraintSpec is a single protocol constraint in Given/When/Then/Should-Not format. Mirrors Python ConstraintSpec dataclass.

type ConstraintsSection

type ConstraintsSection struct {
	Constraints []ConstraintElem
}

ConstraintsSection documents the <constraints> element shape. NOT used for xml.Marshal.

type CoordCmdElem

type CoordCmdElem struct {
	Id       string `xml:"id,attr"`
	Action   string `xml:"action,attr"`
	Template string `xml:"template,attr"`
	RoleRef  string `xml:"role-ref,attr,omitempty"`
	Shared   string `xml:"shared,attr,omitempty"`
}

CoordCmdElem is a single <coord-cmd id="..." action="..." template="..." .../> element.

type CoordinationCommand

type CoordinationCommand struct {
	Id       string
	Action   string
	Template string
	RoleRef  types.RoleId // zero value means shared across all roles
	Shared   bool
}

CoordinationCommand is a coordination command for inter-agent communication via Beads. Mirrors Python CoordinationCommand dataclass.

type CoordinationCommandsSection

type CoordinationCommandsSection struct {
	XMLName  xml.Name       `xml:"coordination-commands"`
	Commands []CoordCmdElem `xml:"coord-cmd"`
}

CoordinationCommandsSection is the top-level <coordination-commands> element.

type CoverEntityElem

type CoverEntityElem struct {
	Type  string `xml:"type,attr"`
	Depth string `xml:"depth,attr"`
	Refs  string `xml:"refs,attr,omitempty"`
	Note  string `xml:"note,attr,omitempty"`
}

CoverEntityElem is <entity type="..." depth="..." .../> inside <covers>.

type CoversElem

type CoversElem struct {
	Entities []CoverEntityElem `xml:"entity"`
}

CoversElem wraps <covers>.

type CreatesLabelsElem

type CreatesLabelsElem struct {
	LabelRefs []LabelRefElem `xml:"label-ref"`
}

CreatesLabelsElem wraps <creates-labels>.

type DelegateElem

type DelegateElem struct {
	ToRole string `xml:"to-role,attr"`
	Phases string `xml:"phases,attr"`
}

DelegateElem is <delegate to-role="..." phases="..."/>.

type DelegatesElem

type DelegatesElem struct {
	Delegates []DelegateElem `xml:"delegate"`
}

DelegatesElem wraps <delegates>.

type DepChainElem

type DepChainElem struct {
	Note  string             `xml:"note,attr"`
	Steps []DepChainStepElem `xml:"step"`
}

DepChainElem is <dependency-chain note="...">.

type DepChainStepElem

type DepChainStepElem struct {
	TaskTitle   string `xml:"task-title,attr"`
	PhaseRef    string `xml:"phase-ref,attr"`
	Description string `xml:"description,attr"`
}

DepChainStepElem is <step task-title="..." phase-ref="..." description="..."/>.

type DependencyModelSection

type DependencyModelSection struct {
	XMLName        xml.Name            `xml:"dependency-model"`
	Rule           string              `xml:"rule"`
	CanonicalChain string              `xml:"canonical-chain"`
	Command        string              `xml:"command"`
	AntiPattern    string              `xml:"anti-pattern"`
	ReferenceLinks *ReferenceLinksElem `xml:"reference-links"`
}

DependencyModelSection is the top-level <dependency-model> element. Content is mixed text/element — kept as raw text since it uses free-form prose and nested elements with no fixed structure.

type DocumentElem

type DocumentElem struct {
	Id      string      `xml:"id,attr"`
	Path    string      `xml:"path,attr"`
	Purpose string      `xml:"purpose,attr"`
	Covers  *CoversElem `xml:"covers"`
}

DocumentElem is a single <document id="..." path="..." purpose="..."> element.

type DocumentsSection

type DocumentsSection struct {
	XMLName   xml.Name       `xml:"documents"`
	Documents []DocumentElem `xml:"document"`
}

DocumentsSection is the top-level <documents> element.

type EnumType

type EnumType struct {
	Name   string      `xml:"name,attr"`
	Values []EnumValue `xml:"value"`
}

EnumType is a single <enum name="..."> element containing values.

type EnumValue

type EnumValue struct {
	Id          string `xml:"id,attr"`
	Description string `xml:"description,attr"`
	// Optional attrs present on SeverityLevel values only.
	Blocks string `xml:"blocks,attr,omitempty"`
	Label  string `xml:"label,attr,omitempty"`
}

EnumValue is a single <value id="..." .../> element inside an <enum>.

type EnumsSection

type EnumsSection struct {
	XMLName xml.Name   `xml:"enums"`
	Enums   []EnumType `xml:"enum"`
}

EnumsSection is the top-level <enums> element.

type ErrorLayer

type ErrorLayer string

ErrorLayer categorizes validation errors by their detection layer. Values match the Python ErrorLayer enum wire values.

const (
	// LayerStructural covers missing required attributes, duplicate IDs,
	// and malformed XML.
	LayerStructural ErrorLayer = "Structural"

	// LayerReferential covers references (phase-ref, role-ref, etc.) that
	// point to IDs not defined elsewhere in the document.
	LayerReferential ErrorLayer = "Referential Integrity"

	// LayerSemantic covers logical inconsistencies such as out-of-order
	// phase numbers, duplicate axis letters, or invalid enum values.
	LayerSemantic ErrorLayer = "Semantic"
)

type Example

type Example struct {
	Id              string
	Lang            string // ExampleLang wire value: "bash", "go", "python", etc.
	Label           string // ExampleLabel wire value: "correct", "anti-pattern", etc.
	Code            string
	AlsoIllustrates string // optional cross-reference to another constraint
}

Example is a labeled code example for a constraint or procedure step. Mirrors Python CodeExample dataclass.

type ExampleElem

type ExampleElem struct {
	Id              string `xml:"id,attr"`
	Lang            string `xml:"lang,attr"`
	Label           string `xml:"label,attr"`
	AlsoIllustrates string `xml:"also-illustrates,attr,omitempty"`
}

ExampleElem is an <example id="..." lang="..." label="..."> element. The <code> child contains CDATA and is handled by manual fmt.Fprintf.

type ExitCondElem

type ExitCondElem struct {
	Type      string `xml:"type,attr"`
	Condition string `xml:"condition,attr"`
}

ExitCondElem is <exit-condition type="..." condition="..."/> inside a stage.

type ExitCondition

type ExitCondition struct {
	Type      string // ExitConditionType: "success", "continue", "escalate", "proceed"
	Condition string
}

ExitCondition is an exit condition for a workflow stage. Type must be one of the ExitConditionType wire values. Mirrors Python ExitCondition dataclass.

type ExtraLabelElem

type ExtraLabelElem struct {
	Ref string `xml:"ref,attr"`
}

ExtraLabelElem is <extra-label ref="..."/>.

type FigureElem

type FigureElem struct {
	Id           string    `xml:"id,attr"`
	Title        string    `xml:"title,attr"`
	Type         string    `xml:"type,attr"`
	SectionRef   string    `xml:"section-ref,attr"`
	RoleRefs     []RefElem `xml:"role-ref"`
	WorkflowRefs []RefElem `xml:"workflow-ref"`
	CommandRefs  []RefElem `xml:"command-ref"`
}

FigureElem is a single <figure id="..." title="..." type="..." section-ref="..."> element.

type FigureSpec

type FigureSpec struct {
	Id           string // FigureId wire value
	Title        string
	Type         string // FigureType wire value: "ascii-diagram"
	RoleRefs     []types.RoleId
	SectionRef   string // SectionRef wire value: "workflows"
	WorkflowRefs []string
	CommandRefs  []string
	Content      string // loaded at generation time
}

FigureSpec is a figure specification (ASCII diagram or other visual). Mirrors Python Figure dataclass.

type FiguresSection

type FiguresSection struct {
	XMLName xml.Name     `xml:"figures"`
	Figures []FigureElem `xml:"figure"`
}

FiguresSection is the top-level <figures> element.

type FollowupEpicElem

type FollowupEpicElem struct {
	LabelRef       string `xml:"label-ref,attr"`
	Trigger        string `xml:"trigger,attr"`
	GatedOnBlocker string `xml:"gated-on-blocker,attr"`
	OwnerRole      string `xml:"owner-role,attr"`
}

FollowupEpicElem is <followup-epic label-ref="..." trigger="..." .../>.

type FollowupLifecycleSection

type FollowupLifecycleSection struct {
	XMLName          xml.Name           `xml:"followup-lifecycle"`
	Trigger          string             `xml:"trigger"`
	OwnerRole        string             `xml:"owner-role"`
	GatedOnBlocker   string             `xml:"gated-on-blocker"`
	DependencyChain  *DepChainElem      `xml:"dependency-chain"`
	LeafTaskAdoption *LeafTaskAdoptElem `xml:"leaf-task-adoption"`
	References       *FollowupRefsElem  `xml:"references"`
	HandoffChain     *HandoffChainElem  `xml:"handoff-chain"`
}

FollowupLifecycleSection is the top-level <followup-lifecycle> element.

type FollowupRefElem

type FollowupRefElem struct {
	Type   string `xml:"type,attr"`
	Target string `xml:"target,attr"`
	Note   string `xml:"note,attr"`
}

FollowupRefElem is <ref type="..." target="..." note="..."/>.

type FollowupRefsElem

type FollowupRefsElem struct {
	Refs []FollowupRefElem `xml:"ref"`
}

FollowupRefsElem wraps <references> in followup-lifecycle.

type FragmentId

type FragmentId string

FragmentId is the strongly-typed key for shared fragment registrations. Values match the frag--* canonical naming convention (e.g. "frag--rev-vote-options"). PascalCase constants are derived by dropping the "frag--" prefix, splitting on "-", and prefixing with "Frag".

Mirrors the RoleId / PhaseId / CommandId convention.

const (
	// FragRevVoteOptions is the canonical vote-options table shared between the
	// reviewer and reviewer-vote skill bodies (D3-ratified ACCEPT row wording).
	FragRevVoteOptions FragmentId = "frag--rev-vote-options"

	// FragSupReviewAllSlices is the canonical "spawn 3 reviewers for ALL slices"
	// behavior shared between the supervisor and impl-review skill bodies.
	FragSupReviewAllSlices FragmentId = "frag--sup-review-all-slices"

	// FragSupReviewCheckEach is the canonical "check each slice against criteria"
	// behavior shared between the supervisor and impl-review skill bodies.
	FragSupReviewCheckEach FragmentId = "frag--sup-review-check-each"

	// FragSupReviewSeverityGroups is the canonical "ALWAYS create 3 severity groups"
	// behavior shared between the supervisor and impl-review skill bodies.
	FragSupReviewSeverityGroups FragmentId = "frag--sup-review-severity-groups"

	// FragSupBlockerDualParent is the canonical "dual-parent: blocks BOTH severity
	// group AND slice" behavior shared between the supervisor and impl-review skill
	// bodies.
	FragSupBlockerDualParent FragmentId = "frag--sup-blocker-dual-parent"

	// FragSupDeferredFollowup is the canonical "route ONLY user-DEFER'd UAT items
	// to the FOLLOWUP epic; all review severities must reach 0 before wave close"
	// behavior shared between the supervisor and impl-review skill bodies.
	// (Renamed from FragSupImportantMinorFollowup per R7/A1: review severities are
	// no longer deferrable; the FOLLOWUP epic is fed solely by DEFER'd UAT items.)
	FragSupDeferredFollowup FragmentId = "frag--sup-deferred-followup"

	// FragSupFollowupEpicTiming is the canonical "supervisor creates EPIC_FOLLOWUP
	// immediately" behavior shared between the supervisor and impl-review skill
	// bodies.
	FragSupFollowupEpicTiming FragmentId = "frag--sup-followup-epic-timing"

	// FragSupSeverityTree is the canonical Severity Tree (EAGER Creation) prose
	// section shared between the supervisor and impl-review skill bodies.
	FragSupSeverityTree FragmentId = "frag--sup-severity-tree"

	// FragSupNamingConvention is the canonical Naming Convention prose section
	// (SLICE-{N}-REVIEW-{axis}-{round} format) shared between the supervisor and
	// impl-review skill bodies.
	FragSupNamingConvention FragmentId = "frag--sup-naming-convention"

	// FragRevPlanVoteOptions is the vote-options table for PLAN reviews (Phase 3
	// architect-request-review). DISTINCT from FragRevVoteOptions (code review)
	// by its final line: "Binary only. No severity tree for plan reviews."
	// (vs code review's "Binary only. No intermediate levels."); the ACCEPT-row
	// wording is shared (unified per UAT-2). Single-owner (reviewer-review-plan),
	// but promoted to a fragment for registry completeness and D2 distinctness
	// enforcement.
	FragRevPlanVoteOptions FragmentId = "frag--rev-plan-vote-options"

	// FragValidationCases is the canonical "elicit/confirm/evaluate concrete
	// validation cases for EVERY REQUEST — a definition of done plus correct and
	// incorrect behaviours, user-confirmed, with failing real-data cases stored as
	// test fixtures" behavior (R6/A2, generalized from fix-intent-only at v2-2).
	// Referenced via behaviorRef from the user-elicit, user-uat, and
	// worker-implement skill bodies (wired in SLICE-2).
	FragValidationCases FragmentId = "frag--validation-cases"

	// FragReviewCleanExit is the canonical "iterate review->fix->re-review up to the
	// chosen review-effort budget; clean = 0 BLOCKER + 0 IMPORTANT + 0 MINOR within
	// budget; on budget exhaustion without clean, surface outstanding findings to
	// the user at a gate" behavior (R7/A1, reworked to a configurable budget at
	// v2-2). Referenced via behaviorRef from the supervisor and impl-review skill
	// bodies (wired in SLICE-3).
	FragReviewCleanExit FragmentId = "frag--review-clean-exit"
)

type FragmentKind

type FragmentKind string

FragmentKind identifies the payload type stored in a SharedFragment.

const (
	// FragmentKindBehavior indicates the fragment holds a *BehaviorSpec payload.
	FragmentKindBehavior FragmentKind = "behavior"

	// FragmentKindProse indicates the fragment holds a *ProseSection payload.
	FragmentKindProse FragmentKind = "prose"
)

type FragmentParityError

type FragmentParityError struct {
	// OrphanConstant is non-empty when a FragmentId constant has no matching
	// SharedFragmentSpecs entry.
	OrphanConstant FragmentId

	// OrphanSpec is non-empty when a SharedFragmentSpecs key has no matching
	// FragmentId constant in AllFragmentIds.
	OrphanSpec FragmentId
}

FragmentParityError describes a mismatch between AllFragmentIds (the declared typed constants) and the keys of SharedFragmentSpecs.

func (*FragmentParityError) Error

func (e *FragmentParityError) Error() string

Error returns an actionable message.

type GenerateOptions

type GenerateOptions struct {
	// Diff prints a unified diff of old vs new content to stdout (default: true).
	Diff bool

	// Write writes the new content to the skill file (default: true).
	Write bool

	// Init prepends BEGIN/END markers to files that lack them before generating.
	// When false (default), missing markers return a *MarkerError.
	Init bool
}

GenerateOptions controls the behaviour of GenerateSkill and GenerateSubSkill.

type HandoffChainElem

type HandoffChainElem struct {
	Note        string                  `xml:"note,attr"`
	Transitions []HandoffChainTransElem `xml:"transition"`
}

HandoffChainElem is <handoff-chain note="...">.

type HandoffChainTransElem

type HandoffChainTransElem struct {
	Order       string `xml:"order,attr"`
	HandoffRef  string `xml:"handoff-ref,attr"`
	Description string `xml:"description,attr"`
	SameActor   string `xml:"same-actor,attr,omitempty"`
}

HandoffChainTransElem is <transition order="..." handoff-ref="..." description="..." .../>.

type HandoffElem

type HandoffElem struct {
	Id              string               `xml:"id,attr"`
	SourceRole      string               `xml:"source-role,attr"`
	TargetRole      string               `xml:"target-role,attr"`
	AtPhase         string               `xml:"at-phase,attr"`
	ContentLevel    string               `xml:"content-level,attr"`
	FilePattern     string               `xml:"file-pattern,attr,omitempty"`
	Trigger         string               `xml:"trigger,attr,omitempty"`
	Context         string               `xml:"context,attr,omitempty"`
	RequiredFields  *RequiredFieldsElem  `xml:"required-fields"`
	SkillInvocation *SkillInvocationElem `xml:"skill-invocation"`
	Note            *HandoffNoteElem     `xml:"note"`
}

HandoffElem is a single <handoff id="..." ...> element.

type HandoffNoteElem

type HandoffNoteElem struct {
	Text string `xml:",chardata"`
}

HandoffNoteElem wraps <note> text content in a handoff.

type HandoffSpec

type HandoffSpec struct {
	Id             string
	SourceRole     types.RoleId
	TargetRole     types.RoleId
	AtPhase        protocol.PhaseId
	ContentLevel   string // ContentLevel wire value: "full-provenance", "summary-with-ids"
	RequiredFields []string
}

HandoffSpec specifies an actor-change transition handoff document. Mirrors Python HandoffSpec dataclass.

type HandoffsSection

type HandoffsSection struct {
	XMLName              xml.Name                  `xml:"handoffs"`
	StoragePattern       string                    `xml:"storage-pattern,attr"`
	Handoffs             []HandoffElem             `xml:"handoff"`
	SameActorTransitions *SameActorTransitionsElem `xml:"same-actor-transitions"`
}

HandoffsSection is the top-level <handoffs storage-pattern="..."> element.

type IDCollision

type IDCollision struct {
	// Id is the duplicate identifier string (e.g. "rev-vote-options").
	Id string

	// Namespace identifies which registry the collision spans
	// (e.g. "SkillBodySpecs inline", "SharedFragmentSpecs", "role-behavior").
	Namespace string

	// LocationA is the first occurrence description (registry/skill-dir).
	LocationA string

	// LocationB is the second occurrence description.
	LocationB string
}

IDCollision describes a global-ID uniqueness violation: the same string ID appears in two distinct locations across the codegen registries.

All fields are always populated so the error message is self-contained.

func (*IDCollision) Error

func (e *IDCollision) Error() string

Error returns an actionable message: what/why/where/when/meaning/fix.

type InstancesElem

type InstancesElem struct {
	Count string `xml:"count,attr"`
	Per   string `xml:"per,attr"`
}

InstancesElem is <instances count="..." per="..."/>.

type InvalidFragment

type InvalidFragment struct {
	// FragRef is the offending fragment's map key.
	FragRef FragmentId

	// Reason describes the specific violation.
	Reason string
}

InvalidFragment describes a SharedFragmentSpecs entry that violates the exactly-one-payload rule (must have Prose XOR Behavior, never both/neither).

func (*InvalidFragment) Error

func (e *InvalidFragment) Error() string

Error returns an actionable message.

type InvariantsElem

type InvariantsElem struct {
	Invariants []string `xml:"invariant"`
}

InvariantsElem wraps <invariants>.

type KeyQuestionsElem

type KeyQuestionsElem struct {
	Questions []string `xml:"q"`
}

KeyQuestionsElem wraps <key-questions><q>...</q></key-questions>.

type LabelElem

type LabelElem struct {
	Id          string `xml:"id,attr"`
	Value       string `xml:"value,attr"`
	Special     string `xml:"special,attr,omitempty"`
	PhaseRef    string `xml:"phase-ref,attr,omitempty"`
	SubstepRef  string `xml:"substep-ref,attr,omitempty"`
	SeverityRef string `xml:"severity-ref,attr,omitempty"`
	Description string `xml:"description,attr,omitempty"`
}

LabelElem is a single <label .../> element.

type LabelRefElem

type LabelRefElem struct {
	Ref string `xml:"ref,attr"`
}

LabelRefElem is <label-ref ref="..."/>.

type LabelSpec

type LabelSpec struct {
	Id          string
	Value       string // the actual label string e.g. "pasture:p9-impl:s9-slice"
	Special     bool
	PhaseRef    string // optional phase reference
	SubstepRef  string // optional substep reference
	SeverityRef string // optional severity reference
	Description string // optional description
}

LabelSpec is the complete specification for a protocol label. Mirrors Python LabelSpec dataclass.

type LabelsSection

type LabelsSection struct {
	XMLName xml.Name    `xml:"labels"`
	Labels  []LabelElem `xml:"label"`
}

LabelsSection is the top-level <labels> element.

type LeafTaskAdoptElem

type LeafTaskAdoptElem struct {
	Rule    string `xml:"rule"`
	Command string `xml:"command"`
	Note    string `xml:"note"`
}

LeafTaskAdoptElem is <leaf-task-adoption>.

type MarkerError

type MarkerError struct {
	// Path is the file path where the marker problem was found.
	Path string

	// Problem is a short description of what went wrong.
	// Examples: "missing both markers", "duplicate BEGIN", "END before BEGIN".
	Problem string

	// Line is the 1-based line number of the offending marker, or 0 when
	// the problem is not associated with a specific line (e.g., both markers
	// missing).
	Line int

	// Fix is an actionable remediation message that tells the user exactly
	// what to do to resolve the problem.
	Fix string
}

MarkerError is a typed error for marker validation failures.

It contains actionable diagnostic information: what went wrong, where it failed (file path and line number), and how to fix it. Using a dedicated type instead of fmt.Errorf allows callers to assert on the specific failure kind without string parsing.

func (*MarkerError) Error

func (e *MarkerError) Error() string

Error implements the error interface.

The message follows the actionable-error convention:

(1) what went wrong   — Problem field
(2) where it failed   — Path + Line
(3) how to fix it     — Fix field

type OwnedPhasesElem

type OwnedPhasesElem struct {
	PhaseRefs []PhaseRefElem `xml:"phase-ref"`
}

OwnedPhasesElem wraps <owns-phases>.

type PhaseContext

type PhaseContext struct {
	Phase       protocol.PhaseId
	Constraints []ConstraintContext
	Labels      []string
	Transitions []Transition
}

PhaseContext is the context injection fragment for a specific protocol phase. Populated by GetPhaseContext and used by prompt construction to embed phase-appropriate constraints, labels, and valid transitions.

func GetPhaseContext

func GetPhaseContext(phase protocol.PhaseId) PhaseContext

GetPhaseContext returns the context injection fragment for the given protocol phase.

It populates PhaseContext with:

  • Constraints: resolved ConstraintContext objects from phaseConstraints[phase]
  • Labels: label values from LabelSpecs where PhaseRef matches phase's p-number
  • Transitions: valid transitions from PhaseSpecs[phase]

Panics if any constraint ID in phaseConstraints[phase] is not found in ConstraintSpecs. This is a programming error (stale mapping) that must be fixed in the source, not handled at runtime.

type PhaseElem

type PhaseElem struct {
	Id          string           `xml:"id,attr"`
	Number      string           `xml:"number,attr"`
	Domain      string           `xml:"domain,attr"`
	Name        string           `xml:"name,attr"`
	Description string           `xml:"description"`
	Substeps    *SubstepsElem    `xml:"substeps"`
	TaskTitles  []TaskTitleElem  `xml:"task-title"`
	Transitions *TransitionsElem `xml:"transitions"`
	// Optional special elements (present on specific phases only).
	SeverityTree *SeverityTreeElem `xml:"severity-tree"`
	SameActorAs  *SameActorAsElem  `xml:"same-actor-as"`
	TDDLayers    *TDDLayersElem    `xml:"tdd-layers"`
	FollowupEpic *FollowupEpicElem `xml:"followup-epic"`
}

PhaseElem is a single <phase id="..." number="..." domain="..." name="..."> element.

type PhaseRefElem

type PhaseRefElem struct {
	Ref string `xml:"ref,attr"`
}

PhaseRefElem is <phase-ref ref="..."/>.

type PhaseSpec

type PhaseSpec struct {
	Id          protocol.PhaseId
	Name        string
	Number      int
	Domain      types.Domain
	OwnerRoles  []types.RoleId
	Transitions []Transition
}

PhaseSpec is the complete specification for a single protocol phase. Mirrors Python PhaseSpec dataclass.

type PhasesSection

type PhasesSection struct {
	XMLName xml.Name    `xml:"phases"`
	Phases  []PhaseElem `xml:"phase"`
}

PhasesSection is the top-level <phases> element.

type ProcedureRoleGroup

type ProcedureRoleGroup struct {
	Ref   string
	Steps []ProcedureStepElem
}

ProcedureRoleGroup is a <role ref="..."> grouping inside <procedure-steps>. NOT used for xml.Marshal.

type ProcedureStep

type ProcedureStep struct {
	Id          string
	Order       int
	Instruction string
	Command     string           // optional exact shell/bd command
	Context     string           // optional situational context
	NextState   protocol.PhaseId // optional phase transition
	Examples    []Example
}

ProcedureStep is a single step in a role's startup or operational procedure. Mirrors Python ProcedureStep dataclass.

type ProcedureStepElem

type ProcedureStepElem struct {
	Order       string `xml:"order,attr"`
	Id          string `xml:"id,attr"`
	NextState   string `xml:"next-state,attr,omitempty"`
	Instruction string `xml:"instruction"`
	Command     string `xml:"command,omitempty"`
	Context     string `xml:"context,omitempty"`
	// Examples contain CDATA — defined here for completeness but built manually.
	Examples []ExampleElem `xml:"example"`
}

ProcedureStepElem is a <step order="..." id="..." ...> element used in both startup-sequence and procedure-steps sections.

type ProcedureStepsSection

type ProcedureStepsSection struct {
	RoleGroups []ProcedureRoleGroup
}

ProcedureStepsSection documents the <procedure-steps> element shape. NOT used for xml.Marshal.

type ProseSection

type ProseSection struct {
	Id          string         // unique within skill body; not used during template rendering — available for programmatic lookup via ExtractSection or future ID-based access
	Title       string         // heading text, e.g. "What You Own"
	Content     string         // pre-formatted markdown content below the heading
	Subsections []ProseSection // optional nested sections (rendered as H3 under H2)
	FragRef     FragmentId     // non-zero → marker; resolved pre-render from SharedFragmentSpecs
}

ProseSection is a titled block of markdown content for skill body rendering. Sections are rendered in slice order. Heading level is determined by the template (H2 for top-level, H3 for subsections).

A non-zero FragRef marks this entry as a placement MARKER: all other fields are left zero and the entry is resolved to the SharedFragment payload pre-render by the resolution pass in skills.go.

type RecipeBlock

type RecipeBlock struct {
	Id          string // unique within skill body; not used during template rendering — available for programmatic lookup
	Title       string // e.g. "Phase 1: REQUEST Task"
	Description string // context paragraph before the code block
	Lang        string // code block language, typically "bash"
	Code        string // the actual bd command template
}

RecipeBlock is a bd command recipe with context and code example.

type RefElem

type RefElem struct {
	Ref string `xml:"ref,attr"`
}

RefElem is a generic <*-ref ref="..."/> element used within a figure. encoding/xml resolves the element tag name from the slice field struct tag in FigureElem (role-ref, workflow-ref, or command-ref), so a single type serves all three reference collections.

type ReferenceLinksElem

type ReferenceLinksElem struct {
	Note    string `xml:"note,attr"`
	Pattern string `xml:"pattern"`
}

ReferenceLinksElem is the <reference-links note="..."> element.

type RequiredFieldsElem

type RequiredFieldsElem struct {
	Text string `xml:",chardata"`
}

RequiredFieldsElem wraps <required-fields> text content.

type ReviewAxesSection

type ReviewAxesSection struct {
	XMLName xml.Name         `xml:"review-axes"`
	Axes    []ReviewAxisElem `xml:"axis"`
}

ReviewAxesSection is the top-level <review-axes> element.

type ReviewAxisElem

type ReviewAxisElem struct {
	Id           string            `xml:"id,attr"`
	Letter       string            `xml:"letter,attr"`
	Name         string            `xml:"name,attr"`
	Short        string            `xml:"short,attr"`
	KeyQuestions *KeyQuestionsElem `xml:"key-questions"`
}

ReviewAxisElem is a single <axis ...> element.

type ReviewAxisSpec

type ReviewAxisSpec struct {
	Id           string
	Letter       string // ReviewAxis wire value: "correctness", "test_quality", "elegance"
	Name         string
	Short        string
	KeyQuestions []string
}

ReviewAxisSpec is the complete specification for a code review axis. Mirrors Python ReviewAxisSpec dataclass.

type RoleContext

type RoleContext struct {
	Role                 types.RoleId
	Phases               []protocol.PhaseId
	Constraints          []ConstraintContext
	Commands             []string
	Handoffs             []string
	Introduction         string
	OwnershipNarrative   string
	Behaviors            []BehaviorSpec
	Checklists           []Checklist
	CoordinationCommands []CoordinationCommand
	Workflows            []Workflow
	ReviewAxes           []ReviewAxisSpec
	Figures              []FigureSpec
}

RoleContext is the context injection fragment for a specific agent role. Populated by GetRoleContext and used by prompt construction to embed role-appropriate constraints, phases, commands, and handoffs.

func GetRoleContext

func GetRoleContext(role types.RoleId) RoleContext

GetRoleContext returns the context injection fragment for the given agent role.

It populates RoleContext with:

  • Phases: phases where this role is an owner role (inverted from PhaseSpecs)
  • Constraints: resolved ConstraintContext objects from roleConstraints[role]
  • Commands: command names from CommandSpecs where RoleRef == role
  • Handoffs: handoff IDs from HandoffSpecs where role is source or target
  • Introduction: from RoleSpecs[role].Introduction
  • OwnershipNarrative: from RoleSpecs[role].OwnershipNarrative
  • Behaviors: from RoleSpecs[role].Behaviors
  • Checklists: from ChecklistSpecs where RoleRef == role
  • CoordinationCommands: role-specific + shared from CoordinationCommands
  • Workflows: from WorkflowSpecs where RoleRef == role
  • ReviewAxes: from ReviewAxisSpecs (reviewer only; empty for all others)
  • Figures: from FigureSpecs where role in RoleRefs

Panics if any constraint ID in roleConstraints[role] is not found in ConstraintSpecs. This is a programming error (stale mapping) that must be fixed in the source, not handled at runtime.

type RoleElem

type RoleElem struct {
	Id                 string           `xml:"id,attr"`
	Name               string           `xml:"name,attr"`
	Description        string           `xml:"description,attr"`
	OwnedPhases        *OwnedPhasesElem `xml:"owns-phases"`
	Delegates          *DelegatesElem   `xml:"delegates"`
	LabelAwareness     string           `xml:"label-awareness"`
	UsesAxes           *UsesAxesElem    `xml:"uses-axes"`
	Invariants         *InvariantsElem  `xml:"invariants"`
	Tools              string           `xml:"tools"`
	Model              string           `xml:"model"`
	Thinking           string           `xml:"thinking"`
	OwnershipModel     string           `xml:"ownership-model"`
	Introduction       string           `xml:"introduction"`
	OwnershipNarrative string           `xml:"ownership-narrative"`
	Behaviors          *BehaviorsElem   `xml:"behaviors"`
}

RoleElem is a single <role id="..." name="..." description="..."> element.

type RoleSpec

type RoleSpec struct {
	Id                 types.RoleId
	Name               string
	Description        string
	Model              string // e.g. "opus", "sonnet", "haiku"
	Thinking           string // e.g. "medium"
	Tools              []string
	OwnedPhases        []protocol.PhaseId
	Introduction       string
	OwnershipNarrative string
	Behaviors          []BehaviorSpec
}

RoleSpec is the complete specification for an agent role. Mirrors Python RoleSpec dataclass.

type RolesSection

type RolesSection struct {
	XMLName xml.Name   `xml:"roles"`
	Roles   []RoleElem `xml:"role"`
}

RolesSection is the top-level <roles> element.

type SameActorAsElem

type SameActorAsElem struct {
	PhaseRef string `xml:"phase-ref,attr"`
	Note     string `xml:"note,attr"`
}

SameActorAsElem is <same-actor-as phase-ref="..." note="..."/>.

type SameActorTransitionElem

type SameActorTransitionElem struct {
	FromPhase string `xml:"from-phase,attr"`
	ToPhase   string `xml:"to-phase,attr"`
	Actor     string `xml:"actor,attr"`
}

SameActorTransitionElem is <transition from-phase="..." to-phase="..." actor="..."/>.

type SameActorTransitionsElem

type SameActorTransitionsElem struct {
	Note        string                    `xml:"note,attr"`
	Transitions []SameActorTransitionElem `xml:"transition"`
}

SameActorTransitionsElem wraps <same-actor-transitions>.

type SchemaIndex

type SchemaIndex struct {
	PhaseIds      map[string]bool
	SubstepIDs    map[string]bool
	LabelIDs      map[string]bool
	RoleIds       map[string]bool
	CommandIds    map[string]bool
	AxisIDs       map[string]bool
	HandoffIDs    map[string]bool
	ConstraintIDs map[string]bool
	DocumentIDs   map[string]bool
	TeamIDs       map[string]bool
	WorkflowIDs   map[string]bool
	SeverityIDs   map[string]bool

	// EnumValueIDs maps enum name → set of value IDs defined within it.
	EnumValueIDs map[string]map[string]bool

	// PhaseNumbers maps phase_id → numeric order (e.g. "p1" → 1).
	PhaseNumbers map[string]int

	// PhaseDomains maps phase_id → domain string (e.g. "p1" → "user").
	PhaseDomains map[string]string

	// PhaseSubstepOrders maps phase_id → ordered list of substep entries.
	PhaseSubstepOrders map[string][]SubstepOrderEntry

	// LabelValues maps label_id → value string (e.g. "L-p1s1_1" → "pasture:p1-user:s1_1-request").
	LabelValues map[string]string

	// AxisLetters maps axis_id → letter string (e.g. "axis-correctness" → "A").
	AxisLetters map[string]string

	// RolePhaseRefs maps role_id → set of phase_ids that role owns.
	RolePhaseRefs map[string]map[string]bool

	// StartupStepOrders maps substep_id → slice of step order values found
	// inside that substep's <startup-sequence>.
	StartupStepOrders map[string][]int
}

SchemaIndex holds all IDs and metadata extracted during structural validation. It is populated by buildIndex and consumed by checkRefs and checkSemantics. Mirrors the Python SchemaIndex dataclass.

type SevGroupElem

type SevGroupElem struct {
	SeverityRef string `xml:"severity-ref,attr"`
	LabelRef    string `xml:"label-ref,attr"`
	DualParent  string `xml:"dual-parent,attr,omitempty"`
}

SevGroupElem is a <group severity-ref="..." label-ref="..." .../> element.

type SeverityTreeElem

type SeverityTreeElem struct {
	Enabled  string         `xml:"enabled,attr"`
	Creation string         `xml:"creation,attr,omitempty"`
	Reason   string         `xml:"reason,attr,omitempty"`
	Rules    []string       `xml:"rule"`
	Groups   []SevGroupElem `xml:"group"`
}

SeverityTreeElem is the <severity-tree ...> element.

type SharedFragment

type SharedFragment struct {
	Id       FragmentId
	Kind     FragmentKind
	Behavior *BehaviorSpec // non-nil when Kind == FragmentKindBehavior
	Prose    *ProseSection // non-nil when Kind == FragmentKindProse
}

SharedFragment is a reusable payload (either a BehaviorSpec or a ProseSection) stored in SharedFragmentSpecs and referenced by placement markers in SkillBody entries.

Exactly one of Behavior or Prose must be non-nil. Owners are not stored directly — they are derived via FragmentToOwnerRefs() (D1: owners derived from consumer markers, not embedded).

type SkillBody

type SkillBody struct {
	Preamble  string         // optional intro (e.g., PROCESS.md link)
	Sections  []ProseSection // ordered prose sections (rendered as H2)
	Recipes   []RecipeBlock  // ordered code recipes
	Behaviors []BehaviorSpec // body-specific G/W/T behaviors (NOT ConstraintSpec)
}

SkillBody is the complete body content for a role or sub-skill. Rendered inside the BEGIN/END marker region by the unified skill.go.tmpl and skill_sub.go.tmpl templates.

type SkillInvocationElem

type SkillInvocationElem struct {
	TargetRole string `xml:"target-role,attr,omitempty"`
	CommandRef string `xml:"command-ref,attr,omitempty"`
	Directive  string `xml:"directive,attr"`
	Note       string `xml:"note,attr,omitempty"`
}

SkillInvocationElem is <skill-invocation target-role="..." command-ref="..." directive="..."/>. target-role and command-ref are omitempty so they can be omitted when only directive (and optionally note) are needed (e.g., in handoff skill-invocation elements).

type SkillStructureError

type SkillStructureError struct {
	// Problems is a list of structural violations found.
	Problems []string
}

SkillStructureError describes a structural problem in a generated SKILL.md.

func (*SkillStructureError) Error

func (e *SkillStructureError) Error() string

Error implements the error interface.

type StageElem

type StageElem struct {
	Id             string         `xml:"id,attr"`
	Name           string         `xml:"name,attr"`
	Order          string         `xml:"order,attr"`
	Execution      string         `xml:"execution,attr"`
	PhaseRef       string         `xml:"phase-ref,attr,omitempty"`
	Actions        []ActionElem   `xml:"action"`
	ExitConditions []ExitCondElem `xml:"exit-condition"`
}

StageElem is a single <stage id="..." name="..." order="..." execution="..." ...> element.

type StartupSequenceElem

type StartupSequenceElem struct {
	Steps []ProcedureStepElem `xml:"step"`
}

StartupSequenceElem wraps <startup-sequence> containing procedure steps.

type SubstepData

type SubstepData struct {
	Id            string
	Type          string // SubstepType wire value
	Execution     string // ExecutionMode wire value
	Order         int
	LabelRef      string
	ParallelGroup string // optional parallel group name
	Description   string
	ExtraLabel    string // optional extra label ref
	// Instances specifies repeated substep instantiation metadata.
	Instances *SubstepInstances
	// StartupSequence signals that PROCEDURE_STEPS[supervisor] should be embedded.
	StartupSequence bool
}

SubstepData holds canonical per-phase substep specifications. Mirrors the inner dicts in Python SUBSTEP_DATA.

type SubstepElem

type SubstepElem struct {
	Id            string               `xml:"id,attr"`
	Type          string               `xml:"type,attr"`
	Execution     string               `xml:"execution,attr"`
	Order         string               `xml:"order,attr"`
	ParallelGroup string               `xml:"parallel-group,attr,omitempty"`
	LabelRef      string               `xml:"label-ref,attr"`
	Description   string               `xml:"description"`
	ExtraLabel    *ExtraLabelElem      `xml:"extra-label"`
	Instances     *InstancesElem       `xml:"instances"`
	Startup       *StartupSequenceElem `xml:"startup-sequence"`
}

SubstepElem is a single <substep ...> element.

type SubstepInstances

type SubstepInstances struct {
	Count string // e.g. "3", "N"
	Per   string // e.g. "review-axis", "production-code-path"
}

SubstepInstances describes how many times a substep is instantiated.

type SubstepOrderEntry

type SubstepOrderEntry struct {
	Id        string
	Order     int
	Execution string // "sequential" or "parallel"
}

SubstepOrderEntry holds ordering metadata for a single substep within a phase. Mirrors the Python tuple (id, order, execution) from phase_substep_orders.

type SubstepsElem

type SubstepsElem struct {
	Substeps []SubstepElem `xml:"substep"`
}

SubstepsElem wraps <substeps>.

type TDDLayerElem

type TDDLayerElem struct {
	Number      string `xml:"number,attr"`
	Name        string `xml:"name,attr"`
	Description string `xml:"description,attr"`
}

TDDLayerElem is <layer number="..." name="..." description="..."/>.

type TDDLayersElem

type TDDLayersElem struct {
	Layers []TDDLayerElem `xml:"layer"`
}

TDDLayersElem wraps <tdd-layers>.

type TaskTitleElem

type TaskTitleElem struct {
	Pattern    string `xml:"pattern,attr"`
	Substep    string `xml:"substep,attr,omitempty"`
	Convention string `xml:"convention"`
}

TaskTitleElem is a <task-title pattern="..." .../> or block element.

type TaskTitlesSection

type TaskTitlesSection struct {
	XMLName     xml.Name              `xml:"task-titles"`
	Conventions []TitleConventionElem `xml:"title-convention"`
}

TaskTitlesSection is the top-level <task-titles> element.

type TitleConvention

type TitleConvention struct {
	Pattern       string
	LabelRef      string
	CreatedBy     string
	PhaseRef      string // optional phase reference
	ExtraLabelRef string // optional extra label reference
	Note          string // optional note
}

TitleConvention is a task title naming convention for a phase/substep type. Mirrors Python TitleConvention dataclass.

type TitleConventionElem

type TitleConventionElem struct {
	Pattern       string `xml:"pattern,attr"`
	LabelRef      string `xml:"label-ref,attr"`
	CreatedBy     string `xml:"created-by,attr"`
	PhaseRef      string `xml:"phase-ref,attr,omitempty"`
	ExtraLabelRef string `xml:"extra-label-ref,attr,omitempty"`
	Note          string `xml:"note,attr,omitempty"`
}

TitleConventionElem is a single <title-convention .../> element.

type Transition

type Transition struct {
	ToPhase   protocol.PhaseId
	Condition string
	Action    string // optional action on transition
}

Transition is a single valid phase transition. Mirrors Python Transition dataclass.

type TransitionElem

type TransitionElem struct {
	ToPhase         string               `xml:"to-phase,attr"`
	Condition       string               `xml:"condition,attr"`
	Action          string               `xml:"action,attr,omitempty"`
	SkillInvocation *SkillInvocationElem `xml:"skill-invocation"`
}

TransitionElem is a single <transition to-phase="..." condition="..." ...> element.

type TransitionsElem

type TransitionsElem struct {
	Transitions []TransitionElem `xml:"transition"`
}

TransitionsElem wraps <transitions>.

type UnresolvedMarker

type UnresolvedMarker struct {
	// FragRef is the unresolvable marker reference.
	FragRef FragmentId

	// ConsumerSkill is the SkillBodySpecs key where the marker appears.
	ConsumerSkill string

	// MarkerKind is "ProseSection" or "BehaviorSpec".
	MarkerKind string
}

UnresolvedMarker describes a FragRef placement marker that references a fragment not present in SharedFragmentSpecs.

func (*UnresolvedMarker) Error

func (e *UnresolvedMarker) Error() string

Error returns an actionable message.

type UsesAxesElem

type UsesAxesElem struct {
	AxisRefs []AxisRefElem `xml:"axis-ref"`
}

UsesAxesElem wraps <uses-axes>.

type ValidationError

type ValidationError struct {
	// Layer is the detection layer that produced this error.
	Layer ErrorLayer

	// ElementPath is the XPath-style description of the offending element,
	// e.g. "phase[@id='p1']/substep[@id='s1_1']".
	ElementPath string

	// Message describes what is wrong, why, and how to fix it.
	Message string
}

ValidationError represents a single schema validation finding. All three fields are always populated; an empty ElementPath indicates the error is at the document root level.

func ValidateSchema

func ValidateSchema(r io.Reader) ([]ValidationError, error)

ValidateSchema reads XML from r and validates it against the 3-layer Pasture Protocol schema rules.

Error contract:

  • io.Reader read failure → (nil, error)
  • XML parse failure → ([]ValidationError{{Layer: LayerStructural, ...}}, nil)
  • Violations found → ([]ValidationError{...}, nil) with len > 0
  • Valid schema → (nil, nil)

func ValidateTree

func ValidateTree(root *XMLNode) []ValidationError

ValidateTree validates a parsed XMLNode tree against the 3-layer Aura Protocol schema rules and returns all violations found.

Returns nil when the tree is valid. A nil root is treated as an empty document with no violations.

type Workflow

type Workflow struct {
	Id          string
	Name        string
	Description string
	RoleRef     types.RoleId
	Stages      []WorkflowStage
}

Workflow is a complete workflow specification for an agent role. Keyed in WorkflowSpecs by workflow id. Mirrors Python Workflow dataclass.

type WorkflowAction

type WorkflowAction struct {
	Id          string
	Instruction string
	Command     string // optional concrete shell/tool command
}

WorkflowAction is a single action within a workflow stage. Mirrors Python WorkflowAction dataclass.

type WorkflowElem

type WorkflowElem struct {
	Id          string      `xml:"id,attr"`
	Name        string      `xml:"name,attr"`
	RoleRef     string      `xml:"role-ref,attr"`
	Description string      `xml:"description,attr"`
	Stages      []StageElem `xml:"stage"`
}

WorkflowElem is a single <workflow id="..." name="..." role-ref="..." description="..."> element.

type WorkflowStage

type WorkflowStage struct {
	Id                string
	Name              string
	Order             int
	Execution         string           // WorkflowExecution: "sequential", "parallel", "conditional-loop"
	PhaseRef          protocol.PhaseId // optional phase this stage maps to
	Actions           []WorkflowAction
	ExitConditions    []ExitCondition
	OperationalDetail string // optional prose rendered immediately after formal actions, before exit conditions
}

WorkflowStage is a single stage in an agent workflow. Mirrors Python WorkflowStage dataclass.

type WorkflowsSection

type WorkflowsSection struct {
	XMLName   xml.Name       `xml:"workflows"`
	Workflows []WorkflowElem `xml:"workflow"`
}

WorkflowsSection is the top-level <workflows> element.

type XMLNode

type XMLNode struct {
	XMLName  xml.Name
	Attrs    []xml.Attr `xml:",any,attr"`
	Children []*XMLNode `xml:",any"`
	Text     string     `xml:",chardata"`
}

XMLNode is a generic XML tree node for validator tree operations. It can represent any element in the schema document and is used by ValidateTree to walk the document without requiring concrete struct types.

func (*XMLNode) Attr

func (n *XMLNode) Attr(name string) string

Attr returns the value of the named attribute, or "" if not present.

func (*XMLNode) Find

func (n *XMLNode) Find(tag string) *XMLNode

Find returns the first direct child whose local tag matches tag, or nil.

func (*XMLNode) FindAll

func (n *XMLNode) FindAll(tag string) []*XMLNode

FindAll returns all direct children whose local tag matches tag.

func (*XMLNode) Iter

func (n *XMLNode) Iter(tag string) []*XMLNode

Iter recursively finds all descendant nodes (including self) whose local tag matches tag, in document order.

func (*XMLNode) UnmarshalXML

func (n *XMLNode) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements xml.Unmarshaler to parse an XMLNode tree from an XML decoder. This gives us a fully recursive generic tree without needing concrete struct types for every element.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL