Reference
Starter Packs
How explicit ota init --pack ... works, when to use each pack, and what the built-in packs really seed.
Recommended next
When to use this page
Use this page when the question is not whether ota init exists, but which explicit starter pack should seed the first draft.
Starter packs keep the pack-led path explicit and review-first. They do not replace detector-led init, and they do not silently switch based on repo signals.
- use plain
ota init --dry-runwhen ota should shape the first draft from repo signals - use
ota init --packswhen you want to compare the built-in conventional starters first - use
ota init --pack <name> --dry-runwhen you want one explicit starter path you will review before writing - keep
--packauthoritative; advisories exist to warn, not to auto-switch the chosen pack
Review-first flow
The safe path is compare, preview, then write.
Start with the catalog when you are choosing a pack. Start with detector-led init when you want ota to infer the first draft instead.
Detector-led preview now also calls out the Agent boundary outcome directly, so a missing agent block is explained as Inferred, Partially inferred, or Omitted instead of being left implicit in the YAML.
ota init --packsota init --pack node --dry-runota init --pack python --dry-runota init --pack ruby --dry-runota init --pack go --dry-runota init --pack rust --dry-runota init --pack dotnet --dry-runota init --pack php-composer --dry-runota init --pack java-maven --dry-runota init --pack java-gradle --dry-runota init --dry-runota initHow to compare packs
Do not choose by language label alone.
Compare the starter by the exact loop it seeds, the few conventional knobs it allows, and the boundary it deliberately leaves for review.
- seeded loop: start with the pack whose setup, build, dev, or test path already matches the repo's normal first draft
- explicit knobs: use Node or Python pack knobs only when the package-manager or test-runner boundary is real and known up front
- does-not-infer boundary: prefer the pack whose deliberate non-goals still leave the least repo-specific editing behind
- when two packs are plausible, preview both with
--dry-runinstead of stretching one pack past its declared boundary
Available packs
These are the built-in conventional starters today.
Choose the pack whose execution boundary already matches the repo instead of picking the closest language label and hoping the rest works out later.
node
Seeds toolchain-owned Node (toolchains.node) plus setup, dev, and test around one explicit package manager. Knob: --package-manager npm|pnpm|yarn|bun. Does not infer custom script names or package manager unless you choose it.
Example
python
Seeds toolchain-owned Python (toolchains.python via uv), uv-based setup (uv sync), and uv-run test. Knob: --test-runner pytest|unittest. Does not infer repo-specific dependency-group layout or repo-specific test layout for you.
Example
ruby
Seeds toolchain-owned Ruby (toolchains.ruby) plus Bundler setup (bundle install) and test (bundle exec rake test), and seeds Bundler version governance under toolchains.ruby.package_managers.bundler. No starter knobs. Does not infer framework-specific server commands or repo-specific test wrappers/flags.
Example
go
Seeds go mod download, go build ./..., and go test ./.... No starter knobs. Does not infer workspace layout, code generation, or custom build flags.
Example
rust
Seeds toolchain-owned Rust (toolchains.rust) plus Cargo fetch, build, and test. No starter knobs. Does not infer workspace members, feature flags, or custom cargo aliases.
Example
dotnet
Seeds dotnet restore, dotnet build, and dotnet test. No starter knobs. Does not infer solution-specific target selection, test filtering, or custom dotnet CLI flags.
Example
php-composer
Seeds composer install and reuses composer run test only when the repo already declares scripts.test. No starter knobs. Does not infer framework-specific entrypoints, web server commands, or another PHP test wrapper for you.
Example
java-maven
Seeds setup, build, and test for Maven. Wrapper-aware: prefers ./mvnw when present, otherwise seeds the global Maven prerequisite. Does not infer multi-module reactor details or plugin-specific goals.
Example
java-gradle
Seeds setup, build, and test for Gradle. Wrapper-aware: prefers ./gradlew when present, otherwise seeds the global Gradle prerequisite. Does not infer multi-project build logic or custom Gradle task structure.
Example
Pack-specific knobs
Only add a knob when the boundary is truly conventional. The goal is explicit starter control, not open-ended templating.
- the Node pack keeps
toolchains.nodeownership and changes package-manager lane details from the selected manager - the Python pack keeps
toolchains.pythonownership and changes the seeded uv-run test task and description to the selected test runner - packs that do not expose knobs stay fixed on one explicit conventional path
ota init --pack node --package-manager npm --dry-runota init --pack node --package-manager pnpm --dry-runota init --pack node --package-manager yarn --dry-runota init --pack node --package-manager bun --dry-runota init --pack python --test-runner pytest --dry-runota init --pack python --test-runner unittest --dry-runWhat packs do not infer
Starter packs are explicit templates, not hidden repo-specific synthesis.
The catalog now says this directly in both text and JSON so humans and automation can see where review and follow-up editing still matter.
- Node does not infer the repo's package manager unless
--package-managersays so, and it does not absorb custom script names beyond the seeded setup/dev/test loop - Python stays uv-managed in the starter and does not infer repo-specific dependency-group layout or repo-specific test layout beyond the selected test runner
- Go, Rust, and Dotnet stay on their conventional module, Cargo, or restore/build/test loop; they do not infer workspace structure, code generation, feature flags, solution-level target selection, or custom CLI aliases
- Php-composer stays on
composer installand only reusesscripts.testwhen it already exists; it does not invent a framework-specific PHP test entrypoint for you - Java Maven and Gradle packs stay on the standard wrapper-or-global build/test path; they do not infer multi-module or multi-project build logic, plugin goals, or org-specific bootstrap scripts
Java wrapper behavior
The Java packs are wrapper-aware on purpose.
A Maven or Gradle repo that already ships its own wrapper should not be forced onto a global host tool assumption just because the pack is explicit.
- if
mvnwexists,java-mavenuses./mvnwcommands and does not seed the globalmaventool ormaven-installedcheck - if
gradlewexists,java-gradleuses./gradlewcommands and does not seed the globalgradletool orgradle-installedcheck - if the wrapper is absent, the starter seeds the global tool requirement and matching precondition check because the repo has no wrapper-owned execution path yet
- the explicit dry-run preview is the authoritative view once ota has seen the repo, because wrapper presence changes the final Java starter details
Advisory mismatch behavior
Explicit pack choice stays authoritative, but ota can still tell you when the repo signals point somewhere else.
The advisory path is read-only. It does not auto-switch packs and it does not merge detector output into the chosen pack.
- advisories appear only when one other pack is the clear stronger match from distinct repo signals
- incidental signals on the selected pack do not suppress a stronger advisory anymore
- human text output now keeps the pack choice explicit while adding
Why, weightedSignals,Selected signals,Strength,Gap, andNextrows for the review step - detection failures do not block
ota init --pack ...; the explicit starter path still previews or writes
ota init --pack python --dry-run{ pack: "python", pack_advisory: { selected_pack: "python", suggested_pack: "node", selected_pack_score: 0, suggested_pack_score: 3, score_gap: 3, signals: ["package.json"], signal_details: [ { signal: "package.json", weight: 3 } ], selected_signal_details: [], next: "ota init --pack node --dry-run ." }}JSON surfaces
Use JSON when automation or hosted tooling needs the same starter-pack truth the CLI is showing to a human.
mode: "catalog"pluspackscomes fromota init --packs --json- each catalog entry includes identity fields, the exact command to run, safe next steps, explicit inference boundaries, and the seeded contract surface
packappears onota init --jsonwhen an explicit pack seeded the starter contractpack_optionsappears when a selected Node package manager or Python test runner changes the seeded starterpack_advisoryappears only when strong detected repo signals disagree with the chosen pack without overriding it, and now includes score gap plus weighted-signal detail fields for both the suggested and selected pack
What this page is not
- not a new top-level command surface separate from
ota init - not detector-led init with prettier copy
- not hidden auto-detection that silently switches your chosen pack
- not a template marketplace or arbitrary starter generator