Built by pi.
Heavily inspired by the pi design philosophy: maximize simplicity and extensibility.
Generate reproducible, scope-locked pi project instances from a validated profile.json plus pinned allowlist.lock.json.
pi-shell exists for one job: create new instance directories with deterministic settings and a provenance manifest. It does not update, mutate, or manage existing instances.
Most setup scripts drift. Teams patch local settings, pull unpinned package refs, and lose track of what produced a given environment.
pi-shell enforces a stricter contract:
- profile and allowlist are schema-validated
- every referenced resource must exist in the allowlist
- allowlist pins must be immutable (
x.y.zor full 40-char SHA) - output includes content hashes and source pins in
.pi-shell-manifest.json - target must be empty (or non-existent) to prevent in-place mutation
npm install -g @4meta5/pi-shell-cli
pi-shell up ./my-instance --profile ./profile.json --yesFor each run, pi-shell up writes:
.pi/settings.json.pi-shell-manifest.json
The manifest captures:
oneWay: trueprofileHashallowlistHashtemplateVersiongeneratedAt- exact source pins used for extensions, packages, and skills
profile.json (shape summary):
{
"name": "my-instance",
"models": { "default": "claude-opus-4-5", "allowed": ["claude-opus-4-5"] },
"extensions": [],
"packages": [],
"skills": [],
"docs": { "references": [] }
}allowlist.lock.json:
{
"version": 1,
"entries": [
{
"id": "example-extension",
"kind": "pi-extension",
"source": "git:github.com/org/repo",
"pin": "0123456789abcdef0123456789abcdef01234567"
}
]
}Usage: pi-shell up [targetPath] [options]
Options:
--profile <path> Path to profile.json (default: ./profile.json)
--dry-run Show what would be generated without writing
--yes Skip confirmation prompt
--help Show this help message
In scope:
- validate profile + allowlist
- enforce immutable pins
- generate settings + manifest in a new directory
Out of scope:
- updating existing instances
- mutating generated instances in place
- package installation or syncing
- long-running daemons or background orchestration
npm test
npm run test:e2eMIT