refactor(template): overall improvements#8
Conversation
Reviewer's GuideRefactors the Copier template into a more modular, option-driven scaffold with feature toggles for CLI/web/GUI/TUI, configuration and tooling choices, and aligns the generated project’s config, docs, CI/CD, and tests with these options while adding new TUI functionality and dev tooling integrations. Sequence diagram for CLI commands dispatching to GUI,TUI,WebsequenceDiagram
actor User
participant TyperApp as Typer_app
participant CLI as cli_module
participant GUI as gui_main
participant TUI as tui_main
participant Web as web_app
participant Uvicorn as uvicorn_server
User->>TyperApp: run "{{github_repo_name}} gui"
TyperApp->>CLI: invoke gui()
CLI->>GUI: main()
GUI-->>User: show_window
User->>TyperApp: run "{{github_repo_name}} interactive"
TyperApp->>CLI: invoke interactive()
CLI->>TUI: main(show_tui=True)
TUI->>TUI: build_info_message()
TUI->>TUI: _display_tui(message)
TUI-->>User: interactive_terminal_ui
User->>TyperApp: run "{{github_repo_name}} web"
TyperApp->>CLI: invoke web()
CLI->>Web: import app
CLI->>Uvicorn: run(app, host, port)
Uvicorn-->>User: serve_http_api
Class diagram for new Settings and TUI componentsclassDiagram
class Settings {
<<pydantic_settings>>
+SettingsConfigDict model_config
+bool debug
+str log_level
+Path config_dir
}
class BaseSettings {
}
Settings --|> BaseSettings
class TuiDisplayError {
<<exception>>
+TuiDisplayError(message)
}
class TuiModule {
<<module>>
+build_info_message() str
+_display_tui(message) None
+main(show_tui) int
}
class InfoApp {
<<TextualApp>>
+str CSS
+list BINDINGS
+compose() ComposeResult
+on_mount() None
+action_quit() None
}
class App {
}
InfoApp --|> App
TuiModule ..> TuiDisplayError : raises
TuiModule ..> InfoApp : instantiates
TuiModule ..> Settings : uses indirect_config
class LoggingSetup {
<<module>>
+setup_logger() Logger
}
class Logger {
}
LoggingSetup ..> Logger : returns
TuiModule ..> Logger : logs
class Metadata {
<<module>>
+str PROJECT_NAME
}
TuiModule ..> Metadata : reads_PROJECT_NAME
Settings ..> Metadata : reads_PROJECT_NAME
class Dirs {
<<module>>
+Path ROOT_FOLDER_PATH
+Path LOG_FILE_PATH
}
LoggingSetup ..> Dirs : uses_paths
Flow diagram for template options driving generated componentsflowchart TD
subgraph CopierTemplate
CY[copier_yml]
Answers[User_answers]
end
CY --> Answers
subgraph FeatureToggles
include_cli
include_web
include_gui
include_tui
use_pydantic_settings
include_changelog
include_contributing
include_code_of_conduct
include_citation
include_pants
include_codecov
include_mise
include_trunk
include_poe
include_commitizen
use_precommit
release_automation
dependency_management
end
Answers --> FeatureToggles
subgraph GeneratedCode
subgraph AppLayers
CLIFile[cli_py_jinja]
WebFile[web_py_jinja]
GUIFile[gui_py_jinja]
TUIFile[tui_py_jinja]
MainFile[__main__py_jinja]
MetadataFile[__metadata__py_jinja]
DirsFile[dirs_py_jinja]
ConfigFile[config_py_jinja]
end
subgraph Tests
TestCLI[test_cli_py_jinja]
TestWeb[test_web_py_jinja]
TestGUI[test_gui_py_jinja]
TestTUI[test_tui_py_jinja]
end
subgraph Docs
Mkdocs[mkdocs_yml_jinja]
DocsIndex[docs_index_md_jinja]
DocsInstall[docs_installation_md_jinja]
DocsUsage[docs_usage_md_jinja]
DocsModules[docs_modules_md_jinja]
ProjectReadme[README_md_jinja]
Changelog[CHANGELOG_md_jinja]
Contributing[CONTRIBUTING_md_jinja]
Citation[CITATION_cff_jinja]
end
subgraph ToolingConfigs
Pyproject[pyproject_toml_jinja]
PreCommit[pre_commit_config_yaml_jinja]
CDWorkflow[cd_yml_jinja]
OpencodeWorkflow[opencode_yml]
ReleaseDrafter[release_drafter_yml_jinja]
ReleasePlease[release_please_config_json_jinja]
Dependabot[dependabot_yml_jinja]
Renovate[renovate_json]
Mise[mise_toml_jinja]
Pants[pants_toml]
Trunk[trunk_yaml]
Codecov[codecov_yml]
PoeConfig[tool_poe_in_pyproject]
CommitizenConfig[tool_commitizen_in_pyproject]
end
end
include_cli --> CLIFile
include_cli --> TestCLI
include_cli --> MainFile
include_cli --> Pyproject
include_web --> WebFile
include_web --> TestWeb
include_web --> Pyproject
include_gui --> GUIFile
include_gui --> TestGUI
include_tui --> TUIFile
include_tui --> TestTUI
include_tui --> CLIFile
use_pydantic_settings --> ConfigFile
use_pydantic_settings --> Pyproject
include_changelog --> Changelog
include_changelog --> ProjectReadme
include_changelog --> CommitizenConfig
include_contributing --> Contributing
include_code_of_conduct --> DocsIndex
include_citation --> Citation
include_mise --> Mise
include_trunk --> Trunk
include_pants --> Pants
include_codecov --> Codecov
include_poe --> PoeConfig
include_commitizen --> CommitizenConfig
use_precommit --> PreCommit
release_automation --> ReleaseDrafter
release_automation --> ReleasePlease
dependency_management --> Dependabot
dependency_management --> Renovate
MetadataFile --> DirsFile
MetadataFile --> CLIFile
MetadataFile --> WebFile
MetadataFile --> GUIFile
MetadataFile --> TUIFile
DirsFile --> Pyproject
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey there - I've reviewed your changes and found some issues that need to be addressed.
- In
template/docs/installation.md.jinja, the extras list uses{% if config %}but there is noconfigtemplate variable (onlyuse_pydantic_settings/ theconfigextra name), so this condition will never be true and should be updated to use the appropriate flag. - The example answers file
.example-input.ymldefinesuse_pre_commit, butcopier.ymldeclaresuse_precommit; this mismatch means the example value will be ignored and should be aligned with the actual question name. - The local
pytestpre-commit hook intemplate/.pre-commit-config.yaml.jinjahardcodes./venv/bin/pytest, while the rest of the template usesuvand a.venvvirtualenv; consider updating this path or usinguvso it works out of the box with generated projects.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `template/docs/installation.md.jinja`, the extras list uses `{% if config %}` but there is no `config` template variable (only `use_pydantic_settings` / the `config` extra name), so this condition will never be true and should be updated to use the appropriate flag.
- The example answers file `.example-input.yml` defines `use_pre_commit`, but `copier.yml` declares `use_precommit`; this mismatch means the example value will be ignored and should be aligned with the actual question name.
- The local `pytest` pre-commit hook in `template/.pre-commit-config.yaml.jinja` hardcodes `./venv/bin/pytest`, while the rest of the template uses `uv` and a `.venv` virtualenv; consider updating this path or using `uv` so it works out of the box with generated projects.
## Individual Comments
### Comment 1
<location> `template/pyproject.toml.jinja:20-24` </location>
<code_context>
+ "tox", "pytest", "ruff", "mypy", "pyright",
+ "type-hints", "typed", "modern-python",
+ "ci-cd", "github-actions", "automation", "mkdocs",
+ "pre-commit", "linting", "testing", "coverage", "release-automation"
+ {% if include_cli %}"typer",{% endif %}
+ {% if include_web %}"fastapi", "docker",{% endif %}
+ {% if include_tui %}"textual", "tui",{% endif %}
+ {% if use_pydantic_settings %}"pydantic",{% endif %}
+]
+# TODO @{{github_user}}: Fill in the missing classifiers...
</code_context>
<issue_to_address>
**issue (bug_risk):** Conditional keyword entries can render invalid TOML due to missing commas between elements.
The last fixed entry (`"release-automation"`) has no trailing comma, and each conditional entry starts on a new line without a leading comma. When any conditional is enabled, this yields adjacent string literals without a separator. Please either add a trailing comma after the last fixed element or start each conditional entry with a comma (e.g. `{% if include_cli %}, "typer"{% endif %}`) so all flag combinations produce valid TOML.
</issue_to_address>
### Comment 2
<location> `template/pyproject.toml.jinja:102` </location>
<code_context>
[dependency-groups]
dev = [
- "{{github_repo_name}}[cli,web]",
+ "{{github_repo_name}}[all]",
"tox==4.31.0",
"tox-uv==1.29.0",
</code_context>
<issue_to_address>
**issue (bug_risk):** The `dev` dependency group always references the `all` extra even when no optional extras are defined.
`[dependency-groups].dev` now always depends on `"{{github_repo_name}}[all]"`, but `[project.optional-dependencies]` (and thus the `all` extra) is only generated when at least one of `include_cli`, `include_web`, `include_tui`, or `use_pydantic_settings` is true. In configs like `.example-input.yml` where all are false, `dev` installs will fail because `all` is undefined. Please either conditionally include `"{{github_repo_name}}[all]"` under the same condition as `[project.optional-dependencies]`, or use `"{{github_repo_name}}"` when no extras are enabled.
</issue_to_address>
### Comment 3
<location> `template/docs/installation.md.jinja:8` </location>
<code_context>
+> - {% if include_cli %}cli: Installs typer and adds {{github_repo_name}} as a command.{% endif %}
+> - {% if include_tui %}tui: Installs textual and adds {{github_repo_name}}-tui as a command.{% endif %}
+> - {% if include_web %}web: Installs FastAPI and adds {{github_repo_name}}-web as a command.{% endif %}
+> - {% if config %}config: Installs pydantic-settings.{% endif %}
+> - all: Installs all extras.
+{% endif %}
</code_context>
<issue_to_address>
**issue (bug_risk):** The conditional for the `config` extra references an undefined template variable.
Other conditions use the `use_pydantic_settings` flag, but this line checks `config`, which isn’t defined in `copier.yml`. That means this extra may render incorrectly or error at runtime. Please switch this to use `use_pydantic_settings` and align the description with that flag.
</issue_to_address>
### Comment 4
<location> `template/docs/index.md.jinja:13-15` </location>
<code_context>
+
+## Indices and tables
+
+- [Index](genindex)
+- [Module Index](modindex)
+- [Search](search)
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Index/search links look like Sphinx artifacts and won’t resolve under MkDocs.
As-is, these will render as broken links. Please either remove them or replace them with links to real MkDocs pages (e.g., existing Markdown docs or MkDocs’ built-in search UI).
</issue_to_address>
### Comment 5
<location> `CLAUDE.md:56` </location>
<code_context>
+uv run --locked <repo-name> info
+
+# Run the FastAPI web app
+uv run --locked fastapi dev <repo-name>.app:app
+
+# Run pre-commit hooks
</code_context>
<issue_to_address>
**issue (bug_risk):** Update FastAPI run command to match the new `web.py` module path.
Other references (README, `web.py` rename) expose the FastAPI app as `<repo-name>.web:app`. This command should use the same path: `uv run --locked fastapi dev <repo-name>.web:app` to avoid a broken or confusing entrypoint.
</issue_to_address>
### Comment 6
<location> `CLAUDE.md:94` </location>
<code_context>
+Projects created from this template have:
+
+- **CLI Application**: Typer-based CLI in `cli.py.jinja` with `version` and `info` commands
+- **Web Application**: FastAPI stub in `app.py.jinja` with `/version` and `/info` endpoints
+- **Core Modules**:
+ - `__metadata__.py.jinja`: Project name constant
</code_context>
<issue_to_address>
**issue:** Align referenced FastAPI template filename with the new `web.py.jinja` name.
This line still mentions `app.py.jinja`, but the FastAPI template is now `web.py.jinja` (via `{% if include_web %}web.py{% endif %}.jinja`). Please update the filename here to keep the documentation accurate.
</issue_to_address>
### Comment 7
<location> `AGENTS.md:14` </location>
<code_context>
+# Pre-commit: uv run --locked tox run -e pre-commit
+# Build: uv build
+# Run CLI: uv run --locked <repo-name> version
+# Run FastAPI: uv run --locked fastapi dev <repo-name>.app:app
+# Serve docs: uv run --only-group docs mkdocs serve
+# Trunk check: trunk check (if configured)
</code_context>
<issue_to_address>
**issue (bug_risk):** FastAPI run command should use the updated `.web:app` module path.
The template and README now use `<repo-name>.web:app` as the FastAPI entrypoint, but this still references `<repo-name>.app:app`. Please update this line to `uv run --locked fastapi dev <repo-name>.web:app` so the documented command works correctly and stays consistent.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Review by RecurseML
🔍 Review performed on 73a9cfc..3c0a027
✨ No bugs found, your code is sparkling clean
✅ Files analyzed, no issues (50)
• .example-input.yml
• .github/workflows/opencode.yml
• AGENTS.md
• CLAUDE.md
• README.md
• copier.yml
• example/.copier-answers.yml
• example/.devcontainer/Dockerfile
• example/.devcontainer/devcontainer.json
• example/.devcontainer/docker-compose.yml
• example/.dockerignore
• example/.editorconfig
• example/.github/FUNDING.yml
• example/.github/ISSUE_TEMPLATE/bug-report.md
• example/.github/ISSUE_TEMPLATE/feature-request.md
• example/.github/PULL_REQUEST/pull_request_template.md
• example/.github/actionlint.yaml
• example/.github/labeler.yml
• example/.github/linters/.codeql.yml
• example/.github/linters/.codespellrc
• example/.github/linters/.cspell.yml
• example/.github/release-drafter.yml
• example/.github/workflows/cd.yml
• example/.github/workflows/codeql.yml
• example/.github/workflows/first-interaction.yml
• example/.github/workflows/gh-pages.yml
• example/.github/workflows/label.yml
• example/.github/workflows/manual.yml
• example/.github/workflows/stale.yml
• example/.gitignore
• example/.markdownlint-cli2.jsonc
• example/.markdownlint.json
• example/.pre-commit-config.yaml
• example/.vscode/extensions.json
• example/.vscode/launch.json
• example/.yamlfmt.yml
• example/.yamllint.yaml
• example/.zed/debug.json
• example/CHANGELOG.md
• example/CODE_OF_CONDUCT.md
• example/CONTRIBUTING.md
• example/Dockerfile
• example/LICENSE
• example/README.md
• example/docs/index.md
• example/mkdocs.yml
• example/pyproject.toml
• example/src/example/__init__.py
• example/src/example/__main__.py
• example/src/example/app.py
⏭️ Files skipped (92)
| Locations |
|---|
.python-version |
example/.github/linters/.markdownlint.yml |
example/.github/linters/.shellcheckrc |
example/.github/linters/.yamllint.yml |
example/.github/linters/actionlint.yml |
example/src/example/cli.py |
example/src/example/gui.py |
example/src/example/logging_setup.py |
example/src/example/py.typed |
example/tests/__init__.py |
example/tests/test_cli.py |
example/tests/test_gui.py |
example/tests/test_web.py |
example/uv.lock |
template/.codecov.yml |
template/.devcontainer/docker-compose.dbeaver.yml |
template/.devcontainer/docker-compose.vpn.yml |
template/.editorconfig |
template/.github/ISSUE_TEMPLATE/config.yml.jinja |
template/.github/actionlint.yaml |
template/.github/workflows/cd.yml.jinja |
template/.github/workflows/check-pr-title.yml |
template/.github/workflows/check-pr-title.yml.jinja |
template/.github/workflows/ci.yml |
template/.github/workflows/ci.yml.jinja |
template/.github/workflows/opencode.yml |
template/.github/workflows/release-drafter.yml.jinja |
template/.github/workflows/release-please.yml |
template/.github/workflows/{% if release_automation == "release-drafter" %}release-drafter.yml{% endif %}.jinja |
template/.github/workflows/{% if release_automation == "release-please" %}release-please.yml{% endif %}.jinja |
template/.github/{% if dependency_management == 'dependabot' %}dependabot.yml{% endif %}.jinja |
template/.github/{% if release_automation == "release-drafter" %}release-drafter.yml{% endif %}.jinja |
template/.markdownlint-cli2.jsonc |
template/.pre-commit-config.yaml.jinja |
template/.release-it.json |
template/.trunk/.gitignore |
template/.trunk/configs/.hadolint.yaml |
template/.trunk/configs/.markdownlint.yaml |
template/.trunk/trunk.yaml |
template/.vscode/launch.json.jinja |
template/.zed/debug.json.jinja |
template/README.md.jinja |
template/docs/index.md |
template/docs/index.md.jinja |
template/docs/installation.md.jinja |
template/docs/modules.md.jinja |
template/docs/usage.md.jinja |
template/examples/advanced/README.md |
template/examples/advanced/main.py |
template/examples/simple/README.md |
template/examples/simple/main.py |
template/mkdocs.yml.jinja |
template/pants.toml |
template/pyproject.toml.jinja |
template/release-please-config.json |
template/renovate.json |
template/src/{{github_repo_name}}/__init__.py |
template/src/{{github_repo_name}}/__init__.py.jinja |
template/src/{{github_repo_name}}/__main__.py.jinja |
template/src/{{github_repo_name}}/__metadata__.py.jinja |
template/src/{{github_repo_name}}/config.py.jinja |
template/src/{{github_repo_name}}/core.py |
template/src/{{github_repo_name}}/dirs.py.jinja |
template/src/{{github_repo_name}}/logging_setup.py.jinja |
template/src/{{github_repo_name}}/utils.py |
template/src/{{github_repo_name}}/{% if include_cli %}cli.py{% endif %}.jinja |
template/src/{{github_repo_name}}/{% if include_gui %}gui.py{% endif %}.jinja |
template/src/{{github_repo_name}}/{% if include_tui %}tui.py{% endif %}.jinja |
template/src/{{github_repo_name}}/{% if include_web %}web.py{% endif %}.jinja |
template/tests/__init__.py |
template/tests/__init__.py.jinja |
template/tests/{% if include_cli %}test_cli.py{% endif %}.jinja |
template/tests/{% if include_gui %}test_gui.py{% endif %}.jinja |
template/tests/{% if include_tui %}test_tui.py{% endif %}.jinja |
template/tests/{% if include_web %}test_web.py{% endif %}.jinja |
template/{% if dependency_management == 'renovate' %}renovate.json{% endif %}.jinja |
template/{% if include_changelog %}CHANGELOG.md{% endif %}.jinja |
template/{% if include_citation %}CITATION.cff{% endif %}.jinja |
template/{% if include_code_of_conduct %}CODE_OF_CONDUCT.md{% endif %}.jinja |
template/{% if include_codecov %}.codecov.yml{% endif %}.jinja |
template/{% if include_contributing %}CONTRIBUTING.md{% endif %}.jinja |
template/{% if include_mise %}mise.toml{% endif %}.jinja |
template/{% if include_pants %}pants.toml{% endif %}.jinja |
template/{% if include_trunk %}.trunk{% endif %}/.gitignore |
template/{% if include_trunk %}.trunk{% endif %}/configs/.hadolint.yaml |
template/{% if include_trunk %}.trunk{% endif %}/configs/.markdownlint.yaml |
template/{% if include_trunk %}.trunk{% endif %}/trunk.yaml |
template/{% if include_web %}Dockerfile{% endif %}.jinja |
template/{% if release_automation == "release-it" %}.release-it.json{% endif %}.jinja |
template/{% if release_automation == "release-please" %}release-please-config.json{% endif %}.jinja |
template/{{_copier_conf.answers_file}}.jinja |
tests/__init__.py |
There was a problem hiding this comment.
Pull request overview
This PR transforms a basic Python project template into a highly configurable Copier template by introducing conditional includes for optional components. The refactor adds extensive configurability through new template variables in copier.yml, enabling users to selectively include CLI (Typer), web (FastAPI), TUI (Textual), GUI (Tkinter) interfaces, along with configurable dependency management, release automation, and optional development tools. The changes separate concerns by creating a new __metadata__.py module for project constants, restructure configuration handling to support pydantic-settings, enhance documentation structure, and remove the example project in favor of expanded configuration options.
Key Changes
- Added 20+ new configuration options in
copier.ymlfor conditional inclusion of components (CLI, web, TUI, GUI, C extensions, pydantic-settings, release automation, dependency management, etc.) - Introduced
__metadata__.pymodule to centralize project metadata and updated all imports fromconfig.pyto use the new module - Restructured template files to use conditional Jinja2 blocks based on new configuration flags
Reviewed changes
Copilot reviewed 142 out of 163 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
copier.yml |
Added 20+ new configuration variables for conditional component inclusion |
README.md |
Updated documentation to reflect new configurability options |
.example-input.yml |
Expanded with all new configuration options set to defaults |
AGENTS.md |
New AI agent guidance file for development commands and code style |
CLAUDE.md |
Comprehensive Claude AI assistant documentation |
template/pyproject.toml.jinja |
Heavily modified to support conditional dependencies and optional components |
template/src/{{github_repo_name}}/__metadata__.py.jinja |
New module for project metadata constants |
template/src/{{github_repo_name}}/config.py.jinja |
Restructured to use pydantic-settings when enabled |
template/src/{{github_repo_name}}/cli.py.jinja |
Updated imports and added conditional commands for TUI/GUI/web |
template/src/{{github_repo_name}}/logging_setup.py.jinja |
Updated imports to use new dirs.py module |
template/tests/test_*.py.jinja |
Updated test files to use pytest fixtures and new metadata module |
template/.pre-commit-config.yaml |
Enhanced with additional hooks including pyright, black, isort, codespell, commitizen |
template/.github/workflows/*.yml.jinja |
Restructured workflows for conditional release automation and dependency management |
Comments suppressed due to low confidence (13)
template/{{_copier_conf.answers_file}}.jinja:1
- The
---YAML document separator on line 2 appears after a comment line. While technically valid, this is unconventional. Typically, if a YAML document separator is used, it should be the first line of the file. Consider either removing the separator entirely (since it's not required for single-document YAML files) or placing it before the comment on line 1.
template/{% if include_citation %}CITATION.cff{% endif %}.jinja:1 - The name parsing logic assumes the author's full name has exactly two parts (first and last name). This will break for authors with middle names or single-word names. For authors with names like 'John Paul Smith',
split(' ')[0]will only capture 'John' andsplit(' ')[-1]will capture 'Smith', losing 'Paul'. Consider using a more robust parsing approach or providing separate fields for given and family names in the template variables.
template/{% if include_citation %}CITATION.cff{% endif %}.jinja:1 - Duplicate name parsing issue in the
preferred-citationsection. This has the same problem as lines 5-6 where names with middle names or single-word names will not be handled correctly.
template/src/{{github_repo_name}}/{% if include_tui %}tui.py{% endif %}.jinja:1 - The exception handling on line 103 catches a generic
Exceptionbut the error message on line 104 constructs a TuiDisplayError with the exception message. This loses the original exception type information which could be valuable for debugging. Consider preserving the exception chain or logging the original exception type.
template/pyproject.toml.jinja:1 - The trailing commas in the
alldependency list may result in a syntax error if all conditions evaluate to false, leaving a list with only commas. While unlikely given default values, consider restructuring to avoid potential issues or adding a comment explaining the assumption.
template/pyproject.toml.jinja:1 - Unlike other dependencies in this file, these three test dependencies lack version specifiers. For consistency and reproducibility, consider adding version constraints (e.g., 'pytest-sugar==x.y.z' or 'pytest-sugar>=x.y.z').
template/pyproject.toml.jinja:1 - The path patterns use
./prefix which is inconsistent with standard ruff configuration patterns. Ruff typically expects paths without the leading./. Consider removing the prefix for consistency:tests/*.pyandexamples/*.py.
template/.github/{% if dependency_management == 'dependabot' %}dependabot.yml{% endif %}.jinja:1 - The commit message prefix 'deps' differs from the conventional commit prefix 'chore(deps)' used in many projects and shown in the release-drafter configuration. Consider using 'chore' as the prefix for consistency across the project's tooling.
template/.github/workflows/cd.yml.jinja:1 - Missing closing brace in the Jinja raw block. The
{% raw %}block is not properly closed - it should end with{% endraw %}on line 45, but line 69 shows{% endraw %}which is supposed to close a different block. This will cause template rendering errors.
template/.github/workflows/build-wheels.yml:1 - The workflow uses
UV_PUBLISH_TOKENwith a secretPYPI_TOKEN, but the CD workflow uses trusted publishing without tokens. This inconsistency in publishing methods could be confusing. Consider documenting why different approaches are used or standardizing on one method. If this workflow is for C extensions (as the name suggests), document the publishing strategy difference.
template/.github/actionlint.yaml:1 - Ignoring shellcheck warnings globally across all workflow files may hide legitimate issues. Consider being more specific about which workflows need these exceptions, or better yet, fix the underlying shell script issues that trigger SC2006 (deprecated backticks), SC2086 (unquoted variables), and SC2129 (inefficient redirection).
template/.github/ISSUE_TEMPLATE/config.yml.jinja:1 - Lines 19-27 appear to be duplicates of the contact_links defined earlier in the file (lines 4-18). This creates redundant entries in the GitHub issue template configuration. Remove the duplicate entries to avoid confusion.
template/.editorconfig:1 - Setting
indent_size = unsetfor Makefiles is unusual. Makefiles traditionally use tabs with a specific tab width. Consider settingindent_size = 4orindent_size = 8(common tab widths) instead of unsetting it entirely.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
High-level PR Summary
This PR introduces major architectural improvements to a Python project template (Copier-based), adding extensive configurability through conditional includes. The template now supports optional components like CLI (
typer), web (fastapi), TUI (textual), and GUI (tkinter) interfaces, along with configurable dependency management (Renovate/Dependabot), release automation (release-please/release-it/release-drafter), and optional tools like Commitizen, Poe, Pants, Trunk, and mise. The refactor separates concerns by creating a new__metadata__.pymodule, restructures configuration handling to supportpydantic-settings, enhances documentation structure with new MkDocs pages, and adds comprehensive testing fixtures. The example project has been removed in favor of an expanded.example-input.ymlconfiguration file, and new agent-oriented documentation (AGENTS.md,CLAUDE.md) has been added for AI code assistants.⏱️ Estimated Review Time: 1-3 hours
💡 Review Order Suggestion
copier.ymlREADME.md.example-input.ymlAGENTS.mdCLAUDE.md.github/workflows/opencode.ymltemplate/pyproject.toml.jinjatemplate/src/{{github_repo_name}}/__metadata__.py.jinjatemplate/src/{{github_repo_name}}/config.py.jinjatemplate/src/{{github_repo_name}}/{% if include_cli %}cli.py{% endif %}.jinjatemplate/src/{{github_repo_name}}/{% if include_web %}web.py{% endif %}.jinjatemplate/src/{{github_repo_name}}/{% if include_tui %}tui.py{% endif %}.jinjatemplate/src/{{github_repo_name}}/{% if include_gui %}gui.py{% endif %}.jinjatemplate/docs/index.md.jinjatemplate/docs/installation.md.jinjatemplate/docs/usage.md.jinjatemplate/docs/modules.md.jinjatemplate/README.md.jinjatemplate/mkdocs.yml.jinjatemplate/.github/workflows/{% if release_automation == "release-drafter" %}release-drafter.yml{% endif %}.jinjatemplate/.github/workflows/{% if release_automation == "release-please" %}release-please.yml{% endif %}.jinjatemplate/.github/{% if dependency_management == 'dependabot' %}dependabot.yml{% endif %}.jinjatemplate/.github/{% if dependency_management == 'renovate' %}renovate.json{% endif %}.jinjatemplate/.pre-commit-config.yaml.jinjatemplate/tests/{% if include_cli %}test_cli.py{% endif %}.jinjatemplate/tests/{% if include_web %}test_web.py{% endif %}.jinjatemplate/tests/{% if include_tui %}test_tui.py{% endif %}.jinjatemplate/tests/{% if include_gui %}test_gui.py{% endif %}.jinjatemplate/.vscode/launch.json.jinjatemplate/.zed/debug.json.jinjatemplate/.editorconfigtemplate/.markdownlint-cli2.jsonctemplate/.devcontainer/docker-compose.dbeaver.ymltemplate/.devcontainer/docker-compose.vpn.ymltemplate/examples/simple/main.pytemplate/examples/simple/README.mdtemplate/examples/advanced/main.pytemplate/examples/advanced/README.mdtemplate/{% if include_mise %}mise.toml{% endif %}.jinjatemplate/{% if include_citation %}CITATION.cff{% endif %}.jinja