spawnio 1.0.7__tar.gz → 1.0.9__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 (145) hide show
  1. spawnio-1.0.9/CONTRIBUTING.md +178 -0
  2. {spawnio-1.0.7 → spawnio-1.0.9}/PKG-INFO +63 -15
  3. {spawnio-1.0.7 → spawnio-1.0.9}/README.md +62 -14
  4. spawnio-1.0.9/docs/architecture.md +257 -0
  5. {spawnio-1.0.7 → spawnio-1.0.9}/docs/changelog.md +34 -0
  6. {spawnio-1.0.7 → spawnio-1.0.9}/docs/commands.md +112 -36
  7. {spawnio-1.0.7 → spawnio-1.0.9}/docs/getting-started.md +24 -3
  8. {spawnio-1.0.7 → spawnio-1.0.9}/pyproject.toml +13 -1
  9. spawnio-1.0.9/src/spawn/__init__.py +6 -0
  10. spawnio-1.0.9/src/spawn/cli/app.py +362 -0
  11. spawnio-1.0.9/src/spawn/cli/errors.py +29 -0
  12. spawnio-1.0.9/src/spawn/cli/noninteractive.py +125 -0
  13. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/cli/prompts.py +47 -43
  14. spawnio-1.0.9/src/spawn/core/exceptions.py +50 -0
  15. spawnio-1.0.9/src/spawn/core/models.py +58 -0
  16. spawnio-1.0.7/src/spawn/cli/noninteractive.py → spawnio-1.0.9/src/spawn/core/planning.py +39 -84
  17. spawnio-1.0.9/src/spawn/core/project.py +59 -0
  18. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/core/registry.py +85 -16
  19. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/generators/custom_structure.py +60 -39
  20. spawnio-1.0.9/src/spawn/generators/destination.py +66 -0
  21. spawnio-1.0.9/src/spawn/generators/metadata.py +45 -0
  22. spawnio-1.0.9/src/spawn/generators/pipeline.py +32 -0
  23. spawnio-1.0.9/src/spawn/generators/project_files.py +191 -0
  24. spawnio-1.0.9/src/spawn/generators/project_generator.py +132 -0
  25. spawnio-1.0.9/src/spawn/github/exceptions.py +5 -0
  26. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/github/publisher.py +6 -15
  27. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/github/validators.py +1 -4
  28. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/agent/__init__.py +48 -46
  29. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/agent/content.py +13 -12
  30. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/automation/__init__.py +2 -7
  31. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/backend_api/__init__.py +2 -4
  32. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/chatbot/__init__.py +84 -73
  33. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/chatbot/content.py +15 -13
  34. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/cli_application/__init__.py +17 -10
  35. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/__init__.py +5 -12
  36. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/analysis/__init__.py +7 -6
  37. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/analysis/content.py +1 -0
  38. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/dashboard/__init__.py +7 -6
  39. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/dashboard/content.py +1 -0
  40. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/etl/__init__.py +9 -8
  41. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/etl/content.py +1 -0
  42. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/ml/__init__.py +8 -7
  43. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/ml/content.py +1 -0
  44. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/mcp_server/__init__.py +6 -6
  45. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/rag/__init__.py +17 -17
  46. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/rag/content.py +1 -0
  47. spawnio-1.0.9/src/spawn/templates/shared_content.py +184 -0
  48. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/doctor.py +43 -39
  49. spawnio-1.0.9/src/spawn/utils/doctor_fix.py +226 -0
  50. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/git.py +32 -17
  51. spawnio-1.0.9/src/spawn/utils/redact.py +8 -0
  52. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/success.py +12 -7
  53. spawnio-1.0.9/src/spawn/utils/theme.py +25 -0
  54. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/uv.py +5 -9
  55. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/validators.py +8 -5
  56. spawnio-1.0.9/tests/conftest.py +46 -0
  57. spawnio-1.0.9/tests/fixtures/__init__.py +0 -0
  58. spawnio-1.0.9/tests/fixtures/archetypes.py +11 -0
  59. spawnio-1.0.9/tests/fixtures/static/broken_meta/.spawn/meta.json +1 -0
  60. spawnio-1.0.9/tests/fixtures/static/meta_unknown_intent/.spawn/meta.json +11 -0
  61. spawnio-1.0.9/tests/fixtures/static/non_spawn_python_repo/pyproject.toml +3 -0
  62. spawnio-1.0.9/tests/fixtures/static/non_spawn_python_repo/src/pkg/__init__.py +1 -0
  63. spawnio-1.0.9/tests/fixtures/static/non_spawn_python_repo/tests/test_x.py +2 -0
  64. spawnio-1.0.9/tests/fixtures/trees/agent.txt +20 -0
  65. spawnio-1.0.9/tests/fixtures/trees/automation.txt +20 -0
  66. spawnio-1.0.9/tests/fixtures/trees/backend-api.txt +16 -0
  67. spawnio-1.0.9/tests/fixtures/trees/chatbot.txt +22 -0
  68. spawnio-1.0.9/tests/fixtures/trees/cli.txt +12 -0
  69. spawnio-1.0.9/tests/fixtures/trees/custom.txt +4 -0
  70. spawnio-1.0.9/tests/fixtures/trees/data.txt +12 -0
  71. spawnio-1.0.9/tests/fixtures/trees/mcp.txt +11 -0
  72. spawnio-1.0.9/tests/fixtures/trees/rag.txt +21 -0
  73. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_agent_generator.py +15 -9
  74. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_agent_template.py +22 -14
  75. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_app.py +170 -25
  76. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_automation_generator.py +6 -3
  77. spawnio-1.0.9/tests/test_boundaries.py +35 -0
  78. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_chatbot_generator.py +43 -22
  79. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_chatbot_template.py +136 -105
  80. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_cli_application_generator.py +106 -33
  81. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_cli_application_template.py +13 -6
  82. spawnio-1.0.9/tests/test_create_flags.py +203 -0
  83. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_custom_structure.py +123 -47
  84. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_custom_structure_integration.py +33 -14
  85. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_data_project_analysis.py +9 -7
  86. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_data_project_dashboard.py +5 -3
  87. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_data_project_etl.py +5 -3
  88. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_data_project_gitignore.py +16 -8
  89. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_data_project_ml.py +5 -3
  90. spawnio-1.0.9/tests/test_destination.py +238 -0
  91. spawnio-1.0.9/tests/test_docs.py +42 -0
  92. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_doctor.py +54 -23
  93. spawnio-1.0.9/tests/test_doctor_fix.py +223 -0
  94. spawnio-1.0.9/tests/test_errors.py +219 -0
  95. spawnio-1.0.9/tests/test_fixtures.py +158 -0
  96. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_generator.py +213 -50
  97. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_git.py +1 -0
  98. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_github_publisher.py +7 -21
  99. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_github_validators.py +5 -15
  100. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_mcp_server_generator.py +10 -6
  101. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_models.py +48 -4
  102. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_noninteractive.py +59 -12
  103. spawnio-1.0.9/tests/test_pipeline.py +135 -0
  104. spawnio-1.0.9/tests/test_planning.py +160 -0
  105. spawnio-1.0.9/tests/test_project.py +88 -0
  106. spawnio-1.0.9/tests/test_project_files.py +371 -0
  107. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_prompts.py +174 -81
  108. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_rag_generator.py +15 -8
  109. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_rag_template.py +23 -8
  110. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_registry.py +60 -2
  111. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_templates.py +15 -5
  112. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_uv.py +1 -3
  113. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_validators.py +13 -5
  114. spawnio-1.0.7/.github/workflows/ci.yml +0 -29
  115. spawnio-1.0.7/.github/workflows/publish.yml +0 -24
  116. spawnio-1.0.7/.python-version +0 -1
  117. spawnio-1.0.7/assets/preview.png +0 -0
  118. spawnio-1.0.7/docs/architecture.md +0 -194
  119. spawnio-1.0.7/src/spawn/__init__.py +0 -6
  120. spawnio-1.0.7/src/spawn/cli/app.py +0 -217
  121. spawnio-1.0.7/src/spawn/core/exceptions.py +0 -7
  122. spawnio-1.0.7/src/spawn/core/models.py +0 -21
  123. spawnio-1.0.7/src/spawn/generators/project_generator.py +0 -115
  124. spawnio-1.0.7/src/spawn/github/exceptions.py +0 -5
  125. spawnio-1.0.7/src/spawn/templates/shared_content.py +0 -89
  126. spawnio-1.0.7/src/spawn/utils/theme.py +0 -25
  127. spawnio-1.0.7/uv.lock +0 -218
  128. {spawnio-1.0.7 → spawnio-1.0.9}/.gitignore +0 -0
  129. {spawnio-1.0.7 → spawnio-1.0.9}/LICENSE +0 -0
  130. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/cli/__init__.py +0 -0
  131. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/core/__init__.py +0 -0
  132. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/generators/__init__.py +0 -0
  133. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/github/__init__.py +0 -0
  134. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/__init__.py +0 -0
  135. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/automation/content.py +0 -0
  136. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/backend_api/content.py +0 -0
  137. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/base.py +0 -0
  138. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/cli_application/content.py +0 -0
  139. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/mcp_server/content.py +0 -0
  140. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/__init__.py +0 -0
  141. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/banner.py +0 -0
  142. {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/console.py +0 -0
  143. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_automation_template.py +0 -0
  144. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_console.py +0 -0
  145. {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_mcp_server_template.py +0 -0
@@ -0,0 +1,178 @@
1
+ # Contributing to spawnio
2
+
3
+ Solo-maintained, but PRs are welcome. Here's what you need to know.
4
+
5
+ ---
6
+
7
+ ## Prerequisites
8
+
9
+ - Python 3.12+ (`uv python install 3.12` if using uv)
10
+ - [uv](https://github.com/astral-sh/uv) installed
11
+
12
+ ---
13
+
14
+ ## Setup
15
+
16
+ ```bash
17
+ git clone https://github.com/Abhiix0/Spawn.git
18
+ cd Spawn
19
+ uv sync --all-groups
20
+ ```
21
+
22
+ ---
23
+
24
+ ## Running tests
25
+
26
+ ```bash
27
+ uv run pytest
28
+ ```
29
+
30
+ With coverage:
31
+
32
+ ```bash
33
+ uv run pytest --cov=src/spawn --cov-report=term-missing
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Testing and fixtures
39
+
40
+ - **Factory:** the `spawn_project` fixture in `tests/conftest.py` generates a project offline: `spawn_project("backend-api", framework="fastapi")` returns its `Path`. The `no_toolchain` fixture stubs git, uv and package installs.
41
+ - **Golden trees:** `tests/fixtures/trees/<archetype>.txt` lists every file of a generated archetype. After an intentional output change, regenerate with `SPAWN_UPDATE_TREES=1 uv run pytest tests/test_fixtures.py` and review the diff.
42
+ - **Offline rule:** tests must not use the network, real `git` or real `uv`; use `no_toolchain`.
43
+ - **Adding an archetype:** add an entry to `tests/fixtures/archetypes.py`, run once with `SPAWN_UPDATE_TREES=1` to create its golden tree, and review it.
44
+
45
+ ---
46
+
47
+ ## Linting and formatting
48
+
49
+ ```bash
50
+ uv run ruff check .
51
+ uv run ruff format .
52
+ ```
53
+
54
+ Both must pass before opening a PR. CI enforces this.
55
+
56
+ ---
57
+
58
+ ## Adding a new template
59
+
60
+ Templates follow a consistent three-file pattern. MCP Server (`src/spawn/templates/mcp_server/`) is the cleanest minimal example to copy from.
61
+
62
+ ### 1. Create the template package
63
+
64
+ ```
65
+ src/spawn/templates/<your_slug>/
66
+ __init__.py # MyTemplate(BaseTemplate) class
67
+ content.py # string constants + make_readme() + make_agents_md()
68
+ ```
69
+
70
+ **`content.py`** holds all file content as triple-quoted strings with `{project_name}` placeholders (resolved later via `.format_map(context)`). Export `make_readme()` and `make_agents_md()` as functions that return the formatted string — these are called by `BaseTemplate` machinery automatically.
71
+
72
+ **`__init__.py`** subclasses `BaseTemplate`:
73
+
74
+ ```python
75
+ class MyTemplate(BaseTemplate):
76
+ def __init__(self, extras: list[str] | None = None) -> None:
77
+ self.extras = extras or []
78
+ super().__init__(
79
+ name="My Template",
80
+ folders=["src", "tests"],
81
+ starter_files=[
82
+ ("src/__init__.py", INIT_CONTENT),
83
+ ("src/main.py", MAIN_CONTENT),
84
+ (".env.example", ENV_CONTENT),
85
+ ],
86
+ next_steps=["cd {project_name}", "uv run python -m src.main"],
87
+ )
88
+
89
+ def get_readme_content(self, context: dict) -> str | None:
90
+ return make_readme().format_map(context)
91
+
92
+ def get_agents_md_content(self, context: dict) -> str | None:
93
+ return make_agents_md().format_map(context)
94
+
95
+ def get_dependencies(self) -> list[str]:
96
+ base = ["some-package"]
97
+ if "pytest" in self.extras:
98
+ base.append("pytest")
99
+ return base
100
+
101
+ def post_install(self, project_path: Path) -> None:
102
+ # Write pyproject.toml sections, CI workflows, etc. as needed.
103
+ pass
104
+ ```
105
+
106
+ If your template needs framework or provider selection, look at `ChatbotTemplate` or `AgentTemplate` — those accept `framework` and `provider` constructor args and use `get_supported_providers()` to filter the provider list per framework.
107
+
108
+ ### 2. Register in `src/spawn/core/registry.py`
109
+
110
+ Add an import and a `TemplateMetadata` entry to `TEMPLATES`:
111
+
112
+ ```python
113
+ from spawn.templates.my_template import MyTemplate
114
+
115
+ TEMPLATES = {
116
+ # ... existing entries ...
117
+ "my-slug": TemplateMetadata(
118
+ slug="my-slug",
119
+ display_name="My Template",
120
+ description="One-line description shown in spawn doctor output",
121
+ template_class=MyTemplate,
122
+ available_extras=["ruff", "pytest", "github-actions"],
123
+ # available_frameworks, available_providers, available_cli_types,
124
+ # available_data_types — only set the fields your template uses.
125
+ ),
126
+ }
127
+ ```
128
+
129
+ `instantiate_template()` inspects the constructor signature and forwards only the fields the class accepts, so no changes to that function are needed.
130
+
131
+ ### 3. Write tests
132
+
133
+ Add two test files mirroring the existing pattern:
134
+
135
+ | File | What to test |
136
+ |---|---|
137
+ | `tests/test_<slug>_template.py` | Template constants, `get_dependencies()`, `get_readme_content()`, `py_compile` on each Python starter file, no unescaped braces |
138
+ | `tests/test_<slug>_generator.py` | `generate_project(config)` (or `ProjectGenerator().generate()`) with mocked uv/git/install, directory structure, README content, `.spawn/meta.json` fields |
139
+
140
+ See `tests/test_mcp_server_template.py` and `tests/test_mcp_server_generator.py` for the exact mock patterns (`_mock_uv_and_install()` context manager, `_cfg()` helper, `patch.object(MyTemplate, "post_install")`).
141
+
142
+ Also update `tests/test_registry.py`: increment the `len(slugs) == N` assertion and add `assert "my-slug" in slugs`.
143
+
144
+ ---
145
+
146
+ ## Branch and commit conventions
147
+
148
+ The git log uses a lightweight conventional-commits style — prefix commits with `feat:`, `fix:`, `docs:`, or `chore:` and use the imperative mood in the subject line:
149
+
150
+ ```
151
+ feat: add <slug> template
152
+ fix: handle edge case in parse_structure
153
+ docs: update CONTRIBUTING.md
154
+ chore: bump version to 1.0.8
155
+ ```
156
+
157
+ Branch off `main`, use a short descriptive name (`feat/my-template`, `fix/windows-path`, etc.).
158
+
159
+ ---
160
+
161
+ ## PR expectations
162
+
163
+ - All existing tests must pass (`uv run pytest`).
164
+ - New templates require both a `_template` and a `_generator` test file.
165
+ - `uv run ruff check .` and `uv run ruff format --check .` must be clean.
166
+ - CI (`.github/workflows/ci.yml`) must be green.
167
+ - Keep PRs focused — one template or fix per PR.
168
+
169
+ ---
170
+
171
+ ## Reporting issues / asking questions
172
+
173
+ GitHub Issues are currently **restricted** on this repo. To reach the maintainer:
174
+
175
+ - Open a [GitHub Discussion](https://github.com/Abhiix0/Spawn/discussions) if Discussions are enabled.
176
+ - Otherwise, leave a comment on an existing PR or tag `@Abhiix0` in your PR description.
177
+
178
+ If you hit a bug that's blocking you, a PR with a failing test that reproduces it is a faster path to a fix than waiting for issues to be opened.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: spawnio
3
- Version: 1.0.7
3
+ Version: 1.0.9
4
4
  Summary: Spawn a ready-to-use Python project in seconds
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -88,6 +88,7 @@ It's repetitive. It's inconsistent. And you haven't written a single line of *re
88
88
  | **Arrow-key menus** | Every prompt in `spawn create` is arrow-key/spacebar driven, not typed numbers |
89
89
  | **GitHub publishing** | Connects your project to an existing GitHub repo and pushes the initial commit |
90
90
  | **spawn doctor** | Scores your project's health out of 100, with per-category breakdowns and a prioritized next step |
91
+ | **spawn doctor --fix** | Fixes missing files and config automatically — never overwrites, never installs packages |
91
92
 
92
93
  ---
93
94
 
@@ -143,7 +144,7 @@ Running `spawn` with no arguments shows the banner, the installed version, and t
143
144
 
144
145
  ```
145
146
  SPAWN — scaffold your next project
146
- v1.0.6
147
+ v1.0.9
147
148
 
148
149
  Commands
149
150
  create Scaffold a new project
@@ -190,7 +191,15 @@ Use the arrow keys to move, Enter to select — the same pattern every prompt in
190
191
 
191
192
  **Step 3 — Additional prompts** *(template-dependent — framework, provider, project type, and/or extras, depending on what you picked. See [Project Templates](#project-templates) below for each one's exact flow.)*
192
193
 
193
- **Step 4 — Git**
194
+ **Step 4 — License**
195
+
196
+ ```
197
+ ? Choose a license (Use arrow keys)
198
+ » MIT
199
+ None
200
+ ```
201
+
202
+ **Step 5 — Git**
194
203
 
195
204
  ```
196
205
  Initialize Git? [Y/n]: Y
@@ -253,9 +262,11 @@ my-api/
253
262
  ● pytest
254
263
  ○ docker
255
264
  ○ github-actions
265
+ ○ pre-commit
266
+ ○ mypy
256
267
  ```
257
268
 
258
- **Available extras:** `ruff` `pytest` `docker` `github-actions`
269
+ **Available extras:** `ruff` `pytest` `docker` `github-actions` `pre-commit` `mypy`
259
270
 
260
271
  **Run it:**
261
272
 
@@ -306,9 +317,11 @@ my-cli/
306
317
  ● ruff
307
318
  ● pytest
308
319
  ○ github-actions
320
+ ○ pre-commit
321
+ ○ mypy
309
322
  ```
310
323
 
311
- **Available extras:** `ruff` `pytest` `github-actions`
324
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
312
325
 
313
326
  **Run it:**
314
327
 
@@ -345,9 +358,11 @@ my-automation/
345
358
  ● ruff
346
359
  ● pytest
347
360
  ○ github-actions
361
+ ○ pre-commit
362
+ ○ mypy
348
363
  ```
349
364
 
350
- **Available extras:** `ruff` `pytest` `github-actions`
365
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
351
366
 
352
367
  **Run it:**
353
368
 
@@ -397,9 +412,11 @@ my-chatbot/
397
412
  ● pytest
398
413
  ○ rich
399
414
  ○ github-actions
415
+ ○ pre-commit
416
+ ○ mypy
400
417
  ```
401
418
 
402
- **Available extras:** `ruff` `pytest` `rich` `github-actions`
419
+ **Available extras:** `ruff` `pytest` `rich` `github-actions` `pre-commit` `mypy`
403
420
 
404
421
  **Run it:**
405
422
 
@@ -447,11 +464,13 @@ my-agent/
447
464
  ● ruff
448
465
  ● pytest
449
466
  ○ github-actions
467
+ ○ pre-commit
468
+ ○ mypy
450
469
  ```
451
470
 
452
471
  > If you pick `openai-agents`, only `openai` and `openrouter` appear as provider choices — the list is filtered per framework.
453
472
 
454
- **Available extras:** `ruff` `pytest` `github-actions`
473
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
455
474
 
456
475
  **Run it:**
457
476
 
@@ -492,11 +511,13 @@ my-rag/
492
511
  ● ruff
493
512
  ● pytest
494
513
  ○ github-actions
514
+ ○ pre-commit
515
+ ○ mypy
495
516
  ```
496
517
 
497
518
  RAG System uses a fixed stack — **LlamaIndex + ChromaDB + OpenAI** — so there's no framework or provider prompt, unlike Chatbot and Agent. On first run, it automatically ingests documents from `data/` into a local ChromaDB index, then lets you ask questions against them. Requires an `OPENAI_API_KEY` (used for both the LLM and embeddings).
498
519
 
499
- **Available extras:** `ruff` `pytest` `github-actions`
520
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
500
521
 
501
522
  **Run it:**
502
523
 
@@ -540,9 +561,11 @@ my-data-project/
540
561
  ● ruff
541
562
  ● pytest
542
563
  ○ github-actions
564
+ ○ pre-commit
565
+ ○ mypy
543
566
  ```
544
567
 
545
- **Available extras:** `ruff` `pytest` `github-actions`
568
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
546
569
 
547
570
  **Run it:**
548
571
 
@@ -586,11 +609,13 @@ my-mcp-server/
586
609
  ● ruff
587
610
  ● pytest
588
611
  ○ github-actions
612
+ ○ pre-commit
613
+ ○ mypy
589
614
  ```
590
615
 
591
616
  MCP Server uses a fixed stack — the official `mcp` Python SDK's `FastMCP` — so there's no framework or provider prompt, the same as RAG System.
592
617
 
593
- **Available extras:** `ruff` `pytest` `github-actions`
618
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
594
619
 
595
620
  **Run it:**
596
621
 
@@ -641,6 +666,7 @@ Dependencies (comma separated, optional): fastapi, uvicorn
641
666
  ● Pytest
642
667
  ○ Pre-commit
643
668
  ○ Dockerfile
669
+ ○ Mypy
644
670
 
645
671
  Additional ignore patterns (optional, comma separated): data/, *.csv
646
672
 
@@ -654,7 +680,7 @@ Proceed? [Y/n]: Y
654
680
 
655
681
  **The Dependencies prompt** (shown only when uv is enabled) installs packages immediately via `uv add`.
656
682
 
657
- **The Optional Setup menu** installs dev tools via `uv add --dev` and generates their config files: `ruff.toml`, `tests/__init__.py`, `.pre-commit-config.yaml`, and/or `Dockerfile`.
683
+ **The Optional Setup menu** installs dev tools via `uv add --dev` and generates their config files: `ruff.toml`, `tests/__init__.py`, `.pre-commit-config.yaml`, `Dockerfile`, and/or `[tool.mypy]` in `pyproject.toml`.
658
684
 
659
685
  ### Non-Interactive Mode
660
686
 
@@ -663,7 +689,7 @@ Skip all prompts by passing flags directly or pointing to a JSON config file.
663
689
  **Using flags:**
664
690
 
665
691
  ```bash
666
- spawn create --name my-api --template backend-api --framework fastapi --extras ruff,pytest --git
692
+ spawn create --name my-api --template backend-api --framework fastapi --extras ruff,pytest --license mit --git
667
693
  ```
668
694
 
669
695
  **Using a config file:**
@@ -674,6 +700,7 @@ spawn create --name my-api --template backend-api --framework fastapi --extras r
674
700
  "template": "backend-api",
675
701
  "framework": "fastapi",
676
702
  "extras": ["ruff", "pytest"],
703
+ "license": "mit",
677
704
  "git": true,
678
705
  "uv": true
679
706
  }
@@ -683,7 +710,7 @@ spawn create --name my-api --template backend-api --framework fastapi --extras r
683
710
  spawn create --config spawn.json
684
711
  ```
685
712
 
686
- `--config` takes precedence over individual flags. Add `--dry-run` to either form to validate the config and print it without creating any files.
713
+ `--config` takes precedence over individual flags (an explicit `--no-git`/`--no-uv` is ignored with a warning). Add `--dry-run` to either form to validate the config and print it without creating any files.
687
714
 
688
715
  > Custom Structure is interactive-only in this version.
689
716
 
@@ -741,11 +768,30 @@ spawn doctor ./path/to/project
741
768
 
742
769
  Checks span six categories — Documentation, Version Control, Configuration, Testing, Automation, and Code Quality (Ruff, type checking, pre-commit) — all filesystem-based, nothing is executed or sent over the network.
743
770
 
771
+ #### Automatic Remediation with `--fix`
772
+
773
+ `spawn doctor --fix` creates missing files and config automatically. It **never overwrites** pre-existing files and **never installs packages** directly (instead printing `uv add` commands for optional tools).
774
+
775
+ ```bash
776
+ # Automatically create missing files and config
777
+ spawn doctor --fix
778
+ spawn doctor ./path/to/project --fix
779
+
780
+ # Preview what would be created without touching disk
781
+ spawn doctor --fix --dry-run
782
+
783
+ # Run non-interactively without the confirmation prompt
784
+ spawn doctor --fix --yes
785
+
786
+ # Also add an MIT license if missing
787
+ spawn doctor --fix --license mit
788
+ ```
789
+
744
790
  ### `spawn version`
745
791
 
746
792
  ```bash
747
793
  spawn version
748
- # → Spawn v1.0.7
794
+ # → Spawn v1.0.9
749
795
  ```
750
796
 
751
797
  ### Publish to GitHub
@@ -779,6 +825,8 @@ All tests should pass. If they don't, please [open an issue](https://github.com/
779
825
 
780
826
  | Version | Highlight |
781
827
  |---|---|
828
+ | **v1.0.9** | Core hardening: documented exit-code contract (generation, toolchain and publish failures exit non-zero), `--no-uv` honored for templates (file-only extras still written), path-traversal protection for custom structures, `read_project_metadata` extension boundary |
829
+ | **v1.0.8** | `spawn doctor --fix` (`--dry-run`, `--yes`, `--license`), `--license` flag and prompt on `create`, `CHANGELOG.md` generated for every project, `pre-commit` and `mypy` extras across all templates, Custom Structure Mypy option |
782
830
  | **v1.0.7** | Fixed UTF-8 console crash on Windows when stdout is redirected/piped, added Windows reserved device name validation (`CON`, `PRN`, `AUX`, `NUL`, `COM1`–`9`, `LPT1`–`9`), clarified Python 3.12 requirement |
783
831
  | **v1.0.6** | Removed duplicate banner from `spawn create`; `spawn` alone now shows the banner and command overview |
784
832
  | **v1.0.5** | Published to PyPI as `spawnio`; arrow-key selection menus, no-args banner, consistent Ctrl+C handling |
@@ -77,6 +77,7 @@ It's repetitive. It's inconsistent. And you haven't written a single line of *re
77
77
  | **Arrow-key menus** | Every prompt in `spawn create` is arrow-key/spacebar driven, not typed numbers |
78
78
  | **GitHub publishing** | Connects your project to an existing GitHub repo and pushes the initial commit |
79
79
  | **spawn doctor** | Scores your project's health out of 100, with per-category breakdowns and a prioritized next step |
80
+ | **spawn doctor --fix** | Fixes missing files and config automatically — never overwrites, never installs packages |
80
81
 
81
82
  ---
82
83
 
@@ -132,7 +133,7 @@ Running `spawn` with no arguments shows the banner, the installed version, and t
132
133
 
133
134
  ```
134
135
  SPAWN — scaffold your next project
135
- v1.0.6
136
+ v1.0.9
136
137
 
137
138
  Commands
138
139
  create Scaffold a new project
@@ -179,7 +180,15 @@ Use the arrow keys to move, Enter to select — the same pattern every prompt in
179
180
 
180
181
  **Step 3 — Additional prompts** *(template-dependent — framework, provider, project type, and/or extras, depending on what you picked. See [Project Templates](#project-templates) below for each one's exact flow.)*
181
182
 
182
- **Step 4 — Git**
183
+ **Step 4 — License**
184
+
185
+ ```
186
+ ? Choose a license (Use arrow keys)
187
+ » MIT
188
+ None
189
+ ```
190
+
191
+ **Step 5 — Git**
183
192
 
184
193
  ```
185
194
  Initialize Git? [Y/n]: Y
@@ -242,9 +251,11 @@ my-api/
242
251
  ● pytest
243
252
  ○ docker
244
253
  ○ github-actions
254
+ ○ pre-commit
255
+ ○ mypy
245
256
  ```
246
257
 
247
- **Available extras:** `ruff` `pytest` `docker` `github-actions`
258
+ **Available extras:** `ruff` `pytest` `docker` `github-actions` `pre-commit` `mypy`
248
259
 
249
260
  **Run it:**
250
261
 
@@ -295,9 +306,11 @@ my-cli/
295
306
  ● ruff
296
307
  ● pytest
297
308
  ○ github-actions
309
+ ○ pre-commit
310
+ ○ mypy
298
311
  ```
299
312
 
300
- **Available extras:** `ruff` `pytest` `github-actions`
313
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
301
314
 
302
315
  **Run it:**
303
316
 
@@ -334,9 +347,11 @@ my-automation/
334
347
  ● ruff
335
348
  ● pytest
336
349
  ○ github-actions
350
+ ○ pre-commit
351
+ ○ mypy
337
352
  ```
338
353
 
339
- **Available extras:** `ruff` `pytest` `github-actions`
354
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
340
355
 
341
356
  **Run it:**
342
357
 
@@ -386,9 +401,11 @@ my-chatbot/
386
401
  ● pytest
387
402
  ○ rich
388
403
  ○ github-actions
404
+ ○ pre-commit
405
+ ○ mypy
389
406
  ```
390
407
 
391
- **Available extras:** `ruff` `pytest` `rich` `github-actions`
408
+ **Available extras:** `ruff` `pytest` `rich` `github-actions` `pre-commit` `mypy`
392
409
 
393
410
  **Run it:**
394
411
 
@@ -436,11 +453,13 @@ my-agent/
436
453
  ● ruff
437
454
  ● pytest
438
455
  ○ github-actions
456
+ ○ pre-commit
457
+ ○ mypy
439
458
  ```
440
459
 
441
460
  > If you pick `openai-agents`, only `openai` and `openrouter` appear as provider choices — the list is filtered per framework.
442
461
 
443
- **Available extras:** `ruff` `pytest` `github-actions`
462
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
444
463
 
445
464
  **Run it:**
446
465
 
@@ -481,11 +500,13 @@ my-rag/
481
500
  ● ruff
482
501
  ● pytest
483
502
  ○ github-actions
503
+ ○ pre-commit
504
+ ○ mypy
484
505
  ```
485
506
 
486
507
  RAG System uses a fixed stack — **LlamaIndex + ChromaDB + OpenAI** — so there's no framework or provider prompt, unlike Chatbot and Agent. On first run, it automatically ingests documents from `data/` into a local ChromaDB index, then lets you ask questions against them. Requires an `OPENAI_API_KEY` (used for both the LLM and embeddings).
487
508
 
488
- **Available extras:** `ruff` `pytest` `github-actions`
509
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
489
510
 
490
511
  **Run it:**
491
512
 
@@ -529,9 +550,11 @@ my-data-project/
529
550
  ● ruff
530
551
  ● pytest
531
552
  ○ github-actions
553
+ ○ pre-commit
554
+ ○ mypy
532
555
  ```
533
556
 
534
- **Available extras:** `ruff` `pytest` `github-actions`
557
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
535
558
 
536
559
  **Run it:**
537
560
 
@@ -575,11 +598,13 @@ my-mcp-server/
575
598
  ● ruff
576
599
  ● pytest
577
600
  ○ github-actions
601
+ ○ pre-commit
602
+ ○ mypy
578
603
  ```
579
604
 
580
605
  MCP Server uses a fixed stack — the official `mcp` Python SDK's `FastMCP` — so there's no framework or provider prompt, the same as RAG System.
581
606
 
582
- **Available extras:** `ruff` `pytest` `github-actions`
607
+ **Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
583
608
 
584
609
  **Run it:**
585
610
 
@@ -630,6 +655,7 @@ Dependencies (comma separated, optional): fastapi, uvicorn
630
655
  ● Pytest
631
656
  ○ Pre-commit
632
657
  ○ Dockerfile
658
+ ○ Mypy
633
659
 
634
660
  Additional ignore patterns (optional, comma separated): data/, *.csv
635
661
 
@@ -643,7 +669,7 @@ Proceed? [Y/n]: Y
643
669
 
644
670
  **The Dependencies prompt** (shown only when uv is enabled) installs packages immediately via `uv add`.
645
671
 
646
- **The Optional Setup menu** installs dev tools via `uv add --dev` and generates their config files: `ruff.toml`, `tests/__init__.py`, `.pre-commit-config.yaml`, and/or `Dockerfile`.
672
+ **The Optional Setup menu** installs dev tools via `uv add --dev` and generates their config files: `ruff.toml`, `tests/__init__.py`, `.pre-commit-config.yaml`, `Dockerfile`, and/or `[tool.mypy]` in `pyproject.toml`.
647
673
 
648
674
  ### Non-Interactive Mode
649
675
 
@@ -652,7 +678,7 @@ Skip all prompts by passing flags directly or pointing to a JSON config file.
652
678
  **Using flags:**
653
679
 
654
680
  ```bash
655
- spawn create --name my-api --template backend-api --framework fastapi --extras ruff,pytest --git
681
+ spawn create --name my-api --template backend-api --framework fastapi --extras ruff,pytest --license mit --git
656
682
  ```
657
683
 
658
684
  **Using a config file:**
@@ -663,6 +689,7 @@ spawn create --name my-api --template backend-api --framework fastapi --extras r
663
689
  "template": "backend-api",
664
690
  "framework": "fastapi",
665
691
  "extras": ["ruff", "pytest"],
692
+ "license": "mit",
666
693
  "git": true,
667
694
  "uv": true
668
695
  }
@@ -672,7 +699,7 @@ spawn create --name my-api --template backend-api --framework fastapi --extras r
672
699
  spawn create --config spawn.json
673
700
  ```
674
701
 
675
- `--config` takes precedence over individual flags. Add `--dry-run` to either form to validate the config and print it without creating any files.
702
+ `--config` takes precedence over individual flags (an explicit `--no-git`/`--no-uv` is ignored with a warning). Add `--dry-run` to either form to validate the config and print it without creating any files.
676
703
 
677
704
  > Custom Structure is interactive-only in this version.
678
705
 
@@ -730,11 +757,30 @@ spawn doctor ./path/to/project
730
757
 
731
758
  Checks span six categories — Documentation, Version Control, Configuration, Testing, Automation, and Code Quality (Ruff, type checking, pre-commit) — all filesystem-based, nothing is executed or sent over the network.
732
759
 
760
+ #### Automatic Remediation with `--fix`
761
+
762
+ `spawn doctor --fix` creates missing files and config automatically. It **never overwrites** pre-existing files and **never installs packages** directly (instead printing `uv add` commands for optional tools).
763
+
764
+ ```bash
765
+ # Automatically create missing files and config
766
+ spawn doctor --fix
767
+ spawn doctor ./path/to/project --fix
768
+
769
+ # Preview what would be created without touching disk
770
+ spawn doctor --fix --dry-run
771
+
772
+ # Run non-interactively without the confirmation prompt
773
+ spawn doctor --fix --yes
774
+
775
+ # Also add an MIT license if missing
776
+ spawn doctor --fix --license mit
777
+ ```
778
+
733
779
  ### `spawn version`
734
780
 
735
781
  ```bash
736
782
  spawn version
737
- # → Spawn v1.0.7
783
+ # → Spawn v1.0.9
738
784
  ```
739
785
 
740
786
  ### Publish to GitHub
@@ -768,6 +814,8 @@ All tests should pass. If they don't, please [open an issue](https://github.com/
768
814
 
769
815
  | Version | Highlight |
770
816
  |---|---|
817
+ | **v1.0.9** | Core hardening: documented exit-code contract (generation, toolchain and publish failures exit non-zero), `--no-uv` honored for templates (file-only extras still written), path-traversal protection for custom structures, `read_project_metadata` extension boundary |
818
+ | **v1.0.8** | `spawn doctor --fix` (`--dry-run`, `--yes`, `--license`), `--license` flag and prompt on `create`, `CHANGELOG.md` generated for every project, `pre-commit` and `mypy` extras across all templates, Custom Structure Mypy option |
771
819
  | **v1.0.7** | Fixed UTF-8 console crash on Windows when stdout is redirected/piped, added Windows reserved device name validation (`CON`, `PRN`, `AUX`, `NUL`, `COM1`–`9`, `LPT1`–`9`), clarified Python 3.12 requirement |
772
820
  | **v1.0.6** | Removed duplicate banner from `spawn create`; `spawn` alone now shows the banner and command overview |
773
821
  | **v1.0.5** | Published to PyPI as `spawnio`; arrow-key selection menus, no-args banner, consistent Ctrl+C handling |