View all documentations

Spec Workflow

Wizard enforces Goal and Draft Goal description compliance on GitHub issues. When a Goal or Draft Goal is opened, edited, or assignees change, the app normalizes allowed sections, creates a spec file when needed (Goals and Draft Goals on opened), and surfaces warnings in the issue description.

Spec-disabled organizations

Some organizations are listed under Spec-Disabled Organizations in config/whitelist.json. For those orgs, Wizard skips # Spec validation, automatic spec file creation, and related other-sections warnings. Deadline and Stakeholders Interview checks still run.

See Whitelist for configuration and full behavior.

Allowed description sections

A Goal description may use these sections:

# Spec

https://github.com/<org>/<repo>/blob/main/docs/specs/<name>.md

# Deadline

ETA: undefined

# Stakeholders Interview

- https://docs.google.com/document/d/...

Custom H1 sections are also allowed for grouping issue or PR references — for example # Blocked by followed by a list of issue links. The section body must contain only issue or PR references; free-form text is not permitted inside custom sections. Instructions, scope notes, and design decisions belong in the linked spec file, not in the Goal description.

Spec (required)

# Spec is always required.

  • The section must contain one URL pointing to a .md file under docs/specs/ on the main branch (flat or nested paths are allowed).
  • Valid URL patterns:
    • https://github.com/<org>/<repo>/blob/main/docs/specs/<name>.md
    • https://github.com/<org>/<repo>/blob/main/docs/specs/<folder>/<name>.md
  • No other text is allowed in the section besides the URL.

Deadline (required)

# Deadline is always present on Goal and Draft Goal issues. Wizard creates it automatically if missing.

  • The section must include an ETA: line: ETA: undefined or ETA: <DD-MMM-YYYY> (for example, ETA: 25-May-2026). Wizard normalizes that line on each validation run.
  • Use ETA: undefined when no completion date is set yet.
  • Any other lines in # Deadline are left in place, but Wizard adds a warning tagging the last human editor (same as invalid content in other sections).
  • Set a date via @holdex goal set-eta <date> or @holdex goal set-eta +5d (see Commands).
  • On Goal and Draft Goal issues, the command normalizes # Deadline first, then replaces the existing ETA: line inside that section (including ETA: undefined or invalid values). It does not append a duplicate line.
  • On other issue types, the command updates the first matching ETA: line in the description, or appends one if none exists.

Stakeholders Interview (optional)

Use this section to link Google Documents for stakeholder discovery.

  • URLs must be Google Document links (https://docs.google.com/document/d/...).
  • Use either a single URL on its own line, or a bullet list of URLs.
  • Do not mix single-line and list formats in the same section.
  • This section does not replace the # Spec link.

App-managed > [!WARNING] blocks are ignored during validation so the app's own writes never trigger a violation.

Automatic spec file creation

When a Goal is opened and has no valid spec URL under # Spec, Wizard:

  1. Derives a file name from the Goal title: strips the Goal: prefix, lowercases, replaces spaces and non-alphanumeric characters with hyphens, truncates to 50 characters. Example: Goal: Spec workflowspec-workflow.md.

  2. If that file already exists in docs/specs/, appends -2, -3, and so on until an unused name is found.

  3. Commits docs/specs/<feature>.md to main with frontmatter only:

    ---
    goal: <goal-issue-url>
    ---
  4. Updates the Goal description with the permanent file URL under # Spec.

The link is permanent. If the Goal title changes later, the file name is not updated — the existing link continues to point to the correct file.

Spec creation runs only on opened, not on later edits, so retries do not create duplicate files.

[!NOTE] @holdex goal create-spec always creates a flat file at docs/specs/<name>.md. Nested paths under docs/specs/ are valid only when you link to an existing file manually.

Spec file lifecycle

docs/specs/<feature>.md starts as frontmatter-only and grows as scope is defined. As the Goal is implemented, sections graduate to the relevant file in docs/ and are removed from the spec file. A spec may graduate to multiple files if its sections cover different areas.

When all sections have graduated, the spec file is kept but left as frontmatter-only — it is never deleted. This ensures the # Spec link in the Goal description never breaks and the Goal can be reopened without re-creating the file.

Warnings

Warnings are written to a dedicated Warnings section at the end of the description. They are removed and re-evaluated on each validation run.

Condition Who is mentioned
No valid # Spec URL Current assignees
Spec URL is not a docs/specs/**/*.md link on main Current assignees
Extra content in # Spec Last human editor
Invalid format in # Stakeholders Interview Last human editor
Non–Google Doc URL in # Stakeholders Interview Last human editor
Invalid ETA: value in # Deadline (not undefined or DD-MMM-YYYY) Last human editor
Assignees present but ETA: undefined in # Deadline Current assignees
ETA: date in # Deadline is in the past Current assignees
Extra content in # Deadline (non-ETA: lines) Last human editor
Orphan lines between main sections (no new # title line) Last human editor
Custom # section is empty or its body is not issue/PR references only (Invalid Section Warning) Last human editor

Example (missing spec):

> [!WARNING]
> @assignee1 @assignee2 this Goal has no linked Spec. A Spec is required before work can begin.
> See the [contributing guidelines](https://github.com/holdex/developers/blob/main/docs/CONTRIBUTING.md#specs)
> or the [Wizard docs](https://wizard.holdex.io/docs/commands) for how to create one.

Warnings clear automatically once the description is fixed.

Validation is skipped when the event sender is the app bot or an excluded user, so the app does not tag itself or re-process its own updates.

Google Document commands

Create or attach a Google Document under # Stakeholders Interview via issue comments. See Commands for syntax.

Command Action
@holdex goal create-spec Creates docs/specs/<name>.md and links it under # Spec
@holdex goal create-google-doc Creates a new Google Doc and appends its URL to the section
@holdex goal attach-google-doc <url> Attaches an existing Google Doc URL

create-google-doc and attach-google-doc append the Google Doc URL even when the section still has validation warnings; fix any remaining warning in the description when you can.

Google Doc folder routing for the browser extension is configured in Spec Document Folder Configuration.

Branch protection

When Wizard commits a spec file to main, the commit may be rejected by a branch protection rule or repository ruleset. Wizard handles this automatically:

  1. Repo-level rulesets — Wizard calls GET /repos/{owner}/{repo}/rules/branches/main to find active rules of type pull_request or update that originate from a repository-level ruleset. For each one, Wizard fetches the full ruleset and adds itself as a bypass actor (bypass_mode: always), then retries the commit.

  2. Classic branch protection — Wizard calls GET /repos/{owner}/{repo}/branches/main/protection. If the rule includes required_pull_request_reviews or restrictions, Wizard adds its app slug to the relevant allowlist and retries the commit.

  3. Organisation-level rulesets — If the blocking rule originates from an organisation ruleset, Wizard cannot modify it. Instead it posts a comment on the Goal issue tagging the last editor:

    @editor The Wizard app could not auto-create the spec file because a branch protection rule on main is set at the organization level and cannot be modified by the app.

    An org admin must add Wizard as a bypass actor: https://github.com/organizations/{org}/settings/rules/{id}

    After adding the bypass, re-trigger spec creation with @holdex goal create-spec.

    If the specific ruleset URL cannot be determined, the comment provides manual navigation instructions instead.

[!NOTE] Wizard only attempts the bypass fix when the commit fails with HTTP 409 or 422. If branch protection is not configured on main, no API calls are made.

When validation runs

Goal validations run on these issue events:

  • opened
  • edited
  • assigned
  • reopened

Issues with GitHub type Goal (Goal: title prefix) or Draft Goal ([DRAFT] Goal: title prefix) are processed. Draft Goals receive the same section normalization and description warnings.