Skip to content

[Bug]: Re-running specify init --here --force resets feature_numbering in init-options.json to "sequential" #5098

Open

Description

@hnipps

Bug Description

When specify init runs in an existing project, it reads the previous .specify/init-options.json and merges it into the new options (src/specify_cli/command_init.py:850-858, {**previous_init_options, ...}). Custom keys survive. However, "feature_numbering": "sequential" is then set unconditionally, so a project configured for timestamp feature numbering silently switches back to sequential numbering after a re-init.

The expectation is inferred rather than documented. templates/commands/specify.md:87-89 documents feature_numbering in init-options.json as the setting that selects "timestamp" or "sequential" prefixes. There is no specify init flag that sets it, because --branch-numbering was removed (tests/test_branch_numbering.py). Editing the file is therefore the only way to choose timestamp numbering, and the merge suggests user-set options are meant to persist. I found no doc or test that says re-init must keep this key.

Steps to Reproduce

From a fresh clone, after uv sync, save the script below and run uv run python -I repro.py from the repository root. It runs specify init twice in a temporary directory through the CLI app, and sets feature_numbering to "timestamp" between the two runs.

import json, os, tempfile
from pathlib import Path
from typer.testing import CliRunner
from specify_cli import app

proj = Path(tempfile.mkdtemp())
os.chdir(proj)
args = ["init", "--here", "--force", "--integration", "claude", "--script", "sh",
        "--non-interactive", "--ignore-agent-tools"]
runner = CliRunner()
assert runner.invoke(app, args).exit_code == 0

opts_path = proj / ".specify" / "init-options.json"
opts = json.loads(opts_path.read_text())
opts["feature_numbering"] = "timestamp"
opts["my_custom_key"] = "kept?"
opts_path.write_text(json.dumps(opts))
print("before:", {k: opts[k] for k in ("feature_numbering", "my_custom_key")})

assert runner.invoke(app, args).exit_code == 0
after = json.loads(opts_path.read_text())
print("after: ", {k: after.get(k) for k in ("feature_numbering", "my_custom_key")})

Expected Behavior

feature_numbering: "timestamp" should survive a re-init, as my_custom_key does. This is inferred from the option merge at src/specify_cli/command_init.py:850-851 and the documentation of the setting at templates/commands/specify.md:87-89.

Actual Behavior

before: {'feature_numbering': 'timestamp', 'my_custom_key': 'kept?'}
after:  {'feature_numbering': 'sequential', 'my_custom_key': 'kept?'}

Specify CLI Version

1.2.4.dev0 (main at 27d14e2)

AI Agent

Not applicable

Operating System

Linux 6.18 (Ubuntu container)

Python Version

Python 3.12.3

Additional Context

A likely fix is to default feature_numbering to "sequential" only when the previous options do not already set it.

Also reproduced on macOS (Darwin 25.6, arm64) with Python 3.14.4 and uv run python -I repro.py against 27d14e2; the output matches the above.

AI Disclosure

Found and reproduced with Claude Code (model: Claude Opus 4.8), run autonomously under human supervision. The human reporter re-ran every reproduction above before filing.

Activity

  1. added
    triage-must-haveVerdict: high-value, important work for Spec Kit — do first
    on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    triage-must-haveVerdict: high-value, important work for Spec Kit — do first

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions