Skip to content

Commit d61f870

Browse files
Ralph Agentclaude
andcommitted
🐛 Fix project metadata and type errors
- Remove garbled characters from README and pyproject.toml descriptions - Add rich as direct dependency to fix DEP003 issues - Add type annotations to fix langfuse type checker errors Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent e2b021e commit d61f870

7 files changed

Lines changed: 504 additions & 5 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# Python-Template
1+
# python-template
22

33
<p align="center">
44
<img src="media/banner.png" alt="2" width="400">
55
</p>
66

77
<p align="center">
8-
<b>Opinionated Python project stack. 🔋 Batteries included. </b>
8+
<b>🐍 Opinionated uv Python template with batteries included. Cursorrules, LLMs, linting, dead code analysis, and a whole lot more.</b>
99
</p>
1010

1111
<p align="center">

prd.json

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
{
2+
"project": "Python-Template",
3+
"branchName": "ralph/onboarding-cli",
4+
"description": "Interactive onboarding CLI that replaces make init/setup with a guided typer-based flow covering project renaming, dependency setup, env var configuration, pre-commit hooks, and AI-powered media generation",
5+
"userStories": [
6+
{
7+
"id": "US-001",
8+
"title": "Create typer CLI scaffold with subcommands",
9+
"description": "As a developer, I need the CLI entry point and subcommand structure so that the full flow and individual steps are both accessible.",
10+
"acceptanceCriteria": [
11+
"New file onboard.py at project root",
12+
"typer and questionary added as project dependencies via uv add",
13+
"Uses typer as CLI framework with rich for output formatting",
14+
"Running 'uv run python onboard.py --help' shows all available subcommands: rename, deps, env, hooks, media",
15+
"Each subcommand has a placeholder implementation that prints 'Step X not yet implemented'",
16+
"Running 'uv run python onboard.py' with no args calls a main function that will later orchestrate all steps",
17+
"Typecheck passes"
18+
],
19+
"priority": 1,
20+
"passes": true,
21+
"notes": ""
22+
},
23+
{
24+
"id": "US-002",
25+
"title": "Implement project rename step",
26+
"description": "As a user setting up a new project from this template, I want to interactively name and describe my project so that all placeholder references are updated.",
27+
"acceptanceCriteria": [
28+
"The 'rename' subcommand prompts for project name with validation (kebab-case, no spaces)",
29+
"Prompts for project description (free text)",
30+
"Updates the name field in pyproject.toml from 'python-template' to the new name",
31+
"Updates the description field in pyproject.toml",
32+
"Updates the '# Python-Template' heading in README.md to the new name",
33+
"Updates the tagline/description line in README.md",
34+
"Shows a rich Panel summary of what was changed after completion",
35+
"Skips with informational message if project name in pyproject.toml is already not 'python-template'",
36+
"Runnable standalone via 'uv run python onboard.py rename'",
37+
"Typecheck passes"
38+
],
39+
"priority": 2,
40+
"passes": true,
41+
"notes": ""
42+
},
43+
{
44+
"id": "US-003",
45+
"title": "Implement dependency setup step",
46+
"description": "As a user, I want dependencies installed automatically so that my environment is ready without manual steps.",
47+
"acceptanceCriteria": [
48+
"The 'deps' subcommand checks if uv is installed via shutil.which('uv')",
49+
"If uv is not found, prints install instructions (link to docs.astral.sh/uv) and exits with error",
50+
"Creates .venv via 'uv venv' if .venv directory does not exist",
51+
"Runs 'uv sync' to install all dependencies",
52+
"Shows a rich spinner during uv sync execution",
53+
"Prints success message with green checkmark on completion, or red error on failure",
54+
"Runnable standalone via 'uv run python onboard.py deps'",
55+
"Typecheck passes"
56+
],
57+
"priority": 3,
58+
"passes": true,
59+
"notes": ""
60+
},
61+
{
62+
"id": "US-004",
63+
"title": "Implement environment variable configuration step",
64+
"description": "As a user, I want to interactively select which API keys and secrets I need, then fill them in, so that my .env file is configured correctly.",
65+
"acceptanceCriteria": [
66+
"The 'env' subcommand reads all keys from .env.example as the source of truth",
67+
"Parses .env.example comment lines (e.g. '# LLM API Keys') to derive service groups",
68+
"If .env already exists, loads it and identifies which keys have non-empty non-placeholder values",
69+
"Presents a questionary.checkbox list of all env var keys, organized by group headings from .env.example",
70+
"Keys that already have values in .env are pre-checked in the checkbox list",
71+
"For each ticked key that is empty or missing, prompts user to enter the value with questionary.password if the key name contains SECRET, KEY, TOKEN, or PASSWORD (case-insensitive), otherwise questionary.text",
72+
"For each ticked key that already has a value, asks 'Keep existing value? (Y/n)' and skips if yes",
73+
"Writes .env file preserving the group comment structure from .env.example",
74+
"Keys the user did not tick are written commented out (prefixed with #) in .env",
75+
"Prints a rich summary: N keys configured, M keys skipped",
76+
"Runnable standalone via 'uv run python onboard.py env'",
77+
"Typecheck passes"
78+
],
79+
"priority": 4,
80+
"passes": true,
81+
"notes": ""
82+
},
83+
{
84+
"id": "US-005",
85+
"title": "Implement pre-commit hooks activation step",
86+
"description": "As a user, I want to be prompted to activate pre-commit hooks so that code quality checks run automatically on every commit.",
87+
"acceptanceCriteria": [
88+
"The 'hooks' subcommand reads .pre-commit-config.yaml and lists the configured hook names",
89+
"Displays hooks in a rich Table with columns for hook name and description",
90+
"Shows a questionary.confirm prompt recommending activation with text like 'Activate pre-commit hooks? (Recommended)'",
91+
"If user accepts, runs 'git config core.hooksPath .githooks' via subprocess",
92+
"Prints green success message on activation",
93+
"If user declines, prints a note: 'You can activate later with: git config core.hooksPath .githooks'",
94+
"Runnable standalone via 'uv run python onboard.py hooks'",
95+
"Typecheck passes"
96+
],
97+
"priority": 5,
98+
"passes": true,
99+
"notes": ""
100+
},
101+
{
102+
"id": "US-006",
103+
"title": "Refactor banner and logo scripts to accept parameters",
104+
"description": "As a developer, I need the generation scripts to accept title and theme as function parameters so the onboarding CLI can invoke them programmatically.",
105+
"acceptanceCriteria": [
106+
"init/generate_banner.py exposes an async function generate_banner(title: str, theme: str) that performs the banner generation",
107+
"init/generate_logo.py exposes an async function generate_logo(project_name: str, theme: str) that performs the logo generation",
108+
"The __main__ blocks in both files call these functions with default values so 'make banner' and 'make logo' still work",
109+
"Both functions accept the theme/suggestion as a parameter instead of hardcoding it",
110+
"Both functions accept the project title/name as a parameter instead of hardcoding it",
111+
"Existing make banner and make logo targets still work as before",
112+
"Typecheck passes"
113+
],
114+
"priority": 6,
115+
"passes": true,
116+
"notes": ""
117+
},
118+
{
119+
"id": "US-007",
120+
"title": "Implement media generation step in CLI",
121+
"description": "As a user, I want to describe my project's visual theme during onboarding and have banner and logo assets generated automatically.",
122+
"acceptanceCriteria": [
123+
"The 'media' subcommand checks if GEMINI_API_KEY is set in .env or os.environ",
124+
"If GEMINI_API_KEY is not set, prints a warning and offers to skip via questionary.confirm",
125+
"Prompts user for a theme/style description via questionary.text with example placeholder text",
126+
"Asks user what to generate via questionary.select with options: Banner only, Logo only, Both, Skip",
127+
"Calls the refactored generate_banner() and/or generate_logo() functions from init/ with the project name and theme",
128+
"Shows a rich spinner during generation with status text like 'Generating banner...'",
129+
"On completion, prints file paths of all generated assets",
130+
"Runnable standalone via 'uv run python onboard.py media'",
131+
"Typecheck passes"
132+
],
133+
"priority": 7,
134+
"passes": true,
135+
"notes": "Depends on US-006 (refactored init scripts). The project name for media generation should come from pyproject.toml."
136+
},
137+
{
138+
"id": "US-008",
139+
"title": "Implement full onboarding flow orchestrator",
140+
"description": "As a user, I want to run the full onboarding in sequence so that I go from a fresh clone to a fully configured project in one command.",
141+
"acceptanceCriteria": [
142+
"Running 'uv run python onboard.py' with no subcommand executes all steps in order: rename, deps, env, hooks, media",
143+
"Shows a rich welcome Panel at the start with project name and description of what will happen",
144+
"Between each step, shows a step progress header like 'Step 2/5: Dependencies'",
145+
"Before each step, asks 'Run this step? (Y/n/skip)' - user can skip individual steps",
146+
"At the end, prints a rich summary Panel showing what was completed (green checkmarks) and what was skipped (yellow dashes)",
147+
"Summary includes suggested next commands: make test, make ci, make all",
148+
"If a step fails, prints the error and asks whether to continue or abort",
149+
"Typecheck passes"
150+
],
151+
"priority": 8,
152+
"passes": true,
153+
"notes": "Depends on all previous stories (US-002 through US-007) being implemented."
154+
},
155+
{
156+
"id": "US-009",
157+
"title": "Remove old Makefile targets and update documentation",
158+
"description": "As a maintainer, I want the old make init/setup/setup_githooks targets removed and all docs updated so there is one clear onboarding path.",
159+
"acceptanceCriteria": [
160+
"make init target removed from Makefile",
161+
"make setup target removed from Makefile",
162+
"make setup_githooks target removed from Makefile",
163+
"New 'make onboard' target added that runs 'uv run python onboard.py'",
164+
"CLAUDE.md updated: replace make init / make setup references with make onboard and CLI subcommand equivalents",
165+
"README.md updated with new onboarding instructions referencing make onboard",
166+
"Any other Makefile targets that depended on setup (e.g. 'all' target) are updated to use the new deps flow or call uv sync directly",
167+
"Update README.md with instructions for the onboarding CLI",
168+
"Document how to run individual steps (uv run python onboard.py <step>)",
169+
"Typecheck passes",
170+
"All tests pass"
171+
],
172+
"priority": 9,
173+
"passes": true,
174+
"notes": ""
175+
}
176+
]
177+
}

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ dependencies = [
3434
"numpy>=2.2.2",
3535
"typer",
3636
"questionary",
37+
"rich>=14.3.1",
3738
]
3839
readme = "README.md"
3940
requires-python = ">= 3.12"

scripts/ralph/progress.txt

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
## Codebase Patterns
2+
- uv is not pre-installed in this environment; install via `curl -LsSf https://astral.sh/uv/install.sh | sh`
3+
- Alpine Linux environment - use `sudo apk add` for system packages, needs `gcc g++ musl-dev` for scikit-learn build
4+
- Add new CLI/script files to `[tool.vulture] exclude` in pyproject.toml to avoid false positives on CLI entry points
5+
- Set git identity with `git config user.email/user.name` before committing (not pre-configured)
6+
- ruff C901 complexity limit is 10; extract helpers to keep functions under this limit
7+
- ruff B904: `raise` inside `except` must use `from err` or `from None`
8+
- pytest runs with `-n auto` by default (parallel); override with `-o "addopts=-n0"` for single-threaded
9+
- Use `TERM=dumb OPENBLAS_NUM_THREADS=1` to avoid terminal/thread warnings in this environment
10+
- `onboard.py` is the interactive CLI entry point; `make onboard` invokes it
11+
12+
# Ralph Progress Log
13+
Started: Mon Feb 23 23:48:11 UTC 2026
14+
---
15+
16+
## 2026-02-24 - US-001
17+
- Created `onboard.py` at project root with typer CLI scaffold
18+
- Added `typer` and `questionary` as project dependencies via `uv add`
19+
- 5 subcommands: rename, deps, env, hooks, media - all with placeholder implementations
20+
- Running with no args calls main orchestrator (placeholder)
21+
- `--help` shows all subcommands
22+
- Added `onboard.py` to vulture exclusions in pyproject.toml
23+
- Files changed: onboard.py (new), pyproject.toml, uv.lock
24+
- **Learnings for future iterations:**
25+
- uv needs to be installed first in this environment
26+
- Alpine needs gcc/g++/musl-dev for scikit-learn (transitive dep from scrubadub)
27+
- typer's `invoke_without_command=True` + `@app.callback` pattern handles no-subcommand invocation
28+
---
29+
30+
## 2026-02-24 - US-002
31+
- Implemented `rename` subcommand in onboard.py
32+
- Prompts for kebab-case project name with regex validation
33+
- Prompts for free-text description
34+
- Updates pyproject.toml name and description fields
35+
- Updates README.md heading and tagline
36+
- Shows rich Panel summary of changes
37+
- Skips with info message if project already renamed (name != 'python-template')
38+
- Files changed: onboard.py
39+
- **Learnings for future iterations:**
40+
- README tagline is wrapped in `<b>` tags: `<b>Opinionated Python project stack. 🔋 Batteries included. </b>`
41+
- questionary returns None on Ctrl+C; use `typer.Abort()` to handle cancellation
42+
- `_validate_kebab_case` returns `True` or error string for questionary validation
43+
---
44+
45+
## 2026-02-24 - US-003
46+
- Implemented `deps` subcommand in onboard.py
47+
- Checks uv availability via `shutil.which('uv')`
48+
- Creates .venv via `uv venv` if not exists
49+
- Runs `uv sync` with rich spinner
50+
- Shows green success or red error messages
51+
- Files changed: onboard.py
52+
- **Learnings for future iterations:**
53+
- Use `rich.console.Console().status()` for spinner display
54+
- `subprocess.run` with `capture_output=True` for clean output handling
55+
---
56+
57+
## 2026-02-24 - US-004
58+
- Implemented `env` subcommand in onboard.py
59+
- Parses .env.example for groups (comment lines) and key/value pairs
60+
- Loads existing .env and identifies configured keys (non-placeholder values)
61+
- Presents questionary.checkbox with grouped keys, pre-checking configured ones
62+
- Uses questionary.password for SECRET/KEY/TOKEN/PASSWORD keys
63+
- Asks to keep existing values for already-configured keys
64+
- Writes .env preserving group structure, commenting out unselected keys
65+
- Refactored into helper functions to keep complexity under ruff C901 limit (max 10)
66+
- Files changed: onboard.py
67+
- **Learnings for future iterations:**
68+
- ruff C901 complexity limit is 10; env step needed 3 helper functions to comply
69+
- .env.example uses `# Group Name` comments to define sections
70+
- Placeholder values like `sk-...` need to be treated as empty
71+
---
72+
73+
## 2026-02-24 - US-005
74+
- Implemented `hooks` subcommand in onboard.py
75+
- Reads .pre-commit-config.yaml and lists hooks in a rich Table
76+
- Prompts for activation with questionary.confirm (default=True)
77+
- Runs `git config core.hooksPath .githooks` on activation
78+
- Shows helpful message with manual command on decline
79+
- Files changed: onboard.py
80+
- **Learnings for future iterations:**
81+
- .pre-commit-config.yaml has repos > hooks structure with id and name fields
82+
- yaml import done inside function to avoid top-level import (only needed for hooks)
83+
---
84+
85+
## 2026-02-24 - US-006
86+
- Refactored init/generate_banner.py: renamed `suggestion` param to `theme` in BannerDescription signature and generate_banner() function
87+
- Refactored init/generate_logo.py: renamed `suggestion` param to `theme` in WordmarkDescription signature and generate_logo() function
88+
- __main__ blocks updated to use `theme` variable name
89+
- `make banner` and `make logo` still work (they call `__main__` blocks)
90+
- Files changed: init/generate_banner.py, init/generate_logo.py
91+
- **Learnings for future iterations:**
92+
- Both scripts already accepted parameters; the main change was renaming `suggestion` → `theme`
93+
- generate_banner returns Image.Image; generate_logo returns dict[str, Image.Image]
94+
- generate_logo also accepts `output_dir` parameter (defaults to docs/public/)
95+
---
96+
97+
## 2026-02-24 - US-007
98+
- Implemented `media` subcommand in onboard.py
99+
- Checks GEMINI_API_KEY in .env and os.environ
100+
- Offers to skip if key not configured
101+
- Prompts for theme/style description
102+
- questionary.select for: Banner only, Logo only, Both, Skip
103+
- Calls refactored generate_banner() / generate_logo() with project name from pyproject.toml
104+
- Shows spinner during generation, prints generated file paths
105+
- Extracted `_run_media_generation()` helper to keep C901 complexity under 10
106+
- Files changed: onboard.py
107+
- **Learnings for future iterations:**
108+
- `_check_gemini_key()` reads .env directly (not through dotenv) to check key presence
109+
- Local imports of init modules used inside function to avoid import errors at CLI startup
110+
---
111+
112+
## 2026-02-24 - US-008
113+
- Implemented full onboarding orchestrator in `_run_orchestrator()`
114+
- Shows welcome Panel with project name and step overview
115+
- Runs all 5 steps in order: rename, deps, env, hooks, media
116+
- Each step shows "Step N/5: Name" header
117+
- Users can skip individual steps via Yes/Skip select
118+
- If a step fails (non-zero exit), asks whether to continue or abort
119+
- Final summary Panel shows completed (green checkmarks) and skipped (yellow dashes)
120+
- Includes suggested next commands: make test, make ci, make all
121+
- Uses STEP_FUNCTIONS dict to register step functions after definition
122+
- Extracted `_print_summary()` helper
123+
- Files changed: onboard.py
124+
- **Learnings for future iterations:**
125+
- ruff B904: raise in except must use `from err` or `from None`
126+
- ruff F541: f-strings without placeholders are flagged
127+
- typer.Exit and SystemExit both caught for step failure handling
128+
---
129+
130+
## 2026-02-24 - US-009
131+
- Removed `make init`, `make setup`, `make setup_githooks` targets from Makefile
132+
- Added `make onboard` target that runs `uv run python onboard.py`
133+
- Updated `make all` to use `uv sync` directly instead of `setup` + `setup_githooks`
134+
- Updated CLAUDE.md: replaced `make init`/`make setup` references with `make onboard` and CLI subcommands
135+
- Updated README.md Quick Start: replaced `make init` with `make onboard`, added CLI subcommand docs
136+
- All 15 tests pass, typecheck passes, ruff passes
137+
- Files changed: Makefile, CLAUDE.md, README.md
138+
- **Learnings for future iterations:**
139+
- `make all` depended on `setup` and `setup_githooks` - updated to `check_uv` + inline `uv sync`
140+
- pytest.ini has `addopts = -n auto` which runs tests in parallel by default
141+
- Use `-o "addopts=-n0"` to override and run tests single-threaded
142+
---

0 commit comments

Comments
 (0)