project-kit-cli 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.
- project_kit_cli-0.1.0/LICENSE +21 -0
- project_kit_cli-0.1.0/PKG-INFO +97 -0
- project_kit_cli-0.1.0/README.md +77 -0
- project_kit_cli-0.1.0/pyproject.toml +63 -0
- project_kit_cli-0.1.0/pyproject.toml.orig +52 -0
- project_kit_cli-0.1.0/src/project_kit/__init__.py +8 -0
- project_kit_cli-0.1.0/src/project_kit/__main__.py +5 -0
- project_kit_cli-0.1.0/src/project_kit/agents.py +81 -0
- project_kit_cli-0.1.0/src/project_kit/ai_attribution.py +69 -0
- project_kit_cli-0.1.0/src/project_kit/approval.py +36 -0
- project_kit_cli-0.1.0/src/project_kit/assets/hooks/commit-msg +14 -0
- project_kit_cli-0.1.0/src/project_kit/assets/project/workflow.yml +63 -0
- project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-decide/SKILL.md +63 -0
- project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-discover/SKILL.md +57 -0
- project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-handoff/SKILL.md +43 -0
- project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-plan/SKILL.md +55 -0
- project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-provision/SKILL.md +45 -0
- project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-start/SKILL.md +47 -0
- project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-workflow/SKILL.md +51 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/adr.md +32 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/backlog.example.json +59 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/brief.md +77 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/constitution-input.md +78 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/development-workflow.md +51 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/github/ISSUE_TEMPLATE/adr.yml +21 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/github/ISSUE_TEMPLATE/bug.yml +25 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/github/ISSUE_TEMPLATE/config.yml +1 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/github/ISSUE_TEMPLATE/epic.yml +15 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/github/ISSUE_TEMPLATE/feature.yml +22 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/github/pull_request_template.md +21 -0
- project_kit_cli-0.1.0/src/project_kit/assets/templates/interview.md +68 -0
- project_kit_cli-0.1.0/src/project_kit/backlog.py +312 -0
- project_kit_cli-0.1.0/src/project_kit/cli.py +286 -0
- project_kit_cli-0.1.0/src/project_kit/config.py +139 -0
- project_kit_cli-0.1.0/src/project_kit/doctor.py +187 -0
- project_kit_cli-0.1.0/src/project_kit/fsutil.py +27 -0
- project_kit_cli-0.1.0/src/project_kit/gh.py +152 -0
- project_kit_cli-0.1.0/src/project_kit/handoff.py +360 -0
- project_kit_cli-0.1.0/src/project_kit/help.py +152 -0
- project_kit_cli-0.1.0/src/project_kit/installer.py +100 -0
- project_kit_cli-0.1.0/src/project_kit/labels.py +17 -0
- project_kit_cli-0.1.0/src/project_kit/project_choice.py +127 -0
- project_kit_cli-0.1.0/src/project_kit/providers/__init__.py +1 -0
- project_kit_cli-0.1.0/src/project_kit/providers/github.py +329 -0
- project_kit_cli-0.1.0/src/project_kit/provision.py +260 -0
- project_kit_cli-0.1.0/src/project_kit/provision_issues.py +360 -0
- project_kit_cli-0.1.0/src/project_kit/state.py +115 -0
- project_kit_cli-0.1.0/src/project_kit/templating.py +23 -0
- project_kit_cli-0.1.0/src/project_kit/workflow.py +168 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Miguel Tomás
|
|
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.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: project-kit-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Project definition and dev-workflow kit that hands off to Spec Kit
|
|
5
|
+
Keywords: project-management,spec-kit,claude-code,workflow,github
|
|
6
|
+
Author: Miguel Tomás
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Software Development
|
|
15
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Project-URL: Repository, https://github.com/miguelmatg/project-kit
|
|
18
|
+
Project-URL: Issues, https://github.com/miguelmatg/project-kit/issues
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# project-kit
|
|
22
|
+
|
|
23
|
+
Herramienta para el **antes** de un proyecto: definirlo, planificarlo, decidir su
|
|
24
|
+
arquitectura y montar su flujo de desarrollo y gestión (GitHub primero, GitLab después).
|
|
25
|
+
Al terminar entrega el relevo a [Spec Kit](https://github.com/github/spec-kit), que define e
|
|
26
|
+
implementa cada spec.
|
|
27
|
+
|
|
28
|
+
> Estado: diseño y esqueleto del paquete (v0.1 en desarrollo). Ver [`docs/design.md`](docs/design.md).
|
|
29
|
+
|
|
30
|
+
## Instalación y uso
|
|
31
|
+
|
|
32
|
+
Requisitos: [uv](https://docs.astral.sh/uv/), `git`, y [`gh`](https://cli.github.com/) con
|
|
33
|
+
sesión iniciada y los scopes `repo` y `project` (`gh auth refresh -s project`) para publicar en
|
|
34
|
+
GitHub. [Claude Code](https://claude.com/claude-code) es el agente que guía las fases.
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
# Instalar (ahora, desde un clon; cuando se publique será `uv tool install project-kit-cli`; el comando es `project-kit`)
|
|
38
|
+
uv tool install --editable <ruta-a-este-clon>
|
|
39
|
+
|
|
40
|
+
# En el repositorio del proyecto (puede estar vacío)
|
|
41
|
+
project-kit doctor # comprueba las herramientas
|
|
42
|
+
project-kit init # instala skills y plantillas; pregunta si la IA firma commits y si abrir Claude
|
|
43
|
+
project-kit help # guía visual del flujo y los comandos (también: `project-kit` a secas)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`init` copia los ficheros y, al terminar, muestra los agentes de IA soportados (hoy solo Claude
|
|
47
|
+
Code) y ofrece abrirlo en esa misma terminal ya con **`/pk-start`** (Intro acepta). Se puede
|
|
48
|
+
evitar con `--agent none`; sin terminal no pregunta ni lanza nada, y dentro de Claude Code no
|
|
49
|
+
abre otro. Si lo prefieres, ábrelo tú y ejecuta `/pk-start`. Pregunta si quieres **solo
|
|
50
|
+
inicializar** o **empezar a definir el proyecto**, y al terminar cada fase ofrece continuar o
|
|
51
|
+
parar. `project-kit status` muestra en qué fase estás y cuál toca.
|
|
52
|
+
|
|
53
|
+
| Fase | Skill | Qué hace | Salida |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| 0 | `/pk-start` | Comprueba el entorno y elige: solo inicializar o empezar | `.project-kit/` |
|
|
56
|
+
| 1 | `/pk-discover` | Entrevista sobre qué es el proyecto | `docs/project/brief.md` |
|
|
57
|
+
| 2 | `/pk-decide` | Guía las decisiones de stack y arquitectura | `docs/adr/*.md` |
|
|
58
|
+
| 3 | `/pk-workflow` | Acuerda el flujo de trabajo del equipo | `docs/development-workflow.md` |
|
|
59
|
+
| 4 | `/pk-plan` | Deriva fases, épicas y backlog | `roadmap.md`, `backlog.json` |
|
|
60
|
+
| 5 | `/pk-provision` | Crea milestones, ramas, Project e issues | GitHub |
|
|
61
|
+
| 6 | `/pk-handoff` | Relevo a Spec Kit (una spec por issue) | `constitution-input.md` |
|
|
62
|
+
|
|
63
|
+
Cada fase termina con una aprobación (`project-kit approve <fase>`) y puede rellenarse a mano
|
|
64
|
+
a partir de las plantillas de `.project-kit/templates/`. Las fases se listan en
|
|
65
|
+
`.project-kit/workflow.yml`, con el mismo estilo que el de Spec Kit; para un proyecto pequeño se
|
|
66
|
+
desactiva una con `enabled: false`.
|
|
67
|
+
|
|
68
|
+
## Documentación
|
|
69
|
+
|
|
70
|
+
- [Diseño](docs/design.md): alcance, fases, proveedor, relevo a Spec Kit, decisiones abiertas.
|
|
71
|
+
- [Publicación](docs/publishing.md): qué hace falta para `uv tool install project-kit-cli` público.
|
|
72
|
+
- [Esquema de `backlog.json`](docs/backlog-schema.md): formato del backlog y reglas de validación.
|
|
73
|
+
- [Relevo a Spec Kit](docs/handoff.md): qué genera `handoff`, cómo instala Spec Kit y qué viene después.
|
|
74
|
+
- [Provisionado en GitHub](docs/provisioning.md): qué crea `provision`, idempotencia y protección de ramas.
|
|
75
|
+
- [Referencia: playbook del flujo](docs/references/template-repo-playbook.md): receta de origen
|
|
76
|
+
(extraída de otro proyecto).
|
|
77
|
+
|
|
78
|
+
## Licencia y contribuciones
|
|
79
|
+
|
|
80
|
+
MIT ([`LICENSE`](LICENSE)). Las issues con ideas y mejoras son bienvenidas; el código lo
|
|
81
|
+
desarrolla solo su autor y las pull requests están desactivadas ([`CONTRIBUTING.md`](CONTRIBUTING.md)).
|
|
82
|
+
|
|
83
|
+
## Ramas
|
|
84
|
+
|
|
85
|
+
`main` (estable), `release` (pruebas) y `develop` (desarrollo). Todo entra por PR.
|
|
86
|
+
|
|
87
|
+
## Desarrollo
|
|
88
|
+
|
|
89
|
+
Requiere [uv](https://docs.astral.sh/uv/).
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
uv sync # entorno y dependencias
|
|
93
|
+
uv run project-kit --version
|
|
94
|
+
uv run pytest # tests
|
|
95
|
+
uv run ruff check . # lint
|
|
96
|
+
uv run ruff format . # formato
|
|
97
|
+
```
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# project-kit
|
|
2
|
+
|
|
3
|
+
Herramienta para el **antes** de un proyecto: definirlo, planificarlo, decidir su
|
|
4
|
+
arquitectura y montar su flujo de desarrollo y gestión (GitHub primero, GitLab después).
|
|
5
|
+
Al terminar entrega el relevo a [Spec Kit](https://github.com/github/spec-kit), que define e
|
|
6
|
+
implementa cada spec.
|
|
7
|
+
|
|
8
|
+
> Estado: diseño y esqueleto del paquete (v0.1 en desarrollo). Ver [`docs/design.md`](docs/design.md).
|
|
9
|
+
|
|
10
|
+
## Instalación y uso
|
|
11
|
+
|
|
12
|
+
Requisitos: [uv](https://docs.astral.sh/uv/), `git`, y [`gh`](https://cli.github.com/) con
|
|
13
|
+
sesión iniciada y los scopes `repo` y `project` (`gh auth refresh -s project`) para publicar en
|
|
14
|
+
GitHub. [Claude Code](https://claude.com/claude-code) es el agente que guía las fases.
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
# Instalar (ahora, desde un clon; cuando se publique será `uv tool install project-kit-cli`; el comando es `project-kit`)
|
|
18
|
+
uv tool install --editable <ruta-a-este-clon>
|
|
19
|
+
|
|
20
|
+
# En el repositorio del proyecto (puede estar vacío)
|
|
21
|
+
project-kit doctor # comprueba las herramientas
|
|
22
|
+
project-kit init # instala skills y plantillas; pregunta si la IA firma commits y si abrir Claude
|
|
23
|
+
project-kit help # guía visual del flujo y los comandos (también: `project-kit` a secas)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`init` copia los ficheros y, al terminar, muestra los agentes de IA soportados (hoy solo Claude
|
|
27
|
+
Code) y ofrece abrirlo en esa misma terminal ya con **`/pk-start`** (Intro acepta). Se puede
|
|
28
|
+
evitar con `--agent none`; sin terminal no pregunta ni lanza nada, y dentro de Claude Code no
|
|
29
|
+
abre otro. Si lo prefieres, ábrelo tú y ejecuta `/pk-start`. Pregunta si quieres **solo
|
|
30
|
+
inicializar** o **empezar a definir el proyecto**, y al terminar cada fase ofrece continuar o
|
|
31
|
+
parar. `project-kit status` muestra en qué fase estás y cuál toca.
|
|
32
|
+
|
|
33
|
+
| Fase | Skill | Qué hace | Salida |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| 0 | `/pk-start` | Comprueba el entorno y elige: solo inicializar o empezar | `.project-kit/` |
|
|
36
|
+
| 1 | `/pk-discover` | Entrevista sobre qué es el proyecto | `docs/project/brief.md` |
|
|
37
|
+
| 2 | `/pk-decide` | Guía las decisiones de stack y arquitectura | `docs/adr/*.md` |
|
|
38
|
+
| 3 | `/pk-workflow` | Acuerda el flujo de trabajo del equipo | `docs/development-workflow.md` |
|
|
39
|
+
| 4 | `/pk-plan` | Deriva fases, épicas y backlog | `roadmap.md`, `backlog.json` |
|
|
40
|
+
| 5 | `/pk-provision` | Crea milestones, ramas, Project e issues | GitHub |
|
|
41
|
+
| 6 | `/pk-handoff` | Relevo a Spec Kit (una spec por issue) | `constitution-input.md` |
|
|
42
|
+
|
|
43
|
+
Cada fase termina con una aprobación (`project-kit approve <fase>`) y puede rellenarse a mano
|
|
44
|
+
a partir de las plantillas de `.project-kit/templates/`. Las fases se listan en
|
|
45
|
+
`.project-kit/workflow.yml`, con el mismo estilo que el de Spec Kit; para un proyecto pequeño se
|
|
46
|
+
desactiva una con `enabled: false`.
|
|
47
|
+
|
|
48
|
+
## Documentación
|
|
49
|
+
|
|
50
|
+
- [Diseño](docs/design.md): alcance, fases, proveedor, relevo a Spec Kit, decisiones abiertas.
|
|
51
|
+
- [Publicación](docs/publishing.md): qué hace falta para `uv tool install project-kit-cli` público.
|
|
52
|
+
- [Esquema de `backlog.json`](docs/backlog-schema.md): formato del backlog y reglas de validación.
|
|
53
|
+
- [Relevo a Spec Kit](docs/handoff.md): qué genera `handoff`, cómo instala Spec Kit y qué viene después.
|
|
54
|
+
- [Provisionado en GitHub](docs/provisioning.md): qué crea `provision`, idempotencia y protección de ramas.
|
|
55
|
+
- [Referencia: playbook del flujo](docs/references/template-repo-playbook.md): receta de origen
|
|
56
|
+
(extraída de otro proyecto).
|
|
57
|
+
|
|
58
|
+
## Licencia y contribuciones
|
|
59
|
+
|
|
60
|
+
MIT ([`LICENSE`](LICENSE)). Las issues con ideas y mejoras son bienvenidas; el código lo
|
|
61
|
+
desarrolla solo su autor y las pull requests están desactivadas ([`CONTRIBUTING.md`](CONTRIBUTING.md)).
|
|
62
|
+
|
|
63
|
+
## Ramas
|
|
64
|
+
|
|
65
|
+
`main` (estable), `release` (pruebas) y `develop` (desarrollo). Todo entra por PR.
|
|
66
|
+
|
|
67
|
+
## Desarrollo
|
|
68
|
+
|
|
69
|
+
Requiere [uv](https://docs.astral.sh/uv/).
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
uv sync # entorno y dependencias
|
|
73
|
+
uv run project-kit --version
|
|
74
|
+
uv run pytest # tests
|
|
75
|
+
uv run ruff check . # lint
|
|
76
|
+
uv run ruff format . # formato
|
|
77
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "project-kit-cli"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Project definition and dev-workflow kit that hands off to Spec Kit"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
keywords = [
|
|
10
|
+
"project-management",
|
|
11
|
+
"spec-kit",
|
|
12
|
+
"claude-code",
|
|
13
|
+
"workflow",
|
|
14
|
+
"github",
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Topic :: Software Development",
|
|
23
|
+
]
|
|
24
|
+
dependencies = ["pyyaml>=6.0.3"]
|
|
25
|
+
|
|
26
|
+
[[project.authors]]
|
|
27
|
+
name = "Miguel Tomás"
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Repository = "https://github.com/miguelmatg/project-kit"
|
|
31
|
+
Issues = "https://github.com/miguelmatg/project-kit/issues"
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
project-kit = "project_kit.cli:main"
|
|
35
|
+
|
|
36
|
+
[tool.uv.build-backend]
|
|
37
|
+
module-name = "project_kit"
|
|
38
|
+
|
|
39
|
+
[tool.pytest.ini_options]
|
|
40
|
+
testpaths = ["tests"]
|
|
41
|
+
|
|
42
|
+
[tool.ruff]
|
|
43
|
+
line-length = 100
|
|
44
|
+
target-version = "py312"
|
|
45
|
+
|
|
46
|
+
[tool.ruff.lint]
|
|
47
|
+
select = [
|
|
48
|
+
"E",
|
|
49
|
+
"F",
|
|
50
|
+
"I",
|
|
51
|
+
"UP",
|
|
52
|
+
"B",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[build-system]
|
|
56
|
+
requires = ["uv_build>=0.13.1,<0.14.0"]
|
|
57
|
+
build-backend = "uv_build"
|
|
58
|
+
|
|
59
|
+
[dependency-groups]
|
|
60
|
+
dev = [
|
|
61
|
+
"pytest>=8",
|
|
62
|
+
"ruff>=0.8",
|
|
63
|
+
]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "project-kit-cli"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Project definition and dev-workflow kit that hands off to Spec Kit"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "Miguel Tomás" }]
|
|
10
|
+
keywords = ["project-management", "spec-kit", "claude-code", "workflow", "github"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 3 - Alpha",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Topic :: Software Development",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"pyyaml>=6.0.3",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Repository = "https://github.com/miguelmatg/project-kit"
|
|
25
|
+
Issues = "https://github.com/miguelmatg/project-kit/issues"
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
project-kit = "project_kit.cli:main"
|
|
29
|
+
|
|
30
|
+
[tool.uv.build-backend]
|
|
31
|
+
# The distribution is project-kit-cli (the name free on PyPI); the package keeps its name.
|
|
32
|
+
module-name = "project_kit"
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["uv_build>=0.13.1,<0.14.0"]
|
|
36
|
+
build-backend = "uv_build"
|
|
37
|
+
|
|
38
|
+
[dependency-groups]
|
|
39
|
+
dev = [
|
|
40
|
+
"pytest>=8",
|
|
41
|
+
"ruff>=0.8",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
testpaths = ["tests"]
|
|
46
|
+
|
|
47
|
+
[tool.ruff]
|
|
48
|
+
line-length = 100
|
|
49
|
+
target-version = "py312"
|
|
50
|
+
|
|
51
|
+
[tool.ruff.lint]
|
|
52
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""project-kit: define, plan and set up a project before handing off to Spec Kit."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = version("project-kit-cli")
|
|
7
|
+
except PackageNotFoundError: # running from a source tree that was never installed
|
|
8
|
+
__version__ = "0.0.0"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""AI coding agents project-kit can hand the terminal over to after ``init``.
|
|
2
|
+
|
|
3
|
+
An agent is whatever reads the installed skills and runs ``/pk-start``. Today that is Claude
|
|
4
|
+
Code only; supporting another one is a new entry in ``AGENTS``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import shutil
|
|
9
|
+
import subprocess
|
|
10
|
+
from collections.abc import Callable, Mapping
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class Agent:
|
|
17
|
+
id: str
|
|
18
|
+
name: str
|
|
19
|
+
executable: str
|
|
20
|
+
prompt: str # what the agent is started with: the entry-point skill
|
|
21
|
+
install_hint: str
|
|
22
|
+
inside_env: str # environment variable the agent sets in the shells it opens
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
AGENTS = (
|
|
26
|
+
Agent(
|
|
27
|
+
id="claude",
|
|
28
|
+
name="Claude Code",
|
|
29
|
+
executable="claude",
|
|
30
|
+
prompt="/pk-start",
|
|
31
|
+
install_hint="https://claude.com/claude-code",
|
|
32
|
+
inside_env="CLAUDECODE",
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
AGENT_IDS = tuple(a.id for a in AGENTS)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_agent(agent_id: str) -> Agent:
|
|
39
|
+
return next(a for a in AGENTS if a.id == agent_id)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def is_inside(agent: Agent, env: Mapping[str, str] | None = None) -> bool:
|
|
43
|
+
"""True when we run from a shell opened by this agent: launching it again would nest."""
|
|
44
|
+
return bool((os.environ if env is None else env).get(agent.inside_env))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def find_executable(agent: Agent) -> str | None:
|
|
48
|
+
return shutil.which(agent.executable)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def choose(
|
|
52
|
+
ask: Callable[[str], str] | None = None,
|
|
53
|
+
out: Callable[[str], None] = print,
|
|
54
|
+
) -> Agent | None:
|
|
55
|
+
"""Ask which agent to open now. Enter takes the first one. ``None``: the user declines."""
|
|
56
|
+
out("\nOpen an AI agent now to continue with /pk-start?")
|
|
57
|
+
for n, agent in enumerate(AGENTS, 1):
|
|
58
|
+
out(f" {n}) {agent.name}")
|
|
59
|
+
none = len(AGENTS) + 1
|
|
60
|
+
out(f" {none}) No, I will do it myself")
|
|
61
|
+
try:
|
|
62
|
+
answer = (ask or input)("Choice [1]: ").strip()
|
|
63
|
+
except EOFError: # no terminal attached: never launch anything
|
|
64
|
+
return None
|
|
65
|
+
if answer == "":
|
|
66
|
+
return AGENTS[0]
|
|
67
|
+
if answer.isdigit() and 1 <= int(answer) <= len(AGENTS):
|
|
68
|
+
return AGENTS[int(answer) - 1]
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def launch(agent: Agent, root: Path, run: Callable[..., object] = subprocess.run) -> int:
|
|
73
|
+
"""Run the agent in the current terminal, in ``root``, started with its entry skill.
|
|
74
|
+
|
|
75
|
+
Returns the agent's exit code; the terminal is inherited, so it is interactive.
|
|
76
|
+
"""
|
|
77
|
+
exe = find_executable(agent)
|
|
78
|
+
if exe is None:
|
|
79
|
+
raise FileNotFoundError(agent.executable)
|
|
80
|
+
result = run([exe, agent.prompt], cwd=root, check=False)
|
|
81
|
+
return getattr(result, "returncode", 0)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Keep AI assistants out of the commit history when the project asks for it.
|
|
2
|
+
|
|
3
|
+
Two layers, because each assistant removes itself in its own way:
|
|
4
|
+
|
|
5
|
+
* Claude Code has its own setting (``attribution`` in ``.claude/settings.json``), which stops
|
|
6
|
+
it from adding the co-author trailer and the "Generated with" line.
|
|
7
|
+
* For any other assistant, and as a safety net, a ``commit-msg`` git hook strips co-author
|
|
8
|
+
trailers that name a known AI tool. It lives in ``.githooks/`` so it is versioned and the
|
|
9
|
+
whole team gets it; it is switched on with ``git config core.hooksPath .githooks``.
|
|
10
|
+
|
|
11
|
+
Both only ever add what is missing; nothing the user wrote is overwritten.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import contextlib
|
|
15
|
+
import json
|
|
16
|
+
import os
|
|
17
|
+
from importlib.resources import files
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
from project_kit.fsutil import atomic_write_text
|
|
21
|
+
|
|
22
|
+
CLAUDE_SETTINGS = Path(".claude") / "settings.json"
|
|
23
|
+
HOOK = Path(".githooks") / "commit-msg"
|
|
24
|
+
HOOKS_PATH_COMMAND = "git config core.hooksPath .githooks"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def configure_claude(root: Path) -> tuple[Path | None, str]:
|
|
28
|
+
"""Make Claude Code stop signing commits and PRs. Returns (changed file or None, note)."""
|
|
29
|
+
path = root / CLAUDE_SETTINGS
|
|
30
|
+
data: dict = {}
|
|
31
|
+
if path.exists():
|
|
32
|
+
try:
|
|
33
|
+
loaded = json.loads(path.read_text(encoding="utf-8"))
|
|
34
|
+
except json.JSONDecodeError:
|
|
35
|
+
return None, f"{CLAUDE_SETTINGS.as_posix()} is not valid JSON; left alone."
|
|
36
|
+
if not isinstance(loaded, dict):
|
|
37
|
+
return None, f"{CLAUDE_SETTINGS.as_posix()} is not a JSON object; left alone."
|
|
38
|
+
data = loaded
|
|
39
|
+
|
|
40
|
+
attribution = data.get("attribution")
|
|
41
|
+
attribution = dict(attribution) if isinstance(attribution, dict) else {}
|
|
42
|
+
if attribution.get("commit") == "" and attribution.get("pr") == "":
|
|
43
|
+
return None, ""
|
|
44
|
+
attribution["commit"] = ""
|
|
45
|
+
attribution["pr"] = ""
|
|
46
|
+
data["attribution"] = attribution
|
|
47
|
+
atomic_write_text(path, json.dumps(data, indent=2, ensure_ascii=False) + "\n")
|
|
48
|
+
return CLAUDE_SETTINGS, ""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def install_hook(root: Path) -> tuple[Path | None, str]:
|
|
52
|
+
"""Copy the commit-msg hook unless the project already has one. Returns (new file, note)."""
|
|
53
|
+
dest = root / HOOK
|
|
54
|
+
if dest.exists():
|
|
55
|
+
return None, ""
|
|
56
|
+
script = (files("project_kit") / "assets" / "hooks" / "commit-msg").read_text("utf-8")
|
|
57
|
+
atomic_write_text(dest, script)
|
|
58
|
+
with contextlib.suppress(OSError): # no executable bit on some filesystems (Windows)
|
|
59
|
+
os.chmod(dest, 0o755)
|
|
60
|
+
return HOOK, ""
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def hook_is_active(root: Path) -> bool:
|
|
64
|
+
"""True if git is already pointed at ``.githooks`` in this repository."""
|
|
65
|
+
config = root / ".git" / "config"
|
|
66
|
+
if not config.is_file():
|
|
67
|
+
return False
|
|
68
|
+
text = config.read_text(encoding="utf-8", errors="replace")
|
|
69
|
+
return any("".join(line.split()).lower() == "hookspath=.githooks" for line in text.splitlines())
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Approval gates: record that the user signed off on a phase."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from project_kit.backlog import load_backlog
|
|
6
|
+
from project_kit.config import load_config
|
|
7
|
+
from project_kit.state import PHASES, State, StateError, load_state, save_state
|
|
8
|
+
from project_kit.workflow import load_workflow
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def approve_phase(root: Path, phase: str) -> State:
|
|
12
|
+
"""Record the approval of ``phase`` in the project state.
|
|
13
|
+
|
|
14
|
+
A gate refuses to open while an earlier enabled gate of ``workflow.yml`` is still open,
|
|
15
|
+
so the plan cannot be approved before the brief. The ``plan`` gate also refuses to open
|
|
16
|
+
unless the backlog on disk is valid, so an approval always refers to a backlog that
|
|
17
|
+
provisioning can use.
|
|
18
|
+
"""
|
|
19
|
+
if phase not in PHASES:
|
|
20
|
+
raise StateError(f"Unknown phase {phase!r}. Phases: {', '.join(PHASES)}")
|
|
21
|
+
load_config(root) # the project must have been initialised
|
|
22
|
+
state = load_state(root)
|
|
23
|
+
open_gates = load_workflow(root).open_gates_before(phase, state)
|
|
24
|
+
if open_gates:
|
|
25
|
+
names = ", ".join(f"{s.id} (/{s.skill})" for s in open_gates)
|
|
26
|
+
raise StateError(
|
|
27
|
+
f"Cannot approve {phase!r} yet: approve first {names}. "
|
|
28
|
+
"To skip a phase, set `enabled: false` on it in .project-kit/workflow.yml."
|
|
29
|
+
)
|
|
30
|
+
if phase == "plan":
|
|
31
|
+
load_backlog(root)
|
|
32
|
+
state.approve(phase)
|
|
33
|
+
if PHASES.index(phase) > PHASES.index(state.phase):
|
|
34
|
+
state.phase = phase
|
|
35
|
+
save_state(root, state)
|
|
36
|
+
return state
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# project-kit: keep AI assistants out of the commit history.
|
|
3
|
+
# Removes "Co-authored-by:" trailers added by AI tools, and their "Generated with" lines.
|
|
4
|
+
# Enable with: git config core.hooksPath .githooks
|
|
5
|
+
file="$1"
|
|
6
|
+
tmp="$file.pk-tmp"
|
|
7
|
+
grep -v -i -E \
|
|
8
|
+
-e '^co-authored-by:.*(claude|anthropic|copilot|openai|chatgpt|codex|gemini|cursor|aider|devin)' \
|
|
9
|
+
-e '^.*generated with.*(claude|copilot|codex|gemini|cursor)' \
|
|
10
|
+
"$file" > "$tmp"
|
|
11
|
+
# grep exits 1 when nothing is left (an empty message): keep that case valid and silent.
|
|
12
|
+
cat "$tmp" > "$file"
|
|
13
|
+
rm -f "$tmp"
|
|
14
|
+
exit 0
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# project-kit workflow: the phases a project goes through before it is handed to Spec Kit.
|
|
2
|
+
# Safe to edit by hand. Same idea as Spec Kit's workflow.yml: an ordered list of steps with
|
|
3
|
+
# review gates, read by the skills to know what comes next.
|
|
4
|
+
#
|
|
5
|
+
# gate: true the phase ends with an explicit approval (`project-kit approve <id>`)
|
|
6
|
+
# enabled: false skip the phase (small projects); later gates stop waiting for it
|
|
7
|
+
#
|
|
8
|
+
# The order is fixed and the ids are the ones project-kit knows; only `enabled`, `gate`,
|
|
9
|
+
# `title` and `produces` are meant to be changed.
|
|
10
|
+
schema_version: "1.0"
|
|
11
|
+
workflow:
|
|
12
|
+
id: "project-kit"
|
|
13
|
+
name: "Project definition flow"
|
|
14
|
+
description: "From an idea to a provisioned repository and a Spec Kit handoff"
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- id: init
|
|
18
|
+
title: "Set up project-kit in the repository"
|
|
19
|
+
skill: pk-start
|
|
20
|
+
gate: false
|
|
21
|
+
produces:
|
|
22
|
+
- .project-kit/config.yml
|
|
23
|
+
|
|
24
|
+
- id: discover
|
|
25
|
+
title: "Define what the project is: problem, users, scope, constraints"
|
|
26
|
+
skill: pk-discover
|
|
27
|
+
gate: true
|
|
28
|
+
produces:
|
|
29
|
+
- docs/project/brief.md
|
|
30
|
+
|
|
31
|
+
- id: decide
|
|
32
|
+
title: "Decide the stack and the architecture"
|
|
33
|
+
skill: pk-decide
|
|
34
|
+
gate: true
|
|
35
|
+
produces:
|
|
36
|
+
- docs/adr/
|
|
37
|
+
|
|
38
|
+
- id: workflow
|
|
39
|
+
title: "Agree how the team will work: branches, reviews, quality gates"
|
|
40
|
+
skill: pk-workflow
|
|
41
|
+
gate: true
|
|
42
|
+
produces:
|
|
43
|
+
- docs/development-workflow.md
|
|
44
|
+
|
|
45
|
+
- id: plan
|
|
46
|
+
title: "Turn it all into phases, epics and a backlog"
|
|
47
|
+
skill: pk-plan
|
|
48
|
+
gate: true
|
|
49
|
+
produces:
|
|
50
|
+
- docs/project/roadmap.md
|
|
51
|
+
- .project-kit/backlog.json
|
|
52
|
+
|
|
53
|
+
- id: provision
|
|
54
|
+
title: "Create milestones, labels, branches, the Project and the issues"
|
|
55
|
+
skill: pk-provision
|
|
56
|
+
gate: false
|
|
57
|
+
|
|
58
|
+
- id: handoff
|
|
59
|
+
title: "Hand over to Spec Kit: constitution, then one spec per issue"
|
|
60
|
+
skill: pk-handoff
|
|
61
|
+
gate: true
|
|
62
|
+
produces:
|
|
63
|
+
- .project-kit/handoff/constitution-input.md
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pk-decide
|
|
3
|
+
description: Guide the user through the technical and architectural decisions of the project (repository structure, language, framework, package manager, data, auth, hosting, CI) and record each one as an ADR in docs/adr/. Use when the user wants to choose the stack or architecture, or to revisit a decision.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# pk-decide — phase 2
|
|
7
|
+
|
|
8
|
+
Turn the brief into **decisions**: one ADR per decision, with the options considered and the
|
|
9
|
+
reason for the choice. project-kit does not choose for the user; it makes the choice
|
|
10
|
+
explicit, argued and written down. The ADRs feed the plan and, later, the Spec Kit
|
|
11
|
+
constitution.
|
|
12
|
+
|
|
13
|
+
Read `.project-kit/templates/interview.md` first and follow it. ADRs use
|
|
14
|
+
`.project-kit/templates/adr.md`, are named `docs/adr/NNNN-short-title.md` (next free number)
|
|
15
|
+
and can also be written by hand.
|
|
16
|
+
|
|
17
|
+
## Inputs
|
|
18
|
+
|
|
19
|
+
- `docs/project/brief.md`, especially "Constraints" and "Technical preferences already
|
|
20
|
+
stated". Preferences are proposals to confirm, not decisions.
|
|
21
|
+
- Existing `docs/adr/*.md`: never decide twice. To change a decision, write a new ADR and mark
|
|
22
|
+
the old one `Superseded by ADR-NNNN`.
|
|
23
|
+
|
|
24
|
+
## Steps
|
|
25
|
+
|
|
26
|
+
1. **List the decisions this project needs**, from this checklist and from the brief; leave
|
|
27
|
+
out whatever does not apply (a command-line tool has no auth or hosting question):
|
|
28
|
+
- Repository: single repository, monorepo or several repositories; monolith or separate
|
|
29
|
+
services.
|
|
30
|
+
- Language and runtime; framework(s).
|
|
31
|
+
- Package manager and, for monorepos, workspace and build tooling (for example pnpm, npm,
|
|
32
|
+
yarn, uv, cargo workspaces, turborepo, nx).
|
|
33
|
+
- Data: storage, migrations, backups.
|
|
34
|
+
- Authentication and authorisation.
|
|
35
|
+
- API style and integrations with external services.
|
|
36
|
+
- Hosting, environments and deployment; CI.
|
|
37
|
+
- Testing approach and tools; observability.
|
|
38
|
+
- Anything the brief marks as legal or compliance-driven.
|
|
39
|
+
2. **Show the list** and ask which ones are *critical* now (they block planning) and which
|
|
40
|
+
can wait. In "light" mode, only decide the critical ones. Deferred decisions are written
|
|
41
|
+
as `Status: Proposed` or left for a later `pk-decide`.
|
|
42
|
+
3. **For each decision, one at a time:**
|
|
43
|
+
1. Ask the question in the interview format: options with pros and cons for *this*
|
|
44
|
+
project, a recommendation with the reason, and what depends on the answer. Use the
|
|
45
|
+
brief's constraints (team skills, budget, scale, compliance) as the drivers.
|
|
46
|
+
2. If a decision follows from an earlier one (a framework implies a language), do not ask:
|
|
47
|
+
state it and record it in the ADR as a consequence.
|
|
48
|
+
3. After the answer, write the ADR immediately (`Status: Accepted`, today's date) and tell
|
|
49
|
+
the user its path.
|
|
50
|
+
4. **Check consistency** across ADRs: no contradictory choices (for example a package manager
|
|
51
|
+
that the chosen framework does not support). Raise any conflict as a question.
|
|
52
|
+
5. **Present** the list of ADRs with their status and anything still undecided.
|
|
53
|
+
6. **Approval gate.** When the critical ADRs are accepted and the user explicitly approves,
|
|
54
|
+
run `project-kit approve decide`.
|
|
55
|
+
7. Run `project-kit status` and offer `pk-workflow` next: continue now, or stop here.
|
|
56
|
+
|
|
57
|
+
## Rules
|
|
58
|
+
|
|
59
|
+
- Do not decide on the user's behalf and do not present your recommendation as settled.
|
|
60
|
+
- Never invent versions, prices or benchmarks; if a fact matters and you are not sure, say so
|
|
61
|
+
and mark it `[NEEDS CLARIFICATION]`.
|
|
62
|
+
- Keep each ADR to one decision. Write them in the language of `config.yml`.
|
|
63
|
+
- The `Status:` line matters: the handoff reads it to build the constitution.
|