specwarden 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- specwarden-0.1.0/.claude/skills/specwarden/SKILL.md +106 -0
- specwarden-0.1.0/.claude/skills/specwarden/scripts/activate_spec.py +18 -0
- specwarden-0.1.0/.claude/skills/specwarden/scripts/coverage.py +15 -0
- specwarden-0.1.0/.claude/skills/specwarden/scripts/new_spec.py +19 -0
- specwarden-0.1.0/.claude/skills/specwarden/scripts/trace.py +16 -0
- specwarden-0.1.0/.claude/skills/specwarden/templates/decision_entry.md.template +5 -0
- specwarden-0.1.0/.claude/skills/specwarden/templates/spec.md.template +25 -0
- specwarden-0.1.0/.claude/specs/2026-05-28_v1-audit-nits-cli-wrapper-tests-and-caveman-cleanup.md +91 -0
- specwarden-0.1.0/.env.eval.example +11 -0
- specwarden-0.1.0/.github/workflows/ci.yml +32 -0
- specwarden-0.1.0/.github/workflows/release.yml +61 -0
- specwarden-0.1.0/.gitignore +70 -0
- specwarden-0.1.0/CLAUDE.md +103 -0
- specwarden-0.1.0/LICENSE +21 -0
- specwarden-0.1.0/Makefile +18 -0
- specwarden-0.1.0/PKG-INFO +204 -0
- specwarden-0.1.0/README.md +189 -0
- specwarden-0.1.0/SPEC_specwarden.md +357 -0
- specwarden-0.1.0/docs/ARCHITECTURE.md +243 -0
- specwarden-0.1.0/docs/COMPARISONS.md +174 -0
- specwarden-0.1.0/docs/HOOKS.md +257 -0
- specwarden-0.1.0/docs/PHILOSOPHY.md +65 -0
- specwarden-0.1.0/docs/RELEASING.md +51 -0
- specwarden-0.1.0/docs/TROUBLESHOOTING.md +395 -0
- specwarden-0.1.0/docs/superpowers/plans/2026-05-07-specwarden-v1.md +2159 -0
- specwarden-0.1.0/evals/README.md +75 -0
- specwarden-0.1.0/evals/fixtures/task_001_add_auth/expected.md +22 -0
- specwarden-0.1.0/evals/fixtures/task_001_add_auth/prompt.md +5 -0
- specwarden-0.1.0/evals/fixtures/task_001_add_auth/starting_state/README.md +4 -0
- specwarden-0.1.0/evals/fixtures/task_001_add_auth/starting_state/app.py +21 -0
- specwarden-0.1.0/evals/fixtures/task_001_add_auth/starting_state/requirements.txt +1 -0
- specwarden-0.1.0/evals/fixtures/task_001_add_auth/starting_state.tar.gz +0 -0
- specwarden-0.1.0/evals/fixtures/task_002_refactor_logger/expected.md +26 -0
- specwarden-0.1.0/evals/fixtures/task_002_refactor_logger/prompt.md +4 -0
- specwarden-0.1.0/evals/fixtures/task_002_refactor_logger/starting_state/README.md +7 -0
- specwarden-0.1.0/evals/fixtures/task_002_refactor_logger/starting_state/logger.py +48 -0
- specwarden-0.1.0/evals/fixtures/task_002_refactor_logger/starting_state/usage.py +42 -0
- specwarden-0.1.0/evals/fixtures/task_002_refactor_logger/starting_state.tar.gz +0 -0
- specwarden-0.1.0/evals/fixtures/task_003_add_test_suite/expected.md +29 -0
- specwarden-0.1.0/evals/fixtures/task_003_add_test_suite/prompt.md +3 -0
- specwarden-0.1.0/evals/fixtures/task_003_add_test_suite/starting_state/README.md +17 -0
- specwarden-0.1.0/evals/fixtures/task_003_add_test_suite/starting_state/cli.py +80 -0
- specwarden-0.1.0/evals/fixtures/task_003_add_test_suite/starting_state.tar.gz +0 -0
- specwarden-0.1.0/evals/fixtures/task_004_fix_race/expected.md +25 -0
- specwarden-0.1.0/evals/fixtures/task_004_fix_race/prompt.md +4 -0
- specwarden-0.1.0/evals/fixtures/task_004_fix_race/starting_state/README.md +14 -0
- specwarden-0.1.0/evals/fixtures/task_004_fix_race/starting_state/counter.py +37 -0
- specwarden-0.1.0/evals/fixtures/task_004_fix_race/starting_state.tar.gz +0 -0
- specwarden-0.1.0/evals/fixtures/task_005_add_endpoint/expected.md +27 -0
- specwarden-0.1.0/evals/fixtures/task_005_add_endpoint/prompt.md +4 -0
- specwarden-0.1.0/evals/fixtures/task_005_add_endpoint/starting_state/README.md +9 -0
- specwarden-0.1.0/evals/fixtures/task_005_add_endpoint/starting_state/db.py +20 -0
- specwarden-0.1.0/evals/fixtures/task_005_add_endpoint/starting_state/models.py +11 -0
- specwarden-0.1.0/evals/fixtures/task_005_add_endpoint/starting_state/requirements.txt +1 -0
- specwarden-0.1.0/evals/fixtures/task_005_add_endpoint/starting_state/routes.py +21 -0
- specwarden-0.1.0/evals/fixtures/task_005_add_endpoint/starting_state.tar.gz +0 -0
- specwarden-0.1.0/evals/measure.py +199 -0
- specwarden-0.1.0/evals/results/2026-05-11.md +191 -0
- specwarden-0.1.0/evals/run_eval.py +251 -0
- specwarden-0.1.0/examples/go-microservice/.claude/decisions/2026-05-08_add-version-endpoint.md +22 -0
- specwarden-0.1.0/examples/go-microservice/.claude/specs/2026-05-08_add-version-endpoint.md +27 -0
- specwarden-0.1.0/examples/go-microservice/README.md +31 -0
- specwarden-0.1.0/examples/go-microservice/go.mod +5 -0
- specwarden-0.1.0/examples/go-microservice/main.go +54 -0
- specwarden-0.1.0/examples/minimal-python-cli/.claude/decisions/2026-05-08_add-utc-flag.md +22 -0
- specwarden-0.1.0/examples/minimal-python-cli/.claude/specs/2026-05-08_add-utc-flag.md +26 -0
- specwarden-0.1.0/examples/minimal-python-cli/README.md +30 -0
- specwarden-0.1.0/examples/minimal-python-cli/cli.py +37 -0
- specwarden-0.1.0/examples/react-component/.claude/decisions/2026-05-08_add-reset-button.md +22 -0
- specwarden-0.1.0/examples/react-component/.claude/specs/2026-05-08_add-reset-button.md +26 -0
- specwarden-0.1.0/examples/react-component/Counter.test.tsx +11 -0
- specwarden-0.1.0/examples/react-component/Counter.tsx +22 -0
- specwarden-0.1.0/examples/react-component/README.md +28 -0
- specwarden-0.1.0/examples/react-component/package.json +22 -0
- specwarden-0.1.0/install.ps1 +47 -0
- specwarden-0.1.0/install.sh +58 -0
- specwarden-0.1.0/pyproject.toml +46 -0
- specwarden-0.1.0/src/specwarden/__init__.py +3 -0
- specwarden-0.1.0/src/specwarden/cli.py +179 -0
- specwarden-0.1.0/src/specwarden/coverage.py +55 -0
- specwarden-0.1.0/src/specwarden/decisions.py +43 -0
- specwarden-0.1.0/src/specwarden/git_hook.py +52 -0
- specwarden-0.1.0/src/specwarden/hooks/__init__.py +0 -0
- specwarden-0.1.0/src/specwarden/hooks/post_tool_use.py +66 -0
- specwarden-0.1.0/src/specwarden/hooks/pre_tool_use.py +52 -0
- specwarden-0.1.0/src/specwarden/hooks/session_start.py +27 -0
- specwarden-0.1.0/src/specwarden/paths.py +37 -0
- specwarden-0.1.0/src/specwarden/spec.py +117 -0
- specwarden-0.1.0/src/specwarden/trace.py +38 -0
- specwarden-0.1.0/src/specwarden/trailers.py +17 -0
- specwarden-0.1.0/tests/__init__.py +0 -0
- specwarden-0.1.0/tests/test_cli.py +177 -0
- specwarden-0.1.0/tests/test_coverage.py +52 -0
- specwarden-0.1.0/tests/test_decisions.py +47 -0
- specwarden-0.1.0/tests/test_git_hook.py +102 -0
- specwarden-0.1.0/tests/test_measure.py +134 -0
- specwarden-0.1.0/tests/test_paths.py +37 -0
- specwarden-0.1.0/tests/test_post_tool_use.py +57 -0
- specwarden-0.1.0/tests/test_pre_tool_use.py +50 -0
- specwarden-0.1.0/tests/test_session_start.py +32 -0
- specwarden-0.1.0/tests/test_skill_shims.py +50 -0
- specwarden-0.1.0/tests/test_smoke.py +8 -0
- specwarden-0.1.0/tests/test_spec.py +129 -0
- specwarden-0.1.0/tests/test_trace.py +67 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: specwarden
|
|
3
|
+
description: Use when starting any non-trivial code change in this repo — refuses Edit/Write until a one-page spec is written; logs every accepted edit with a backlink. Activates on `/spec`, `/trace`, `/coverage`, `/spec-help`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# specwarden
|
|
7
|
+
|
|
8
|
+
> Every code change traces back to a written spec. Enforced by hooks, not vibes.
|
|
9
|
+
|
|
10
|
+
## What this does
|
|
11
|
+
|
|
12
|
+
specwarden enforces a spec-first discipline: before any Edit or Write tool call lands, a structured one-page spec must exist and be marked ready. The PreToolUse hook reads `.claude/specs/active` on every tool call; if no spec is active, the hook blocks the call and tells you why. This makes the discipline mechanical rather than voluntary.
|
|
13
|
+
|
|
14
|
+
Once a spec is active, every edit is logged to `.claude/decisions/<spec-id>.md` with a timestamp and a reference back to the spec. When you commit, a `Spec: <id>` trailer is appended automatically (requires `specwarden git-hook install`). The result is a chain you can walk in either direction: from a commit to its spec, or from a spec to every file it touched.
|
|
15
|
+
|
|
16
|
+
## Slash commands
|
|
17
|
+
|
|
18
|
+
### `/spec <slug>`
|
|
19
|
+
|
|
20
|
+
Creates a new spec file at `.claude/specs/<slug>.md` from the four-section template and writes the slug to `.claude/specs/active`. Until all four sections are filled in and you type `ready`, the PreToolUse hook blocks any Edit or Write call with a message indicating which sections are still empty.
|
|
21
|
+
|
|
22
|
+
### `/trace [<commit>]`
|
|
23
|
+
|
|
24
|
+
Prints the full chain for a given commit: commit SHA, the `Spec:` trailer, the spec file, and the corresponding decisions log. Defaults to HEAD when no commit is specified.
|
|
25
|
+
|
|
26
|
+
### `/coverage [--last N]`
|
|
27
|
+
|
|
28
|
+
Scans recent commits (all commits, or the last N if `--last N` is given) and reports how many carry a `Spec:` trailer. Output format: `covered/total commits have spec coverage (pct%)`, followed by a list of uncovered SHAs.
|
|
29
|
+
|
|
30
|
+
### `/spec-help`
|
|
31
|
+
|
|
32
|
+
Prints a one-page quick-reference card: the four slash commands, the spec template, the quick-fix escape hatch, and the path layout.
|
|
33
|
+
|
|
34
|
+
## The four-section spec template
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
# <Spec ID>: <Short Title>
|
|
38
|
+
|
|
39
|
+
**Created:** <ISO timestamp>
|
|
40
|
+
**Status:** active | completed | abandoned
|
|
41
|
+
**Author:** <human name>
|
|
42
|
+
|
|
43
|
+
## Assumptions
|
|
44
|
+
What we are taking as given. If any of these turns out to be false, the spec is
|
|
45
|
+
invalid and must be revised before more code lands.
|
|
46
|
+
|
|
47
|
+
- Assumption 1
|
|
48
|
+
- Assumption 2
|
|
49
|
+
|
|
50
|
+
## Scope
|
|
51
|
+
What this change is. Concrete, files-and-functions level if possible.
|
|
52
|
+
|
|
53
|
+
- We will modify X
|
|
54
|
+
- We will add Y
|
|
55
|
+
- We will not touch Z
|
|
56
|
+
|
|
57
|
+
## Non-goals
|
|
58
|
+
What this change is explicitly not. The point of this section is to prevent
|
|
59
|
+
scope creep mid-implementation.
|
|
60
|
+
|
|
61
|
+
- We will not refactor adjacent module M
|
|
62
|
+
- We will not change the public API of P
|
|
63
|
+
|
|
64
|
+
## Success criteria
|
|
65
|
+
How we will know we are done. Must be checkable.
|
|
66
|
+
|
|
67
|
+
- [ ] Test T passes
|
|
68
|
+
- [ ] Manual scenario S works
|
|
69
|
+
- [ ] Documentation D is updated
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## The discipline
|
|
73
|
+
|
|
74
|
+
1. User describes a feature or fix.
|
|
75
|
+
2. You invoke `/spec <slug>` and fill in all four sections in conversation. Push back on vague assumptions, surface trade-offs, propose non-goals to prevent scope creep.
|
|
76
|
+
3. User reviews the spec and types `ready`.
|
|
77
|
+
4. You proceed to edit. Each edit is appended to `.claude/decisions/<spec-id>.md` with a timestamp.
|
|
78
|
+
5. When the work is done, run `specwarden done` from the terminal (or call the `mark_done` helper) to flip the spec status to `completed`.
|
|
79
|
+
6. Commits made while the spec is active automatically carry a `Spec: <id>` trailer if `specwarden git-hook install` was run beforehand.
|
|
80
|
+
|
|
81
|
+
The spec is not a bureaucratic artifact — it is the conversation record that prevents you and the human from talking past each other mid-implementation. Write it as if someone will read it six months from now to understand why a particular decision was made.
|
|
82
|
+
|
|
83
|
+
## Quick-fix mode
|
|
84
|
+
|
|
85
|
+
For edits where a full spec is genuine overhead — typo fixes, dependency version bumps, comment rewording — set `SPECWARDEN_QUICKFIX=1` in the environment before invoking Claude Code. The PreToolUse hook will allow Edit and Write calls without an active spec. The decisions log will not capture the edit. Use sparingly; the coverage report will mark these commits as uncovered.
|
|
86
|
+
|
|
87
|
+
## Hook contract version
|
|
88
|
+
|
|
89
|
+
This skill targets the Claude Code hook contract published in 2026-Q1:
|
|
90
|
+
|
|
91
|
+
- `PreToolUse` returns `{"permissionDecision": "allow" | "deny" | "ask", "message": "..."}` over stdout.
|
|
92
|
+
- `PostToolUse` returns nothing (exit 0); side effects happen on disk.
|
|
93
|
+
- `SessionStart` writes a banner to stdout.
|
|
94
|
+
|
|
95
|
+
If the hook contract changes in a later Claude Code release, this skill must be updated to match. The CI workflow at `.github/workflows/ci.yml` runs a weekly job that exercises the hook contract against the latest published Claude Code release to catch drift early.
|
|
96
|
+
|
|
97
|
+
## Files this skill writes
|
|
98
|
+
|
|
99
|
+
- `.claude/specs/<spec-id>.md` — the spec document, created by `/spec` or `specwarden new`.
|
|
100
|
+
- `.claude/specs/active` — single line containing the currently active spec ID; read by the PreToolUse hook on every tool call.
|
|
101
|
+
- `.claude/decisions/<spec-id>.md` — append-only log of every edit authorized under the spec.
|
|
102
|
+
- `.claude/settings.json` — hook wiring; created once by `specwarden init` and not modified again by the skill.
|
|
103
|
+
|
|
104
|
+
## Out of scope for v1
|
|
105
|
+
|
|
106
|
+
The skill does not generate specs on behalf of the user. The human writes the spec; that is the forcing function. Auto-generated specs would remove the discipline the tool is designed to create. This is recorded in the project's own SPEC under "Non-goals" for v1.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Slash command shim for activating a spec — delegates to `specwarden activate`."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main(argv: list[str]) -> int:
|
|
11
|
+
if len(argv) < 1:
|
|
12
|
+
print("usage: activate_spec <spec-id>", file=sys.stderr)
|
|
13
|
+
return 2
|
|
14
|
+
return subprocess.call(["specwarden", "activate", argv[0]])
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if __name__ == "__main__":
|
|
18
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Slash command shim for /coverage — delegates to `specwarden coverage`."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main(argv: list[str]) -> int:
|
|
11
|
+
return subprocess.call(["specwarden", "coverage", *argv])
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Slash command shim for /spec — delegates to `specwarden new`."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main(argv: list[str]) -> int:
|
|
11
|
+
if len(argv) < 1:
|
|
12
|
+
print("usage: /spec <slug>", file=sys.stderr)
|
|
13
|
+
return 2
|
|
14
|
+
title = " ".join(argv)
|
|
15
|
+
return subprocess.call(["specwarden", "new", title, "--author", "claude"])
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if __name__ == "__main__":
|
|
19
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Slash command shim for /trace — delegates to `specwarden trace`."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main(argv: list[str]) -> int:
|
|
11
|
+
args = argv if argv else ["HEAD"]
|
|
12
|
+
return subprocess.call(["specwarden", "trace", *args])
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if __name__ == "__main__":
|
|
16
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# {spec_id}: {title}
|
|
2
|
+
|
|
3
|
+
**Created:** {created}
|
|
4
|
+
**Status:** active
|
|
5
|
+
**Author:** {author}
|
|
6
|
+
|
|
7
|
+
## Assumptions
|
|
8
|
+
What we are taking as given. If any of these turns out to be false, the spec is invalid and must be revised before more code lands.
|
|
9
|
+
|
|
10
|
+
- TODO
|
|
11
|
+
|
|
12
|
+
## Scope
|
|
13
|
+
What this change is. Concrete, files-and-functions level if possible.
|
|
14
|
+
|
|
15
|
+
- TODO
|
|
16
|
+
|
|
17
|
+
## Non-goals
|
|
18
|
+
What this change is explicitly not. The point of this section is to prevent scope creep mid-implementation.
|
|
19
|
+
|
|
20
|
+
- TODO
|
|
21
|
+
|
|
22
|
+
## Success criteria
|
|
23
|
+
How we will know we are done. Must be checkable.
|
|
24
|
+
|
|
25
|
+
- [ ] TODO
|
specwarden-0.1.0/.claude/specs/2026-05-28_v1-audit-nits-cli-wrapper-tests-and-caveman-cleanup.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# 2026-05-28_v1-audit-nits-cli-wrapper-tests-and-caveman-cleanup: v1 audit nits CLI wrapper tests and Caveman cleanup
|
|
2
|
+
|
|
3
|
+
**Created:** 2026-05-28T18:44:06+00:00
|
|
4
|
+
**Status:** completed
|
|
5
|
+
**Author:** Amey Ambade
|
|
6
|
+
|
|
7
|
+
## Assumptions
|
|
8
|
+
|
|
9
|
+
- `.claude/internal/V1_AUDIT.md` is still the authoritative pre-launch
|
|
10
|
+
audit. It flags exactly two non-blocking nits:
|
|
11
|
+
(a) `coverage` and `trace` CLI wrappers in `src/specwarden/cli.py`
|
|
12
|
+
lack direct CLI-layer tests (existing coverage is module-level);
|
|
13
|
+
(b) the Caveman section in `docs/COMPARISONS.md` was written from
|
|
14
|
+
the SPEC's secondhand reference, not from the Caveman repo.
|
|
15
|
+
- The current test suite is 63 passing under
|
|
16
|
+
`PYTHONPATH=src .venv/bin/python -m pytest -q`. Adding tests must
|
|
17
|
+
keep that count monotonic and the ruff check clean.
|
|
18
|
+
- The Python 3.14 / hatchling editable-install `.pth` quirk is a
|
|
19
|
+
separate, pre-existing issue (documented in WORKLOG and
|
|
20
|
+
NEXT_SESSION). Not in scope here; CLI invocation uses the
|
|
21
|
+
documented `PYTHONPATH=src python -m specwarden.cli` fallback.
|
|
22
|
+
|
|
23
|
+
## Scope
|
|
24
|
+
|
|
25
|
+
- `tests/test_cli.py`: add two new tests at the bottom of the file,
|
|
26
|
+
next to the existing CliRunner tests.
|
|
27
|
+
- `test_coverage_reports_against_real_commits` — initializes a
|
|
28
|
+
real git repo under `tmp_path`, makes two commits (one with a
|
|
29
|
+
`Spec: <id>` trailer, one without), invokes
|
|
30
|
+
`app, ["coverage", "--last", "10", "--root", str(tmp_path)]`,
|
|
31
|
+
asserts exit code 0 and that stdout contains the
|
|
32
|
+
`"N/M commits have spec coverage"` line plus the uncovered SHA
|
|
33
|
+
prefix.
|
|
34
|
+
- `test_trace_with_active_spec_succeeds` — initializes a real git
|
|
35
|
+
repo, runs `specwarden init` + `new` + `activate` via the CLI to
|
|
36
|
+
produce a real spec file, writes a decisions-log entry for that
|
|
37
|
+
spec, makes a commit whose message body carries
|
|
38
|
+
`Spec: <spec-id>`, invokes
|
|
39
|
+
`app, ["trace", "HEAD", "--root", str(tmp_path)]`, asserts exit
|
|
40
|
+
code 0 and that stdout contains the spec id and the `---`
|
|
41
|
+
separators emitted by `trace_commit`.
|
|
42
|
+
- `docs/COMPARISONS.md`: rewrite only the Caveman section
|
|
43
|
+
(`## Caveman` through the section break before
|
|
44
|
+
`## Summary table`). Replace specific reception claims ("5K+ stars
|
|
45
|
+
quickly", "10K upvotes on r/ClaudeAI") with neutral structural
|
|
46
|
+
language. Keep the "what shares" / "what differs" / "when to use
|
|
47
|
+
both" subsection structure. Update the Summary-table row for
|
|
48
|
+
Caveman only if a column claim no longer holds; if it still holds
|
|
49
|
+
structurally, leave the row alone.
|
|
50
|
+
- `.claude/internal/V1_AUDIT.md`: tick both nits closed in the
|
|
51
|
+
"Remaining work" column for DoD #1 row and in the post-launch
|
|
52
|
+
notes if present.
|
|
53
|
+
- `.claude/internal/WORKLOG.md`: append a single new entry
|
|
54
|
+
documenting the change and the spec ID.
|
|
55
|
+
- One commit, conventional-commit format
|
|
56
|
+
(`test(cli): ...` or `chore: close v1 audit nits ...`), with a
|
|
57
|
+
`Spec: 2026-05-28_v1-audit-nits-cli-wrapper-tests-and-caveman-cleanup`
|
|
58
|
+
trailer in the body.
|
|
59
|
+
|
|
60
|
+
## Non-goals
|
|
61
|
+
|
|
62
|
+
- Not fixing the Python 3.14 / hatchling editable-install `.pth`
|
|
63
|
+
quirk. That is a separate issue and deserves its own spec.
|
|
64
|
+
- Not adding tests for any command other than `coverage` and
|
|
65
|
+
`trace`. The audit named exactly those two.
|
|
66
|
+
- Not running the Caveman repo through a fact-finding fetch.
|
|
67
|
+
The user explicitly chose "Replace the secondhand claims with
|
|
68
|
+
neutral language" over the verify-and-correct option.
|
|
69
|
+
- Not changing the comparison structure or summary table for
|
|
70
|
+
GitHub Spec Kit, CLAUDE.md, Cursor, or MCP. Only the Caveman
|
|
71
|
+
section is in scope.
|
|
72
|
+
- Not bumping the package version. This is launch-prep polish, not
|
|
73
|
+
a release.
|
|
74
|
+
|
|
75
|
+
## Success criteria
|
|
76
|
+
|
|
77
|
+
- [ ] `PYTHONPATH=src .venv/bin/python -m pytest -q` reports
|
|
78
|
+
65 passed (was 63).
|
|
79
|
+
- [ ] `uv run ruff check .` is clean.
|
|
80
|
+
- [ ] `uv run ruff format --check .` is clean.
|
|
81
|
+
- [ ] `docs/COMPARISONS.md` Caveman section contains no specific
|
|
82
|
+
star count or upvote claim. The "what shares" / "what
|
|
83
|
+
differs" framing remains intact.
|
|
84
|
+
- [ ] `.claude/internal/V1_AUDIT.md` shows both nits resolved.
|
|
85
|
+
- [ ] One git commit lands with the `Spec:` trailer pointing at
|
|
86
|
+
this spec id. `git log -1 --format=%B | grep -F 'Spec: 2026-05-28_v1-audit-nits-cli-wrapper-tests-and-caveman-cleanup'`
|
|
87
|
+
returns a match.
|
|
88
|
+
- [ ] Spec marked done via
|
|
89
|
+
`python -m specwarden.cli done --root .` after the commit
|
|
90
|
+
lands. `.claude/specs/active` removed; the spec file's
|
|
91
|
+
status frontmatter reads `completed`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copy this file to .env.eval and fill in your key.
|
|
2
|
+
# .env.eval is gitignored via the .env.* rule in .gitignore.
|
|
3
|
+
#
|
|
4
|
+
# Required for `python evals/run_eval.py` when invoking `claude --bare`,
|
|
5
|
+
# which strips OAuth/keychain auth and reads only ANTHROPIC_API_KEY.
|
|
6
|
+
#
|
|
7
|
+
# Get a key at https://console.anthropic.com/settings/keys.
|
|
8
|
+
# Billing for the eval run hits your Anthropic API account, not your
|
|
9
|
+
# Claude Code subscription.
|
|
10
|
+
|
|
11
|
+
ANTHROPIC_API_KEY=sk-ant-your-key-here
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
test:
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
os: [ubuntu-latest, macos-latest]
|
|
21
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
22
|
+
runs-on: ${{ matrix.os }}
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
- uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
cache: "pip"
|
|
29
|
+
- run: pip install -e '.[dev]'
|
|
30
|
+
- run: ruff check .
|
|
31
|
+
- run: ruff format --check .
|
|
32
|
+
- run: pytest --cov=specwarden --cov-report=term-missing
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "[0-9]+.[0-9]+.[0-9]+"
|
|
7
|
+
- "[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: release-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
test:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.12"
|
|
24
|
+
cache: "pip"
|
|
25
|
+
- run: pip install -e '.[dev]'
|
|
26
|
+
- run: ruff check .
|
|
27
|
+
- run: ruff format --check .
|
|
28
|
+
- run: pytest --cov=specwarden --cov-report=term-missing
|
|
29
|
+
|
|
30
|
+
build:
|
|
31
|
+
needs: test
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
- uses: actions/setup-python@v5
|
|
36
|
+
with:
|
|
37
|
+
python-version: "3.12"
|
|
38
|
+
- run: pip install build
|
|
39
|
+
- run: python -m build
|
|
40
|
+
- uses: actions/upload-artifact@v4
|
|
41
|
+
with:
|
|
42
|
+
name: dist
|
|
43
|
+
path: dist/
|
|
44
|
+
|
|
45
|
+
publish:
|
|
46
|
+
needs: build
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
environment: pypi
|
|
49
|
+
permissions:
|
|
50
|
+
id-token: write
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/download-artifact@v4
|
|
53
|
+
with:
|
|
54
|
+
name: dist
|
|
55
|
+
path: dist/
|
|
56
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
57
|
+
with:
|
|
58
|
+
packages-dir: dist/
|
|
59
|
+
# Trusted Publisher: no `password` field needed.
|
|
60
|
+
# PyPI verifies the OIDC token from GitHub against the
|
|
61
|
+
# publisher config at https://pypi.org/manage/account/publishing/
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
MANIFEST
|
|
23
|
+
|
|
24
|
+
# Virtualenvs
|
|
25
|
+
.venv/
|
|
26
|
+
venv/
|
|
27
|
+
env/
|
|
28
|
+
ENV/
|
|
29
|
+
|
|
30
|
+
# Tooling
|
|
31
|
+
.pytest_cache/
|
|
32
|
+
.ruff_cache/
|
|
33
|
+
.coverage
|
|
34
|
+
htmlcov/
|
|
35
|
+
.mypy_cache/
|
|
36
|
+
.tox/
|
|
37
|
+
|
|
38
|
+
# Editor / OS
|
|
39
|
+
.DS_Store
|
|
40
|
+
.idea/
|
|
41
|
+
.vscode/
|
|
42
|
+
*.swp
|
|
43
|
+
*~
|
|
44
|
+
|
|
45
|
+
# Internal tracking — not part of the published artifact
|
|
46
|
+
.claude/internal/
|
|
47
|
+
|
|
48
|
+
# OMC state
|
|
49
|
+
.omc/
|
|
50
|
+
|
|
51
|
+
# Claude Code local settings (per-machine permission cache)
|
|
52
|
+
.claude/settings.local.json
|
|
53
|
+
|
|
54
|
+
# uv lockfile (project uses pip via pyproject.toml; uv lockfile is generated by side-tooling)
|
|
55
|
+
uv.lock
|
|
56
|
+
|
|
57
|
+
# Eval artifacts that should not be committed wholesale
|
|
58
|
+
evals/results/_local/
|
|
59
|
+
evals/.cache/
|
|
60
|
+
|
|
61
|
+
# Local secrets
|
|
62
|
+
.env
|
|
63
|
+
.env.*
|
|
64
|
+
!.env.example
|
|
65
|
+
!.env.*.example
|
|
66
|
+
|
|
67
|
+
# Launch-prep notes (personal; not part of public repo)
|
|
68
|
+
.claude/GIF_RECORDING.md
|
|
69
|
+
.claude/launch.md
|
|
70
|
+
.claude/medium-post.md
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# specwarden — working notes
|
|
2
|
+
|
|
3
|
+
This file is the standing context for anyone (human or agent) working on this repo.
|
|
4
|
+
Read it before touching code. Update it when conventions change.
|
|
5
|
+
|
|
6
|
+
## What we are building
|
|
7
|
+
|
|
8
|
+
`specwarden` is a Claude Code skill plus a set of lifecycle hooks that gate
|
|
9
|
+
filesystem edits behind a written spec. It also ships a Python CLI and an
|
|
10
|
+
eval suite. The full requirements live in `SPEC_specwarden.md` at the repo
|
|
11
|
+
root — that file is the single source of truth for v1 scope.
|
|
12
|
+
|
|
13
|
+
If anything here drifts from `SPEC_specwarden.md`, the SPEC wins.
|
|
14
|
+
|
|
15
|
+
## Working directories
|
|
16
|
+
|
|
17
|
+
| Path | Purpose |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `SPEC_specwarden.md` | Authoritative spec for v1. Treat as read-only unless the user changes scope. |
|
|
20
|
+
| `docs/superpowers/plans/` | Implementation plan(s). The active one is `2026-05-07-specwarden-v1.md`. |
|
|
21
|
+
| `.claude/skills/specwarden/` | The published skill artifact (SKILL.md, scripts, templates). Ships with the package. |
|
|
22
|
+
| `.claude/internal/` | Tracking notes for this build. Gitignored. Worklog, project context, feature specs go here. |
|
|
23
|
+
| `src/specwarden/` | Python CLI package. `pipx install specwarden` installs the entry point. |
|
|
24
|
+
| `hooks/` | Standalone hook scripts copied into the user repo by `specwarden init`. |
|
|
25
|
+
| `evals/` | Three-arm benchmark. Fixtures, runner, results. |
|
|
26
|
+
| `examples/` | Reference projects that show specwarden in use. |
|
|
27
|
+
| `docs/` | Public-facing markdown docs. |
|
|
28
|
+
|
|
29
|
+
## Conventions
|
|
30
|
+
|
|
31
|
+
- Python 3.10+. Use `from __future__ import annotations` and standard library
|
|
32
|
+
where possible. Third-party deps: `typer`, `pytest`. Add more only with a
|
|
33
|
+
reason recorded in the plan.
|
|
34
|
+
- Tests live next to code under `tests/<module>/test_<thing>.py`. Use `pytest`,
|
|
35
|
+
not `unittest`. Aim for one assertion per test where practical.
|
|
36
|
+
- Format with `ruff format`. Lint with `ruff check`. Both run in CI.
|
|
37
|
+
- Markdown is written for engineers reading on a laptop. No marketing tone,
|
|
38
|
+
no superlatives, no AI tells. Headings are sentence case.
|
|
39
|
+
- Commits follow Conventional Commits (`feat:`, `fix:`, `docs:`, `test:`,
|
|
40
|
+
`chore:`, `refactor:`). Subject under 72 chars. No emoji in commits or docs.
|
|
41
|
+
Do not tag releases with a `v` prefix.
|
|
42
|
+
- Every commit that lands real code should carry a `Spec: <spec-id>` trailer.
|
|
43
|
+
The CLI is responsible for keeping that easy.
|
|
44
|
+
- Keep files small and focused. Split when one file owns more than one job.
|
|
45
|
+
|
|
46
|
+
## Spec → decisions → commit chain
|
|
47
|
+
|
|
48
|
+
This is the discipline the project itself tries to enforce, so we eat our own
|
|
49
|
+
dog food while building it:
|
|
50
|
+
|
|
51
|
+
1. Before touching code for a new chunk of work, write a spec under
|
|
52
|
+
`.claude/specs/` (use the four-section template once it exists).
|
|
53
|
+
2. Set the active spec in `.claude/specs/active`.
|
|
54
|
+
3. Make changes. Each edit gets logged to `.claude/decisions/<spec-id>.md`.
|
|
55
|
+
4. Commit with a `Spec: <spec-id>` trailer.
|
|
56
|
+
|
|
57
|
+
For the bootstrap phase we may write specs by hand because the tooling does
|
|
58
|
+
not exist yet. Once the CLI lands (Phase 1 complete), switch to the tooling.
|
|
59
|
+
|
|
60
|
+
## How to run things
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Install the package in editable mode for local work
|
|
64
|
+
pipx install -e .
|
|
65
|
+
|
|
66
|
+
# Run tests
|
|
67
|
+
pytest
|
|
68
|
+
|
|
69
|
+
# Lint and format
|
|
70
|
+
ruff check .
|
|
71
|
+
ruff format .
|
|
72
|
+
|
|
73
|
+
# Run the eval (slow, costs API tokens)
|
|
74
|
+
make eval
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Until `pyproject.toml` is in place, only the planning files exist. See the
|
|
78
|
+
implementation plan for the bootstrap order.
|
|
79
|
+
|
|
80
|
+
## Things to watch out for
|
|
81
|
+
|
|
82
|
+
- The Claude Code hook contract (JSON shape, `permissionDecision` values) is
|
|
83
|
+
the integration surface with the host tool. Pin the hook version we target
|
|
84
|
+
in `SKILL.md` and add a CI test that exercises it.
|
|
85
|
+
- The `.claude/specs/active` file is the synchronization point between hooks
|
|
86
|
+
and the CLI. Treat it as a single line, no trailing whitespace, no BOM.
|
|
87
|
+
- The eval suite uses `claude` headless mode. Document the exact CLI flags
|
|
88
|
+
used so the benchmark is reproducible.
|
|
89
|
+
- Do not auto-generate specs. The whole product loses its meaning if specs
|
|
90
|
+
are produced by the same agent the spec is supposed to constrain.
|
|
91
|
+
|
|
92
|
+
## Out of scope (do not build)
|
|
93
|
+
|
|
94
|
+
See the SPEC's "Non-goals" section. Short list: no web UI, no Jira-style
|
|
95
|
+
project management, no team features, no AI-generated specs, no external
|
|
96
|
+
tracker integrations, no per-language templates.
|
|
97
|
+
|
|
98
|
+
## Where to write progress
|
|
99
|
+
|
|
100
|
+
- Plan progress: tick boxes in `docs/superpowers/plans/2026-05-07-specwarden-v1.md`.
|
|
101
|
+
- Session log: `.claude/internal/WORKLOG.md` (append at end of each session).
|
|
102
|
+
- Cross-session state: `.claude/internal/PROJECT_CONTEXT.md`.
|
|
103
|
+
- Per-feature notes: `.claude/internal/FEATURE_SPECS.md`.
|
specwarden-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Amey Ambade
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|