Ship by Sunday CLI
The Ship by Sunday CLI is the local-first version of the packet intake flow. It asks the same canonical pre-review questions that drive the web packet stages, stores one draft at the repository root, reports readiness with the same compiler logic as /review, and generates the same starter snapshot shape as the protected download route.
Clone the repository, run bun install, then launch the CLI from the repository root with either bun run sbs or the checked-in repo-local wrapper at ./bin/sbs. Both entrypoints share the same command parser, version source, and JSON envelopes. When you run bun run sbs in a real terminal, the CLI opens a bannered entry surface for the current repository instead of dumping raw help. The startup surface points you at resume, next --json, and review --json, while bun run sbs --help, bun run sbs help review, bun run sbs review --help, bun run sbs stage --help, bun run sbs --version, ./bin/sbs --version, and ./bin/sbs completion zsh stay clean and side-effect free. Interactive stage prompts also make :clear and :quit explicit so you can back out safely and resume later.
Use it when:
- you want to shape the packet from a terminal instead of the protected web UI
- you want to import or patch facts from another tool or agent
- you want a local starter snapshot without needing Clerk, Convex auth, or a browser session
- you want a repo-local launcher that does not depend on a registry install or package-manager shim
Where it stores state
The CLI keeps one active draft under:
.ship-by-sunday/draft.jsonThis is a canonical project-definition draft envelope, not a separate CLI-only format.
Core commands
bun run sbs init --fixture complete --json
bun run sbs schema --json
bun run sbs stages --json
bun run sbs fields --stage design --json
bun run sbs next --json
bun run sbs validate --json
bun run sbs set product.product_name "Ship by Sunday CLI" --json
bun run sbs append scope_in "Packet intake" --json
bun run sbs unset build-plan.domain --json
bun run sbs mutate --file ./tmp/mutations.json --json
bun run sbs --help
bun run sbs --version
bun run sbs version --json
bun run sbs completion zsh
bun run sbs completion bash
bun run sbs resume
bun run sbs stage <product|design|marketing|build-plan>
bun run sbs review [--stage build-plan] [--missing-only] [--json]
bun run sbs export --out ./.ship-by-sunday/export.json
bun run sbs export --out -
bun run sbs import --file ./tmp/sbs-cli-complete.json
cat ./tmp/build-plan-patch.json | bun run sbs apply --stage build-plan --file -
bun run sbs generate --out ./tmp/sbs-cli-repo --json
bun run sbs generate --out ./tmp/sbs-cli-repo.zip --zip --json
./bin/sbs --help
./bin/sbs --version
./bin/sbs completion zsh
./bin/sbs completion bashWhat each one does:
initcreates a fresh local draft without entering the interactive prompt flow. Use--fixture completewhen you want a seeded draft for QA, demos, or agent workflows. Use--forceto replace an existing local draft.schema,stages, andfieldslet an agent inspect the canonical packet contract instead of guessing from docs.nextreturns the next stage, next step, missing required fields, and a suggested command.validatereturns the full readiness and stage-status envelope without changing anything.set,unset,append, andremovelet an agent mutate the draft field-by-field without constructing patch JSON files.mutate --file <file|-> --jsonapplies a whole batch of operations atomically. If any operation is invalid, the draft is left unchanged.resumeauto-initializes a blank draft when none exists, then continues from the first incomplete stage.stage <id>revisits one explicit packet stage without changing the canonical stage order.review --jsonprints machine-readable readiness and missing-fact output.--stagenarrows the output to one stage.--missing-onlysuppresses already-ready stages in the human-readable view.exportwrites the current local draft to a JSON file.--out -prints the raw draft JSON to stdout for piping.importreplaces the local draft with a canonical complete definition, canonical draft, or facts-only JSON file.--file -reads JSON from stdin.applymerges a stage-scoped patch file into the draft and rejects keys that do not belong to that stage.--file -reads the patch from stdin.generaterequires a review-ready draft and an explicit--outpath. Directory mode creates a slugified repo folder inside the target path.--zipwrites the same snapshot as a zip archive.--forceallows overwrite.--jsonreturns structured machine-readable metadata about the generated artifact.
Install and Update
The supported install path is still the repository itself. Clone it, run bun install, and use either bun run sbs or ./bin/sbs from the repo root. The repo-local wrapper is the supported direct launcher; it is not a public-package shim and it does not require bunx, Homebrew, or a global install.
bun run sbs --version, ./bin/sbs --version, and bun run sbs version --json all report the same version field. ./bin/sbs completion bash and ./bin/sbs completion zsh print shell scripts to stdout so you can source them manually.
When you need an update, pull the repository and rerun bun install. Self-update is intentionally out of scope for this slice.
Unsupported For Now
- public registry distribution
bunx-based invocation- Homebrew packaging
- self-update or remote update commands
Path behavior
Run the CLI from the repository root.
User-supplied --file and --out paths are resolved relative to the repository root, not the CLI package directory. That means these work the way they look:
bun run sbs import --file ./tmp/sbs-cli-complete.json
bun run sbs generate --out ./tmp/sbs-cli-repoTypical workflow
If you want to work interactively:
bun run sbs resume
bun run sbs review
bun run sbs generate --out ./tmp/sbs-cli-repoIf you want to drive the flow from another tool:
bun run sbs init --fixture complete --json
bun run sbs schema --json
bun run sbs next --json
bun run sbs review --json
bun run sbs generate --out ./tmp/sbs-cli-repo.zip --zip --jsonIf you want to patch only one stage:
bun run sbs apply --stage marketing --file ./tmp/marketing-patch.json
bun run sbs reviewIf you want stdin/stdout-friendly agent workflows:
bun run sbs export --out -
cat ./tmp/build-plan-patch.json | bun run sbs apply --stage build-plan --file -
cat ./tmp/complete-definition.json | bun run sbs import --file -If you want field-level agent control without patch files:
bun run sbs set product.problem_statement "Founders need a local-first packet flow." --json
bun run sbs append scope_in "Local CLI intake" --json
bun run sbs remove scope_in "Local CLI intake" --json
bun run sbs unset build-plan.domain --jsonIf you want one atomic batch instead of one command per field:
cat ./tmp/mutations.json | bun run sbs mutate --file - --jsonAccepted mutation input shapes:
[
{
"op": "set",
"field": "product.product_name",
"value": "Ship by Sunday CLI"
},
{ "op": "append", "field": "scope_in", "value": "Local CLI intake" },
{ "op": "unset", "field": "build-plan.domain" }
]or:
{
"operations": [
{
"op": "set",
"field": "product.product_name",
"value": "Ship by Sunday CLI"
}
]
}JSON contract
When a command supports --json, stdout contains a stable success envelope:
{
"status": "ok",
"command": "next",
"version": "0.1.0"
}On failure, stderr contains a stable error envelope:
{
"status": "error",
"command": "generate",
"version": "0.1.0",
"error_code": "not_review_ready",
"message": "Draft is not review-ready."
}The CLI uses more specific non-zero exit codes for common automation failures such as invalid arguments, missing drafts, overwrite protection, and non-ready generation.
What it shares with the web flow
The CLI does not redefine the packet contract. It reuses:
- the canonical facts schema in
packages/packet-compiler/src/canonical-project-definition/schema.ts - the live stage grouping in
packages/packet-compiler/src/stages/stage-definitions.ts - readiness evaluation in
packages/packet-compiler/src/readiness/ - repo generation in
packages/packet-compiler/src/server.ts
That shared boundary matters because the CLI and the protected /review route should agree about what is missing, what is ready, and what the starter snapshot contains.
Current limits
- The CLI manages one local draft at a time.
- It is intentionally pre-review only. It does not cover post-download execution inputs.
domainandsupport_emailstay placeholder-friendly and do not block generation when the compiler contract leaves them optional.