create-shibumi CLI.
create-shibumi CLI
Every template deploys to a Linux VPS through shibumi-server.
Create a project#
Three questions, then the project exists:
bun create shibumi@latest my-appbun create shibumi@latest my-app
渋み shibumi
success|Project name?
answer|quiet-bamboo
success|What are you shipping?
answer|Bun full-stack app (recommended)
success|Deploy to a VPS now?
answer|Later
result|Created quiet-bamboo
success|Template copied
success|Git initialized; nothing committed, the first commit is yours
success|Dependencies installed
success|Deploy script added (scripts/ship.ts)
info|Next: cd quiet-bamboo, bun dev, and bun ship:setup when you're ready
outro|Docs: https://shibumistack.dev/docs
Answering Yes to the deploy question runs bun ship:setup in the same session, so the project's first deploy happens before you leave the terminal. Later prints the command instead.
Automation skips the questions:
bun create shibumi@latest my-app --template full-stack --yes
--template takes full-stack, blog, or static. --no-git and --no-install skip those steps. VPS deployment only (for now); provider choices stay out until generated fixtures prove each build and deploy path.
Add deployment to an existing project#
A dot instead of a name adopts the current directory. Instead of scaffolding, the deploy script is copied in next to your own files. Your existing files are left as they are, with one exception: package.json gains the ship* scripts and a @clack/prompts dev dependency, since the deploy script imports it.
bun create shibumi .bun create shibumi .
渋み shibumi
info|Existing project found (Astro detected)
success|Add deploy tooling to this project?
answer|Yes
success|Built site directory?
answer|dist/ (detected)
success|Wrote scripts/ship.ts, package.json, Dockerfile, compose.yaml, .dockerignore
success|Added scripts: ship, ship:setup, ship:update, ship:status, ship:logs, ship:webhook
result|Installed @clack/prompts
success|Deploy to a VPS now?
answer|Later
info|Deployments serve dist/. Review the generated Dockerfile and compose.yaml.
outro|Docs: https://shibumistack.dev/docs
The build directory is detected from your dependencies and config files, with the framework signal winning over a directory that happens to be on disk:
| Signal | Directory |
|---|---|
astro or astro.config.* | dist |
@11ty/eleventy or eleventy.config.* | _site |
next or next.config.* | out |
vite or vite.config.* | dist |
a dist, _site, out, or build directory | that one |
a public directory | public |
A dependency or a config file counts as the same signal. Astro and Eleventy both pull Vite in, so a bare Vite match loses to either of them.
Pick Somewhere else to type a path the table missed. --spa makes unknown paths serve index.html; without it, unknown paths 404, which is what a content site wants.
Adopting refuses in three cases rather than guessing:
- Deployment files already exist. A
Dockerfileorcompose.yamlthat Shibumi did not write may build or run something other than your site, so adopting stops and asks you to remove or rename them. - The project is a server app. A
startscript means something runs inside the container, and that isbun ship:setup's job: it asks server or static and writes the matching files. To ship a static build from a project that also has astartscript, runbun ship:setup --static --output-dir <dir>. index.htmlsits at the project root with no directory to serve. The table above found nothing, so the site is a flat pile of files at the root. A static image serves one directory and never packages a whole checkout, so move the site down a level withmkdir public && git mv index.html public/, then adopt again. A project with a detected build directory adopts normally, rootindex.htmlor not.
Without a build script, the output directory has to be committed already, so the shipped image matches the exact commit the server verifies.
Shared project contract#
Generated projects import their libraries directly. Each applicable project includes:
- route or artifact tests and TypeScript checks
- root
agents.mdguidance - current reviewed
scripts/ship.ts - loopback-only Compose configuration, resource limits, and a health check
- package commands for development, setup, status, logs, rollback, and shipping
Project creation initializes Git only when selected. It never stages or commits user files. Existing paths are never overwritten silently, and failed creation leaves the destination absent or unchanged.
Static sites#
Static publishing depends on an artifact contract rather than a framework adapter:
- output path must be relative and remain inside project root
- build must produce
index.html - missing or empty output fails before packaging
- normal file and
404.htmlhandling is default - SPA fallback is explicit, never inferred
Shibumi packages the verified directory in a small static image and checks / before deployment. A framework's source public/ directory does not count unless it is also the completed output.
Blog#
The blog template runs on the same engine as this site — a Bun + Hono markdown renderer — with the parts a blog needs on day one: posts in Markdown, RSS, a sitemap, SEO meta tags, and an llms.txt for agents. It builds to dist/ and ships through the same static path, so bun ship:setup arrives pre-configured.
Full-stack SQLite#
A full-stack project stores its database under persistent /data and enables WAL mode, foreign keys, and a bounded busy timeout. It includes tracked migrations, a fresh-database migration test, pre-migration backup, backup retention, and an explicit restore command.
The project includes database infrastructure and tested queries without an unauthenticated demo mutation endpoint.
Release acceptance#
Tests run against the packed npm artifact, not repository source. Every starting point passes its applicable matrix:
bun install --frozen-lockfile
bun test
bun run check
bun run build
Static output must package only the configured artifact. Bun containers must start on the assigned loopback port and pass their health URL. Full-stack deployment must preserve SQLite data across container replacement and prove backup and restore behavior.
Release checks use a disposable VPS fixture for setup, exact image upload, deployment, health, status, logs, and rollback.
Extensions#
Full-stack projects include the versioned extension command. Add bundled auth, email, or uploads source with:
bun shi add auth
The command previews writes, stops on conflicts, records a named guide under agents/, and does not duplicate files when repeated. Auth and uploads need the full-stack database; uploads also needs auth installed first.
Deferred#
Cloudflare, Vercel, Fly.io, background jobs, payments, admin, and a public extension registry remain planned. They stay out until fixture projects can install, build, run, and deploy them without special cases.
Working server commands are documented in Server commands.