Skip to content

feat(validation): allow numeric-prefixed change names for ordered/tiered workflows #850

@chrisgoddard

Description

@chrisgoddard

Summary

The validateChangeName function in src/utils/change-utils.ts enforces that
change names must start with a lowercase letter:

if (/^[0-9]/.test(name)) {
  return { valid: false, error: 'Change name must start with a letter' };
}

This blocks alternative conventions users might want to use such as numeric prefixes to express
execution tier ordering in multi-agent or parallel-batch workflows.

Motivation

I use OpenSpec as part of an orchestrated, multi-agent development workflows and I
need to encode execution ordering semantics directly in change-ids:

  • 100-audit-codebase, 200-implement-fixes, 300-validate -- sequential tiers
  • 101-01-fix-auth, 101-02-fix-session, 101-03-fix-jwt -- parallel batch within tier 100
  • 801-01-fix-contradiction, 801-02-fix-claim-origin -- versioned sub-changes

Without numeric prefix support, I have to maintain a fork OpenSpec and patch the
validation manually.

Current Behavior

$ openspec new change 100-add-feature
Error: Change name must start with a letter

Proposed Change

Option A (recommended): Remove or relax the must-start-with-letter restriction:

const kebabCasePattern = /^[a-z0-9][a-z0-9]*(-[a-z0-9]+)*$/;

Option B: Make the naming pattern configurable in openspec/config.yaml:

# openspec/config.yaml
schema: spec-driven
changeNamePattern: "^[a-z0-9][-a-z0-9]*$"   # override default

Option B is more conservative but requires additional infrastructure. Option A
is a minimal, backward-compatible change -- all currently-valid names still pass,
since they start with [a-z] which is a subset of [a-z0-9].

Security Consideration

The restriction appears to exist as a safety measure against hidden files (.name)
and path traversal (..). Numeric-start names pose no such risk -- 100-feature
is a perfectly safe directory name. The explicit dot/hyphen-start guards already
prevent those attack vectors independently.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions