skeleton (internal)¶
Create the project skeleton a rhiza-managed repo needs — in Python, Rust or Go — and finish it into the shape the template's gates require.
Not a slash command
This is an internal procedure (plugin/prompts/skeleton.md), not something you
invoke. /rhiza:init reads and follows it at its step 5b.
Why it exists¶
The rhiza template never ships a pyproject.toml. The sync delivers the
Makefile, ruff.toml, pytest.ini, .python-version and CI —
but the project metadata is always the repo's own. So without one,
/rhiza:update's gates can't run at all: make test depends on
install (a uv sync), and the synced .rhiza/tests/test_pyproject.py asserts a
specific [project] shape. This command produces that shape.
It's a thin wrapper around the language's own initialiser (uv init --lib,
cargo init --lib, go mod init) plus the bundled plugin/scripts/init_skeleton.py.
The steps below are the Python path; see Rust and Go.
What it does¶
- Settles the inputs — runs install-uv first, derives
owner/repo from the
originremote when there is one, and asks for the description (the gate requires a non-empty one) and, on a fresh repo, the Python version (3.11–3.14). - Runs
uv init --lib— only when there's nopyproject.tomlyet. It writespyproject.toml,src/<pkg>/__init__.py(+py.typed),README.md,.gitignore, and.python-version, and initialises a git repo if needed. An existingpyproject.tomlis never touched byuv init. - Finishes it via
plugin/scripts/init_skeleton.py— four idempotent, additive edits: src/<pkg>/__init__.py— replaces uv'shello()placeholder with a package docstring (it's undocumented and untested, so it fails both the interrogate and coverage gates). Rewritten only while it's still uv's placeholder.[project].description— fills in uv'sAdd your description here; a real description is left alone.[project.urls]— adds the requiredHomepageandRepository. Existing entries win.[dependency-groups]— adds the requiredtestgroup (pytestandpytest-cov, lower-bounded) when absent. Existing groups are untouched, and nolintgroup is seeded — the template provisions linters through prek/uvx.- Delegates the Python metadata to
python-version —
requires-python, theProgramming Language :: Python :: X.Yclassifiers, and.python-version.
The license is not its job: license owns that, and
/rhiza:init follows it immediately after this procedure.
Rust and Go¶
Same shape, different manifest — and each has one thing the others don't:
| Rust | Go | |
|---|---|---|
| initialiser | cargo init --lib |
go mod init <module path> |
| manifest | Cargo.toml |
go.mod |
| profile | rust-local |
go-local |
| docs gate | #![warn(missing_docs)] — a //! crate doc is prepended, never substituted, because cargo's stub holds the crate's only test |
revive's exported rule — a doc.go package comment, since go mod init writes no Go file at all |
| metadata | [package] gains description, repository, homepage, authors |
nothing to add: go.mod has no such fields |
| version location | .bumpversion.toml, anchored to [package] and to Cargo.lock |
not written here — a Go module's version is its git tag, and go-core ships the config; it arrives with the first /rhiza:update |
The gate is the same idea in each: cargo metadata (Rust) or go list -m plus
go vet (Go) must pass, or the procedure stops rather than hand-writing a manifest.
Notes¶
- Idempotent. Run it twice and the second run changes nothing. Safe on a mature repo — it only fills gaps.
- No license classifiers, ever. Neither this command nor
license writes a
License :: …trove classifier — PEP 639 replaced it with the SPDXlicensefield. The template'stest_pyproject.pystill asserts one, so that check can fail; it runs undermake rhiza-tests, notmake test, so it doesn't block the main suite. It's reported as an upstream template question rather than papered over with a deprecated classifier. The only classifiers written are/python-version's Python entries. [project].authors— the gate wants at least one, anduv initonly populates it from yourgit config. The command flags it if it's missing.- Lower bounds on every dependency (
httpx>=0.27, never barehttpx), including optional and dependency-group entries.
Reference¶
| Source | plugin/prompts/skeleton.md |
| Invocation | not a slash command — reached with Read, never invoked |
| Read by | /rhiza:init, license, python-version |