A composition orchestrator for project scaffolding — compose layers, not templates.
Project description
initree
A composition orchestrator for project scaffolding. It builds a project by composing small, independent layers — language, framework, container, ci, deploy, notify — that exchange data through a typed capability bus. Breadth comes from composing N+M+K layers, not from maintaining N×M×K templates.
initree new myapp --recipe go+gin+docker+gitlab-ci+k8s+slack
Swap one slot and nothing else moves. A consumer binds to a capability key (container.exposed_port),
never to the tool that produced it, so docker→podman or gh-actions→gitlab-ci touches no other layer.
Install
uv tool install initree # or: pipx install initree
Then initree is on your PATH. To run it without installing:
uvx initree new myapp --recipe python+fastapi+docker+gh-actions+vps-ssh
Usage
A recipe is slot layers joined by +. initree new <name> --recipe <recipe> validates the
composition, prompts for each layer's inputs, then writes the project.
Slice 1 — a deployable FastAPI service:
initree new myapp --recipe python+fastapi+docker+gh-actions+vps-ssh
Slice 2 — a Go service on a second CI dialect with a namespaced deploy and an optional notifier:
initree new myapp --recipe go+gin+docker+gitlab-ci+k8s+slack
What the Go recipe writes:
created ./myapp
order: go -> gin -> docker -> k8s -> slack -> gitlab-ci
+ .gitignore
+ go.mod
+ cmd/server/main.go
+ internal/handler/handler.go
+ .dockerignore
+ Dockerfile
+ k8s/deployment.yaml
+ k8s/kustomization.yaml
+ k8s/service.yaml
+ .gitlab-ci.yml
secrets: INITREE_SECRETS.md (provision before first deploy)
INITREE_SECRETS.md is a provisioning checklist generated from the secret purposes the recipe's
layers declare (registry credentials, an SSH key, a Slack webhook). No secret value ever enters the
build — the file tells you what to set, where.
Recipes are subsets, not fixed tuples
Pick one layer per slot you need. notify is optional; drop it and the rest is unchanged. The
shipped layers:
| slot | layers |
|---|---|
| language | python, go |
| framework | fastapi, gin |
| container | docker |
| ci | gh-actions, gitlab-ci |
| deploy | vps-ssh, k8s |
| notify | slack |
CLI
initree new NAME --recipe RECIPE [options]
--recipe TEXT slot layers joined by '+' (required)
--out PATH output directory (default: ./<name-slug>)
--set KEY=VALUE seed a context key directly; repeatable, skips its prompt
--no-input take input defaults instead of prompting
--no-finalize skip finalize hooks (chmod, git init, formatters)
--layers-dir PATH load layers from here (default: the bundled layers)
--set is how you script a build: --no-input --set app.port=9000 --set deploy.host=user@host.
How it works
The engine runs five global phases; layers run in topological order, each uninterrupted:
- resolve — load manifests, prove the recipe is buildable (no
ownsoverlap, every requiredconsumeshas a provider, every injection target exists, the graph is acyclic), compute order. No files written. - prompt — collect each layer's
inputs. - compute — resolve every
provides(${namespace.key}interpolation), then freeze the bus. - emit — render each layer's owned templates, then splice injected fragments into their owner's file at the declared anchor.
- finalize — per-layer hooks.
Each file has exactly one owning layer. The only way another layer adds to a file is a named
injection point the owner declares. The full contract lives in docs/:
docs/01-layer-contract-and-lifecycle.md— the manifest schema and the lifecycle, worked through one slicedocs/02-generalization-proof.md— the same engine across two unrelated stacks, and why the graph stays acyclicdocs/03-capability-registry-v1.md— the locked capability vocabularydocs/04-layer-authoring-guide.md— how to write your own layer
Develop
uv sync
uv run pytest
uv run ruff check src tests
uv run pyright
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file initree-0.1.0.tar.gz.
File metadata
- Download URL: initree-0.1.0.tar.gz
- Upload date:
- Size: 58.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c241d96ae7f5dae80f51afbef0e369f0f36d1c9e93eb2d30b0d9672b017be23
|
|
| MD5 |
1793907b19c90cda18fef47515db01d6
|
|
| BLAKE2b-256 |
d31019ed48e99af0f6e70d18a16c172ebf366a79a7014d986f8ddcbbb99d1786
|
File details
Details for the file initree-0.1.0-py3-none-any.whl.
File metadata
- Download URL: initree-0.1.0-py3-none-any.whl
- Upload date:
- Size: 54.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4bf967866de205f87a0a72fad3548d9cecaa814ecbd11ad06fca0552d2f540ef
|
|
| MD5 |
30ff72170fd4f6509e91e5aa3bf2b13a
|
|
| BLAKE2b-256 |
325f3642575ad1236847d8b2793b1687dbeadcb373d0d7908dbf4642b9d14cc7
|