Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/homebrew-package-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
shell: bash
run: |
set -euo pipefail
package_version="$(PYTHONPATH=src python -c 'from devspec_lite import __version__; print(__version__)')"
package_version="$(PYTHONPATH=src python -c 'from devspec import __version__; print(__version__)')"
if [[ "${GITHUB_REF_TYPE:-}" == "tag" ]]; then
python scripts/verify_release_version.py --tag "${GITHUB_REF_NAME}"
version="${GITHUB_REF_NAME#v}"
Expand All @@ -38,13 +38,13 @@ jobs:
tarball_url="https://github.com/speclabs/devspec-lite/archive/refs/tags/v${version}.tar.gz"
sha256="$(curl -fsSL "${tarball_url}" | sha256sum | awk '{print $1}')"
mkdir -p dist/homebrew/Formula
sed -e "s/REPLACE_WITH_VERSION/${version}/g" -e "s/REPLACE_WITH_RELEASE_SHA256/${sha256}/g" packaging/homebrew/devspec-lite.rb > dist/homebrew/Formula/devspec-lite.rb
test "$(grep -c 'REPLACE_WITH_' dist/homebrew/Formula/devspec-lite.rb)" -eq 0
sed -e "s/REPLACE_WITH_VERSION/${version}/g" -e "s/REPLACE_WITH_RELEASE_SHA256/${sha256}/g" packaging/homebrew/devspec.rb > dist/homebrew/Formula/devspec.rb
test "$(grep -c 'REPLACE_WITH_' dist/homebrew/Formula/devspec.rb)" -eq 0
echo "${sha256} devspec-lite-v${version}.tar.gz" > "dist/homebrew/devspec-lite-v${version}.tar.gz.sha256"
- name: Upload Homebrew artifacts
uses: actions/upload-artifact@v4
with:
name: devspec-lite-homebrew-package
name: devspec-homebrew-package
path: |
dist/homebrew/Formula/devspec-lite.rb
dist/homebrew/Formula/devspec.rb
dist/homebrew/*.sha256
6 changes: 3 additions & 3 deletions .github/workflows/python-package-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ jobs:
- name: Create package checksums
shell: bash
run: |
find dist -maxdepth 1 -type f ! -name devspec-lite-python-package-checksums.txt -print0 \
find dist -maxdepth 1 -type f ! -name devspec-python-package-checksums.txt -print0 \
| sort -z \
| xargs -0 sha256sum > dist/devspec-lite-python-package-checksums.txt
| xargs -0 sha256sum > dist/devspec-python-package-checksums.txt
- name: Upload package artifacts
uses: actions/upload-artifact@v4
with:
name: devspec-lite-python-package-dist
name: devspec-python-package-dist
path: dist/*
- name: Publish to PyPI
if: startsWith(github.ref, 'refs/tags/v')
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ jobs:
python -m venv .smoke
. .smoke/bin/activate
python -m pip install dist/*.whl
devspec-lite --version
devspec-lite init --target "$(mktemp -d)" --profile all --repo-state existing
devspec --version
devspec init --target "$(mktemp -d)" --profile all --repo-state existing
- name: Smoke test wheel on Windows
if: runner.os == 'Windows'
shell: pwsh
run: |
python -m venv .smoke
$wheel = Get-ChildItem dist -Filter '*.whl' | Select-Object -First 1
& .\.smoke\Scripts\python.exe -m pip install $wheel.FullName
$target = Join-Path $env:RUNNER_TEMP 'devspec-lite-wheel-smoke'
$target = Join-Path $env:RUNNER_TEMP 'devspec-wheel-smoke'
New-Item -ItemType Directory -Force -Path $target | Out-Null
.\.smoke\Scripts\devspec-lite.exe --version
.\.smoke\Scripts\devspec-lite.exe init --target $target --profile all --repo-state existing
.\.smoke\Scripts\devspec.exe --version
.\.smoke\Scripts\devspec.exe init --target $target --profile all --repo-state existing
36 changes: 18 additions & 18 deletions .github/workflows/winget-package-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,48 +40,48 @@ jobs:
.\.venv-winget\Scripts\python.exe -m pip install --upgrade pip pyinstaller $wheel.FullName
New-Item -ItemType Directory -Force -Path build\winget | Out-Null
@(
'from devspec_lite.cli import main'
'from devspec.cli import main'
''
'raise SystemExit(main())'
) | Set-Content -Path build\winget\devspec-lite-entry.py -Encoding UTF8
.\.venv-winget\Scripts\pyinstaller.exe --noconfirm --clean --onefile --name devspec-lite --distpath dist\winget --workpath build\pyinstaller --specpath build\pyinstaller --collect-data devspec_lite build\winget\devspec-lite-entry.py
) | Set-Content -Path build\winget\devspec-entry.py -Encoding UTF8
.\.venv-winget\Scripts\pyinstaller.exe --noconfirm --clean --onefile --name devspec --distpath dist\winget --workpath build\pyinstaller --specpath build\pyinstaller --collect-data devspec build\winget\devspec-entry.py
- name: Smoke test portable executable
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$target = Join-Path $env:RUNNER_TEMP 'devspec-lite-winget-smoke'
$target = Join-Path $env:RUNNER_TEMP 'devspec-winget-smoke'
New-Item -ItemType Directory -Force -Path $target | Out-Null
.\dist\winget\devspec-lite.exe --version
.\dist\winget\devspec-lite.exe init --target $target --profile all --repo-state existing
.\dist\winget\devspec-lite.exe doctor --target $target --profile all
.\dist\winget\devspec.exe --version
.\dist\winget\devspec.exe init --target $target --profile all --repo-state existing
.\dist\winget\devspec.exe doctor --target $target --profile all
- name: Generate WinGet manifests and checksum
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$version = if ($env:GITHUB_REF_NAME -match '^v(.+)$') { $Matches[1] } else { python -c "from devspec_lite import __version__; print(__version__)" }
$hash = (Get-FileHash dist\winget\devspec-lite.exe -Algorithm SHA256).Hash.ToLowerInvariant()
"$hash devspec-lite.exe" | Set-Content -Path dist\winget\devspec-lite.exe.sha256 -Encoding ASCII
$url = "https://github.com/speclabs/devspec-lite/releases/download/v$version/devspec-lite.exe"
$manifestRoot = "dist\winget\manifests\s\SpecLabs\DevspecLite\$version"
$version = if ($env:GITHUB_REF_NAME -match '^v(.+)$') { $Matches[1] } else { python -c "from devspec import __version__; print(__version__)" }
$hash = (Get-FileHash dist\winget\devspec.exe -Algorithm SHA256).Hash.ToLowerInvariant()
"$hash devspec.exe" | Set-Content -Path dist\winget\devspec.exe.sha256 -Encoding ASCII
$url = "https://github.com/speclabs/devspec-lite/releases/download/v$version/devspec.exe"
$manifestRoot = "dist\winget\manifests\s\SpecLabs\Devspec\$version"
New-Item -ItemType Directory -Force -Path $manifestRoot | Out-Null
Get-ChildItem packaging\winget -Filter 'DevspecLite*.yaml' | ForEach-Object {
Get-ChildItem packaging\winget -Filter 'Devspec*.yaml' | ForEach-Object {
$manifest = Get-Content $_.FullName -Raw
$manifest = $manifest.Replace('REPLACE_WITH_VERSION', $version).Replace('REPLACE_WITH_RELEASE_URL', $url).Replace('REPLACE_WITH_RELEASE_SHA256', $hash)
Set-Content -Path (Join-Path $manifestRoot $_.Name) -Value $manifest -Encoding UTF8
}
- name: Upload WinGet artifacts
uses: actions/upload-artifact@v4
with:
name: devspec-lite-winget-package
name: devspec-winget-package
path: |
dist/winget/devspec-lite.exe
dist/winget/devspec-lite.exe.sha256
dist/winget/devspec.exe
dist/winget/devspec.exe.sha256
dist/winget/manifests/**/*.yaml
- name: Attach WinGet release artifacts
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v2
with:
files: |
dist/winget/devspec-lite.exe
dist/winget/devspec-lite.exe.sha256
dist/winget/devspec.exe
dist/winget/devspec.exe.sha256
dist/winget/manifests/**/*.yaml
24 changes: 10 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,16 @@ Manual copying and CLI installation produce the same canonical `devspec/` conten

## CLI quick start

The [CLI quick start](docs/quickstart.md) walks through initializing, validating, and choosing the first command.

After choosing a CLI route, initialize and validate the repository:

```powershell
# Existing repository
uvx devspec-lite init --target . --profile all --repo-state existing
uvx devspec-lite doctor --target . --profile all

# New repository
uvx devspec-lite init --target . --profile all --repo-state new
uvx devspec-lite doctor --target . --profile all
uvx devspec init --target . --profile all --repo-state existing
uvx devspec doctor --target . --profile all
```

`init` copies canonical Markdown + XML contracts, concise templates, and the wrappers for the selected agent profile. It generates `devspec/foundation/repository-state.md` from `--repo-state` and seeds empty `devspec/architecture/overview.md` and `artifact-queue.md` from their templates. Those two, plus `devspec/constitution.md`, are project-owned: `init` and `sync` never overwrite them, even with `--force`. Use the `devspec.*` commands exposed by your agent host. Use `devspec-lite diff --target .` to inspect installed-framework drift and `devspec-lite sync --target . --profile all --dry-run` before applying a framework upgrade.
Use `--repo-state new` for a repository with no source yet. The [CLI quick start](docs/quickstart.md) covers both routes and the first command to run.

`init` copies the canonical contracts, protocols, and templates plus the wrappers for the selected agent profile, generates `devspec/foundation/repository-state.md` from `--repo-state`, and seeds empty `devspec/architecture/overview.md` and `artifact-queue.md`. Those two and `devspec/constitution.md` are project-owned: `init` and `sync` never overwrite them, even with `--force`.

Before a framework upgrade, inspect drift with `devspec diff --target .` and preview it with `devspec sync --target . --profile all --dry-run`.

## Choose a workflow route

Expand All @@ -42,5 +37,6 @@ Use the [developer workflow guide](docs/workflows.md) for concrete quickfix, gro

## How to

Follow the scenario-based [how-to guide](docs/how-to.md) to choose the right command, establish an existing or new repository baseline, start and deliver a story, work across multiple repositories, or route a small fix safely.
Before every `devspec.*` command, confirm the single-repository or multi-repository scope, unless current canonical evidence records it. After starting a story, use the normal work-item commands or `continue` without repeating its ID; private per-worktree context resumes only the recorded next action. See the [beginner command examples](docs/command-examples.md) for scaffold layouts, source-scope confirmation, multi-repository boundaries, and a first prompt for every command.
Follow the scenario-based [how-to guide](docs/how-to.md) to choose the right command, establish a baseline, deliver a story, work across repositories, or route a small fix safely. The [beginner command examples](docs/command-examples.md) give a first prompt for every command.

Two rules apply throughout. Confirm single-repository or multi-repository scope before every `devspec.*` command, unless current canonical evidence already records it. After starting a story, run the work-item commands or `continue` without repeating its ID: private per-worktree context resumes only the recorded next action.
2 changes: 1 addition & 1 deletion devspec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

New repository foundation: `projectcontext → techstack → codebase-structure → coding-standards → rules`. Existing repository baseline: `extract` completes the foundation, prepares the applicable diagram list, and asks whether to generate all or selected diagrams. Rare durable cross-work-item principles live in `constitution.md` with stable `CP-###` IDs. `extract` records candidates from evidence; `projectcontext` promotes or retires them only on explicit input.

Work item: `story → grooming` when needed `→ finalize → tasks → implement → review`. Story intake accepts one manual request or, when an authenticated MCP connector is available, one read-only provider work-item reference.
Work item: `story → grooming → finalize → tasks → implement → review`. Grooming is the default step after intake; skip it only when the intake source itself carried explicit acceptance criteria and story.md lists no open requirement gap. Story intake accepts one manual request or, when an authenticated MCP connector is available, one read-only provider work-item reference.
After `story` selects a work item, use the normal work-item commands without repeating its ID. Per-worktree private context resolves the selected story and its recorded `next` action; use an ID only to switch or disambiguate stories.

Use `clarify` only for an active blocker and `quickfix` only for localized, low-risk changes. See `lifecycle.md` for all command transitions.
Expand Down
2 changes: 1 addition & 1 deletion devspec/architecture/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
- Scope: developer workflow and setup guidance, not product runtime architecture.
- Sources: command contracts, protocols, CLI behavior, and setup documentation.
- Constraint: diagrams show confirmed routes only; they do not infer application dependencies.
- Deviation: these four are wide documentation banners sized to the guides that embed them, not the 1600 by 900 canvas `_template/diagram-types.md` requires for a family template. They keep the dark grammar, titles, descriptions, and evidence rules. A diagram generated by `devspec.diagram` uses the family template and its canvas.
- Deviation: these five are wide documentation banners sized to the guides that embed them, not the 1600 by 900 canvas `_template/diagram-types.md` requires for a family template. They keep the dark grammar, titles, descriptions, and evidence rules. A diagram generated by `devspec.diagram` uses the family template and its canvas.

## Diagram index

Expand Down
2 changes: 1 addition & 1 deletion devspec/command-registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Purpose and next route are the contract's own `<purpose>` and `<transition next>
| `devspec.tasks` | Create ordered, independently verifiable implementation tasks. | `devspec.implement`, `devspec.clarify` |
| `devspec.implement` | Implement pending ready tasks with focused checkpoints and validation. | `devspec.review`, `devspec.clarify` |
| `devspec.review` | Review changed work against readiness, tasks, and validation evidence. | `none`, `devspec.implement`, `devspec.clarify` |
| `devspec.diagram` | Create one evidence-backed diagram with duplicate checks and durable queue state. | `return-to-caller`, `devspec.clarify` |
| `devspec.diagram` | Create one evidence-backed diagram with duplicate checks and durable queue state. | `return-to-caller`, `devspec.clarify`, `none` |
| `devspec.quickfix` | Implement and validate one localized, low-risk enhancement or bug fix. | `none`, `devspec.clarify`, `devspec.story` |

Work-item IDs are optional for `grooming`, `finalize`, `tasks`, `implement`, `review`, `clarify`, and `changerequest`. Without an ID, resolve the private per-worktree current context and run only the work item's recorded `next` action. Use an explicit ID to switch stories; when several eligible work items exist, ask the developer to choose.
5 changes: 5 additions & 0 deletions devspec/contracts/devspec.changerequest.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ Invocation: `/devspec.changerequest [work-item-id] Add JSON export`
<input>An optional work-item ID and one related missing requirement.</input>
<rules>
<rule>Append the next CR-### entry and CR-scoped criteria; never rewrite baseline evidence.</rule>
<rule>Mark the earlier finalization, task, implementation, and review sections superseded when the revision increments, preserving their recorded evidence unchanged.</rule>
<rule>Ask one material classification question when it is unclear whether the request is related or a new linked work item.</rule>
</rules>
<entry>Related requirement for a finalized-or-later work item with an active current scope revision; reject independent, blocked, or pre-finalization requests.</entry>
<outputs>
<artifact path="devspec/work-items/&lt;id&gt;/story.md" />
<artifact path="devspec/work-items/&lt;id&gt;/meta.md" />
<artifact path="devspec/work-items/&lt;id&gt;/decisions.md" />
<artifact path="devspec/work-items/&lt;id&gt;/finalize.md" />
<artifact path="devspec/work-items/&lt;id&gt;/tasks.md" />
<artifact path="devspec/work-items/&lt;id&gt;/implement.md" />
<artifact path="devspec/work-items/&lt;id&gt;/review.md" />
</outputs>
<transitions>
<transition outcome="related-change-accepted" stage="finalization" run="active" next="devspec.finalize" />
Expand Down
4 changes: 2 additions & 2 deletions devspec/contracts/devspec.clarify.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Invocation: `/devspec.clarify [work-item-id]`
<scope>Use only to resolve one recorded material blocker and resume the command that recorded it. This command never advances a stage, changes scope, or answers a question its originating command has not recorded.</scope>
<input>An optional work-item ID, or one foundation or quickfix record, with one active material blocker question.</input>
<rules>
<rule>Resolve the one highest-priority material decision in its active queue and append its answer to decisions.md. For a work item, append the origin command, question, resolution, evidence, and exact resume command to clarify.md.</rule>
<rule>Resolve the one question the originating command recorded as its active material blocker, never another queued question and never a question the originating command did not record, and append its answer to decisions.md. When the originating command keeps a wider queue, leave the remaining questions to that command's own re-discovery on resume. For a work item, append the origin command, question, resolution, evidence, and exact resume command to clarify.md.</rule>
<rule>Do not accept scope changes after finalization; route them to changerequest.</rule>
<rule>Return to the saved stage and next action after resolution.</rule>
</rules>
Expand All @@ -26,7 +26,7 @@ Invocation: `/devspec.clarify [work-item-id]`
<artifact path="devspec/foundation/decisions.md" />
<artifact path="devspec/work-items/&lt;id&gt;/decisions.md" />
<artifact path="devspec/work-items/&lt;id&gt;/clarify.md" />
<artifact path="devspec/quickfixes/QF-###-slug.md" />
<artifact path="devspec/quickfixes/QF-&lt;number&gt;-&lt;slug&gt;.md" />
<artifact path="devspec/work-items/&lt;id&gt;/meta.md" />
</outputs>
<transitions>
Expand Down
Loading
Loading