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.
Files changed (49) hide show
  1. project_kit_cli-0.1.0/LICENSE +21 -0
  2. project_kit_cli-0.1.0/PKG-INFO +97 -0
  3. project_kit_cli-0.1.0/README.md +77 -0
  4. project_kit_cli-0.1.0/pyproject.toml +63 -0
  5. project_kit_cli-0.1.0/pyproject.toml.orig +52 -0
  6. project_kit_cli-0.1.0/src/project_kit/__init__.py +8 -0
  7. project_kit_cli-0.1.0/src/project_kit/__main__.py +5 -0
  8. project_kit_cli-0.1.0/src/project_kit/agents.py +81 -0
  9. project_kit_cli-0.1.0/src/project_kit/ai_attribution.py +69 -0
  10. project_kit_cli-0.1.0/src/project_kit/approval.py +36 -0
  11. project_kit_cli-0.1.0/src/project_kit/assets/hooks/commit-msg +14 -0
  12. project_kit_cli-0.1.0/src/project_kit/assets/project/workflow.yml +63 -0
  13. project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-decide/SKILL.md +63 -0
  14. project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-discover/SKILL.md +57 -0
  15. project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-handoff/SKILL.md +43 -0
  16. project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-plan/SKILL.md +55 -0
  17. project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-provision/SKILL.md +45 -0
  18. project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-start/SKILL.md +47 -0
  19. project_kit_cli-0.1.0/src/project_kit/assets/skills/pk-workflow/SKILL.md +51 -0
  20. project_kit_cli-0.1.0/src/project_kit/assets/templates/adr.md +32 -0
  21. project_kit_cli-0.1.0/src/project_kit/assets/templates/backlog.example.json +59 -0
  22. project_kit_cli-0.1.0/src/project_kit/assets/templates/brief.md +77 -0
  23. project_kit_cli-0.1.0/src/project_kit/assets/templates/constitution-input.md +78 -0
  24. project_kit_cli-0.1.0/src/project_kit/assets/templates/development-workflow.md +51 -0
  25. project_kit_cli-0.1.0/src/project_kit/assets/templates/github/ISSUE_TEMPLATE/adr.yml +21 -0
  26. project_kit_cli-0.1.0/src/project_kit/assets/templates/github/ISSUE_TEMPLATE/bug.yml +25 -0
  27. project_kit_cli-0.1.0/src/project_kit/assets/templates/github/ISSUE_TEMPLATE/config.yml +1 -0
  28. project_kit_cli-0.1.0/src/project_kit/assets/templates/github/ISSUE_TEMPLATE/epic.yml +15 -0
  29. project_kit_cli-0.1.0/src/project_kit/assets/templates/github/ISSUE_TEMPLATE/feature.yml +22 -0
  30. project_kit_cli-0.1.0/src/project_kit/assets/templates/github/pull_request_template.md +21 -0
  31. project_kit_cli-0.1.0/src/project_kit/assets/templates/interview.md +68 -0
  32. project_kit_cli-0.1.0/src/project_kit/backlog.py +312 -0
  33. project_kit_cli-0.1.0/src/project_kit/cli.py +286 -0
  34. project_kit_cli-0.1.0/src/project_kit/config.py +139 -0
  35. project_kit_cli-0.1.0/src/project_kit/doctor.py +187 -0
  36. project_kit_cli-0.1.0/src/project_kit/fsutil.py +27 -0
  37. project_kit_cli-0.1.0/src/project_kit/gh.py +152 -0
  38. project_kit_cli-0.1.0/src/project_kit/handoff.py +360 -0
  39. project_kit_cli-0.1.0/src/project_kit/help.py +152 -0
  40. project_kit_cli-0.1.0/src/project_kit/installer.py +100 -0
  41. project_kit_cli-0.1.0/src/project_kit/labels.py +17 -0
  42. project_kit_cli-0.1.0/src/project_kit/project_choice.py +127 -0
  43. project_kit_cli-0.1.0/src/project_kit/providers/__init__.py +1 -0
  44. project_kit_cli-0.1.0/src/project_kit/providers/github.py +329 -0
  45. project_kit_cli-0.1.0/src/project_kit/provision.py +260 -0
  46. project_kit_cli-0.1.0/src/project_kit/provision_issues.py +360 -0
  47. project_kit_cli-0.1.0/src/project_kit/state.py +115 -0
  48. project_kit_cli-0.1.0/src/project_kit/templating.py +23 -0
  49. 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,5 @@
1
+ import sys
2
+
3
+ from project_kit.cli import main
4
+
5
+ sys.exit(main())
@@ -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.