Skip to content

Commit 8a2ea07

Browse files
authored
Merge pull request #57 from Pipelex/release/v0.10.0
Release/v0.10.0
2 parents 0d74d18 + 0aa7388 commit 8a2ea07

18 files changed

Lines changed: 927 additions & 3155 deletions

File tree

.claude/skills/bootstrap/SKILL.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
name: bootstrap
3+
description: Bootstrap this pipelex-starter-python template into a real project — replaces every placeholder name (my-project / my_project / "My Project" / TestMyProject), the package directory, description, author, repo URL and LICENSE holder, then regenerates the lock file and runs the checks and tests. Use this right after creating a repo from the template, or whenever the user says "bootstrap", "set up this template", "rename the project", "initialize the project", "replace the placeholders", "give this project a name", or "make this my own".
4+
---
5+
6+
# Bootstrap Workflow
7+
8+
This repo is a GitHub **template**. A fresh clone still has placeholder names everywhere: the distribution name `my-project`, the importable package `my_project` (a directory plus many references), the README title `My Project`, and the e2e test class `TestMyProject`. This skill turns those placeholders into the user's real project name in one reviewable pass, then proves the result still passes CI's gates.
9+
10+
The mechanical replacement is done by a bundled script — `scripts/bootstrap.py` — because the same name appears in four spellings across code, config, docs, and the license, plus two filesystem renames. The script is deterministic and supports `--dry-run`, so you can show the plan before touching anything. **Your job in this skill is to collect good inputs, preview, run the script, and verify.** Walk the user through it; confirm before the steps that change files.
11+
12+
## Step 1 — Preflight
13+
14+
Confirm this is an un-bootstrapped template and the tree is clean enough to work in:
15+
16+
1. Read the `name = "..."` line near the top of `pyproject.toml`.
17+
- If it is `name = "my-project"`: this is a fresh template — continue.
18+
- If it is anything else, or the `my_project/` directory is gone: it looks **already bootstrapped**. Tell the user and ask whether to proceed anyway (the script is safe to re-run but most edits will be no-ops).
19+
2. Run `git status --short`. If the tree is dirty, mention it — bootstrap will add edits and renames on top, and the user asked for changes to be left **unstaged** for their own review, so a noisy starting point is worth flagging.
20+
21+
## Step 2 — Collect the project details
22+
23+
Ask the user for the following in one consolidated message. Lead with the package name (everything else derives from it) and offer sensible defaults so they can just confirm.
24+
25+
**Required:**
26+
- **Package name** (importable, underscores) — e.g. `invoice_extractor`. Must be lowercase letters/digits/underscores, starting with a letter. This becomes the package directory and every `import` / `library_dirs` reference.
27+
- **Display title** — e.g. `Invoice Extractor`. Default: the package name title-cased. Goes in the README H1.
28+
- **Description** — a one-liner for `pyproject.toml`. (Currently `"Replace this with your project description"`.)
29+
30+
**Optional** (let them skip any):
31+
- **Author** — fills the commented-out `authors = [...]` line in `pyproject.toml`. Ask for **both name and email**; if the user offers only one, explicitly ask for the other (an email with no name is a common omission — confirm the name rather than inventing one or silently pulling it from `git config`).
32+
- **GitHub repository URL** — e.g. `https://github.com/acme/invoice-extractor`. Replaces the `yourusername/my-project` Repository URL and the README clone URLs.
33+
- **License** — the template ships **MIT**. Ask which license the user wants, because switching type (not just the holder) touches three places — the `LICENSE` body, `license = "..."` in `pyproject.toml`, and the README license line — and the script handles all three so you don't have to edit them by hand. Offer:
34+
- **Keep MIT** (default) — pass `--license-holder` (and optionally `--license-year`) to refresh the copyright line; the MIT body stays.
35+
- **Proprietary / all rights reserved** — the script rewrites `LICENSE` to an "all rights reserved" notice and sets `license = "LicenseRef-Proprietary"`. Proprietary has **no SPDX id**, and `uv lock --locked` (CI) validates that field, so the `LicenseRef-` form is required — the script uses it automatically. Collect the copyright holder.
36+
- **Other SPDX license** (e.g. `Apache-2.0`) — the script sets the `license =` field and README label and writes a `LICENSE` **stub**; warn the user they must paste the full license text in themselves (the script can't author arbitrary license bodies).
37+
- **Copyright holder + year** — collect the holder for any non-default choice; the year **defaults to the current year** (the script reads the system clock — don't hardcode or assume it) and can be overridden with `--license-year`.
38+
39+
Derive and show the four name forms so the user can sanity-check before anything runs:
40+
- distribution (dashes): package with `_``-` (e.g. `invoice-extractor`) — override-able
41+
- package (underscores): as given
42+
- title: as given
43+
- test class: `Test` + CamelCase of the package (e.g. `TestInvoiceExtractor`)
44+
45+
If the user gives a title but no package name, slugify the title to underscores for the default package name and confirm it.
46+
47+
## Step 3 — Preview (dry run)
48+
49+
Before changing anything, run the script in dry-run mode and show the user the plan:
50+
51+
```bash
52+
python .claude/skills/bootstrap/scripts/bootstrap.py \
53+
--package "<package>" \
54+
--title "<title>" \
55+
--description "<description>" \
56+
[--author-name "<name>" --author-email "<email>"] \
57+
[--repo-url "<url>"] \
58+
[--license "mit|proprietary|<spdx-id>"] \
59+
[--license-holder "<holder>"] \
60+
[--license-year "<year>"] \
61+
--clean \
62+
--dry-run
63+
```
64+
65+
`--license` defaults to `mit`; pass `proprietary` or an SPDX id when the user chose otherwise. `--license-year` defaults to the current year (read from the system clock) — only pass it to override.
66+
67+
Pass `--clean` because the user opted to strip the template-only scaffolding (the README "Use this template / Next steps" block; the bootstrap skill itself is removed separately in Step 6). Omit it only if the user changed their mind and wants the template block kept.
68+
69+
The dry run prints the renames and the list of files that would be edited. Present that summary and **get explicit confirmation** before the real run. Only pass `--dist` if the user wants a distribution name that isn't just the package with dashes.
70+
71+
## Step 4 — Run the replacement
72+
73+
Re-run the exact same command **without** `--dry-run`. The script:
74+
- renames `my_project/``<package>/` and `tests/e2e/test_my_project.py``tests/e2e/test_<package>.py` (via `git mv`, so history follows)
75+
- substitutes all four name spellings across `pyproject.toml`, `README.md`, `CLAUDE.md`, the package's `.py`/`.mthds` files, and the tests
76+
- fills in description, and (if given) author, repo URL
77+
- applies the license choice in all three places: the `LICENSE` body, `license = "..."` in `pyproject.toml`, and the README license line
78+
- strips the README template block
79+
80+
It deliberately does **not** run the lock file, run the checks, commit, or touch `.github/`, `.venv/`, `uv.lock`, or the existing `release` skill.
81+
82+
**Heads-up — file state changed on disk.** The script rewrites `pyproject.toml`, `README.md`, and `LICENSE` (and `--clean` shifts README line numbers). If you find you need a manual `Edit` afterward, **re-read the file first** and re-derive any line numbers — a pre-run `grep` result is stale, and an `Edit` against an unread/old version will fail with "modified since read." In practice the script is meant to cover every placeholder so manual edits shouldn't be needed; if you reach for one, it's worth checking whether the script should handle that case instead.
83+
84+
**Heads-up — staging is mixed.** `git mv` *stages* the renames (they show as `R` in `git status`), while the content edits stay unstaged (`M`). That's intentional — staged renames give the cleanest diff for review — but it means the change set is not uniformly unstaged. Nothing is committed. The user reviews everything with `git status` + `git diff` and commits when ready (a single `git add -A && git commit` captures both the staged renames and the unstaged edits).
85+
86+
## Step 5 — Regenerate the lock file and verify
87+
88+
The renamed distribution must be reflected in `uv.lock`, or CI's `package-check.yml` (`uv lock --locked`) fails the PR. Then run the same gates `lint-check.yml` and `tests-check.yml` enforce. All three are quiet on success:
89+
90+
```bash
91+
make li # uv lock + uv sync — refreshes uv.lock for the new project name
92+
make agent-check # ruff format/lint, plxt, pyright, mypy
93+
make agent-test # tests, excludes inference/LLM markers
94+
```
95+
96+
- **On success**: report it and continue.
97+
- **On failure**: show the output and fix the cause (a leftover reference, a stale import, a name that didn't get rewritten), then re-run. Don't move on with a red check — the PR's CI will be red too. `make agent-check` auto-formats, so it may itself modify files; that's expected.
98+
99+
## Step 6 — Clean up the bootstrap scaffolding & hand off
100+
101+
Bootstrap is a one-shot, so it removes itself **last**, only after the checks are green:
102+
103+
```bash
104+
rm -rf .claude/skills/bootstrap
105+
```
106+
107+
Use a plain `rm` (not `git rm`) so the deletion stays unstaged, like the other content changes.
108+
109+
Finally, give the user a short summary:
110+
- the four name forms that were applied, and the license that was set
111+
- that the package directory and e2e test file were renamed
112+
- that `uv.lock` was regenerated and `make agent-check` / `make agent-test` pass
113+
- that **nothing is committed**; the renames are staged (`R`) and the content edits are unstaged (`M`) — they should review with `git status` and `git diff`, then commit (a single `git add -A && git commit` captures everything)
114+
- a nudge to skim the new `README.md` and write real project content, and to update `CLAUDE.md` if the project's specifics have changed
115+
116+
## Rules
117+
118+
- **Never commit; let the user review and commit.** Don't `git commit` or `git add` content edits. The renames go through `git mv` (so they're staged as clean `R` entries — that's fine and gives the best diff) while everything else, including the self-removal (`rm`, not `git rm`), stays unstaged. Tell the user the staging is mixed so the "review then commit" handoff isn't a surprise.
119+
- **Always dry-run before the real run** and get confirmation. This edits a brand-new repo and renames a directory; the preview is cheap insurance.
120+
- **Regenerate `uv.lock`.** Renaming the distribution name makes the lock stale; `make li` (or `uv lock`) is what keeps `package-check.yml` green. Don't skip it.
121+
- **Don't stop on a red check.** A failing `make agent-check` / `make agent-test` here means CI will fail too — fix the root cause and re-run.
122+
- **Don't touch the `release` skill or `.github/` workflows** — they're generic to the template and not placeholders.
123+
- If any step fails or the user wants to abort, stop immediately and leave the tree in a state they can inspect — don't push forward through errors.

0 commit comments

Comments
 (0)