Quick start guide/How-to's

To create a new package using the template, use either BestieTemplate.generate or BestieTemplate.new_pkg_quick.

To apply a template to an existing package, use either BestieTemplate.apply.

In this page we have gathered short examples, focused on some use cases.

For a more in-depth guide, check the Full guide

Interactive/Wizard experience

using BestieTemplate: generate

root_dir = mktempdir()


pkg_destination = joinpath(root_dir, "NewPkg.jl")
generate(
    # :local or :online,
    pkg_destination, # full path to the package
    # Dict("Question" => Answer), # to manually set answers
    # defautls = true,
    # quiet = true,
    # use_latest = true,
)
# Answer a bunch of questions
/home/runner/work/BestieTemplate.jl/BestieTemplate.jl/docs/.CondaPkg/.pixi/envs/default/lib/python3.14/site-packages/copier/_vcs.py:381: ShallowCloneWarning: The repository '/home/runner/work/BestieTemplate.jl/BestieTemplate.jl' is a shallow clone, this might lead to unexpected failure or unusually high resource consumption.
  warn(
/home/runner/work/BestieTemplate.jl/BestieTemplate.jl/docs/.CondaPkg/.pixi/envs/default/lib/python3.14/site-packages/copier/_vcs.py:407: DirtyLocalWarning: Dirty template changes included automatically.
  warn(

Quick Tiny package

A minimalist package.

using BestieTemplate: new_pkg_quick

root_dir = mktempdir()

pkg_destination = joinpath(root_dir, "TinyPackage.jl")
package_owner = "JuliaBesties"
authors = "JuliaBesties maintainers"
new_pkg_quick(
    pkg_destination,
    package_owner,
    authors,
    :tiny,
)

# Resulting folder:
- TinyPackage.jl/
  - .copier-answers.yml
  - .gitignore
  - LICENSE
  - Project.toml
  - README.md
  - src/
    - TinyPackage.jl
  - test/
    - Project.toml
    - runtests.jl

Quick Light package

The common niceties: documentation, CI, .JuliaFormatter.toml and other config files that you might want to use (but won't affect you if you don't).

using BestieTemplate

pkg_destination = joinpath(root_dir, "LightPackage.jl")
package_owner = "JuliaBesties"
authors = "JuliaBesties maintainers"
new_pkg_quick(
    pkg_destination,
    package_owner,
    authors,
    :light,
)

# Resulting folder:
Everything from the level above plus:

- LightPackage.jl/
  - .JuliaFormatter.toml
  - .editorconfig
  - .lychee.toml
  - .markdownlint.json
  - .yamlfmt.yml
  - .yamllint.yml
  - codecov.yml
  - .github/
    - PULL_REQUEST_TEMPLATE.md
    - dependabot.yml
    - workflows/
      - Docs.yml
      - ReusableTest.yml
      - TagBot.yml
      - Test.yml
      - TestOnPRs.yml
  - docs/
    - Project.toml
    - make.jl
    - src/
      - 95-reference.md
      - index.md
  - test/
    - test-basic-test.jl

Quick Moderate package

Opinionated suggestions for more stable packages without sacrificing too much development speed.

using BestieTemplate

pkg_destination = joinpath(root_dir, "ModeratePackage.jl")
package_owner = "JuliaBesties"
authors = "JuliaBesties maintainers"
new_pkg_quick(
    pkg_destination,
    package_owner,
    authors,
    :moderate,
)

# Resulting folder:
Everything from the level above plus:

- ModeratePackage.jl/
  - .pre-commit-config.yaml
  - .github/
    - workflows/
      - Lint.yml

Quick Robust package

Opinionated selection to help with larger packages and more developers.

using BestieTemplate

pkg_destination = joinpath(root_dir, "RobustPackage.jl")
package_owner = "JuliaBesties"
authors = "JuliaBesties maintainers"
new_pkg_quick(
    pkg_destination,
    package_owner,
    authors,
    :robust,
)

# Resulting folder:
Everything from the level above plus:

- RobustPackage.jl/
  - .all-contributorsrc
  - CHANGELOG.md
  - CITATION.cff
  - CODE_OF_CONDUCT.md
  - .github/
    - ISSUE_TEMPLATE/
      - 10-bug-report.yml
      - 20-feature-request.yml
      - 30-usage.yml
      - 99-general.yml
      - config.yml
  - docs/
    - src/
      - 90-contributing.md
      - 91-developer.md

Apply to an existing package

Here is an example of applying the template to an existing package.

This is the existing package:

pkg_destination = joinpath(root_dir, "ExistingPackage.jl")
Dict{String, Any} with 3 entries:
  "PackageOwner" => "JuliaBesties"
  "Authors"      => "JuliaBesties maintainers"
  "AddPrecommit" => true

Now we apply the template.

using BestieTemplate: apply
apply(
    # :local or :online,
    pkg_destination, # full path to the package
    # Dict("Question" => Answer), # to manually set answers
    # defautls = true,
    # quiet = true,
    # use_latest = true,
)

# You will be asked questions. For instance, if we only select to add pre-commit, this would be the result:
- ExistingPackage.jl/
  - .JuliaFormatter.toml
  - .copier-answers.yml
  - .editorconfig
  - .gitignore
  - .lychee.toml
  - .markdownlint.json
  - .pre-commit-config.yaml
  - .yamlfmt.yml
  - .yamllint.yml
  - LICENSE
  - Project.toml
  - README.md
  - codecov.yml
  - .github/
    - PULL_REQUEST_TEMPLATE.md
    - dependabot.yml
    - workflows/
      - Docs.yml
      - ReusableTest.yml
      - TagBot.yml
      - Test.yml
      - TestOnPRs.yml
  - docs/
    - Project.toml
    - make.jl
    - src/
      - 95-reference.md
      - index.md
  - src/
    - ExistingPackage.jl
  - test/
    - Project.toml
    - runtests.jl
    - test-basic-test.jl

Change details with new_pkg_quick

For more details on the hidden options see the [Advanced options and non-interactive answers](@ref advanced_options section.

using BestieTemplate: new_pkg_quick

pkg_destination = joinpath(root_dir, "TinyPackage.jl")
package_owner = "JuliaBesties"
authors = "JuliaBesties maintainers"

# Explicitly setting options
extra_data = Dict(
    "JuliaMinVersion" => "1.0",   # From the essential questions that `:tiny` autocompletes
    "AddDocs" => true,            # From the :light strategy
    "AddLintCI" => true,          # From the :moderate strategy
    "AddAllcontributors" => true, # From the :robust strategy
    "AddPrecommitUpdateCI" => true, # From the hidden options
)
new_pkg_quick(
    pkg_destination,
    package_owner,
    authors,
    :tiny,
    extra_data,
)

# Resulting folder: (Notice the new files in comparison to :tiny
- TinyPackage.jl/
  - .all-contributorsrc
  - .copier-answers.yml
  - .gitignore
  - LICENSE
  - Project.toml
  - README.md
  - .github/
    - workflows/
      - Lint.yml
      - PreCommitUpdate.yml
  - docs/
    - Project.toml
    - make.jl
    - src/
      - 95-reference.md
      - index.md
  - src/
    - TinyPackage.jl
  - test/
    - Project.toml
    - runtests.jl

Adding features directly via bestie CLI

If you only want one or two files from the template — a CHANGELOG.md, a dependabot.yml, a pre-commit config — without installing Julia or going through the full apply/update flow, use the experimental bestie-template Python package. It only needs uv on the PATH, no install step required:

uvx --from bestie-template bestie list-features
uvx --from bestie-template bestie add-feature changelog,dependabot path/to/MyPackage.jl

(--from bestie-template is needed because the PyPI package is named bestie-template, while the command it installs is bestie.)

list-features prints every feature bestie can add, along with the answers each one needs and the files it writes; pass --json for a machine-readable version. add-feature then applies one or more features (comma-separated, no spaces) to the package at the given path — each feature writes only the files it owns, leaving the rest of the package untouched.

A few things worth knowing before running it:

  • It overwrites without asking. A feature replaces its own files outright — no diff, no conflict prompt, no backup. Commit or stash first, so git diff/git checkout remains your way to undo it.
  • Some features need existing answers. A few features (e.g. lint_action) read .copier-answers.yml to decide what to render, and refuse to run without it. Check list-features --json for an _explicit variant first — it takes the same information as -d KEY=VALUE flags instead.
  • Version pinning. --ref vX.Y.Z pins the template version used to render the feature; omit it to use the latest release, or pass --ref main for a feature that has not shipped in a release yet.

For AI coding agents, this same workflow is packaged as the bestie-features skill, which teaches an agent the feature names, how to resolve the answers each one needs, and the follow-up work some features require. Install it with npx skills add JuliaBesties/BestieTemplate.jl.

Adding a single feature with add_feature

The same idea is available from Julia, through BestieTemplate.add_feature: apply one named slice of the template — say, just the changelog — to an existing package, without going through the full apply/update flow.

Here, AnswerPackage.jl already has a .copier-answers.yml (from new_pkg_quick/generate/apply), so add_feature reads the answers it needs — PackageOwner, PackageName — straight from it:

using BestieTemplate: add_feature

pkg_destination = joinpath(root_dir, "AnswerPackage.jl")

add_feature(
    :changelog,
    pkg_destination,
)

# Resulting folder: (Notice the new CHANGELOG.md)
- AnswerPackage.jl/
  - .copier-answers.yml
  - .gitignore
  - CHANGELOG.md
  - LICENSE
  - Project.toml
  - README.md
  - src/
    - AnswerPackage.jl
  - test/
    - Project.toml
    - runtests.jl

On a package with no .copier-answers.yml, add_feature still guesses what it can from the package itself — PackageName, Authors and JuliaMinVersion from Project.toml, PackageOwner from docs/make.jl if present, indentation from .JuliaFormatter.toml — and only complains about what's left. For a :tiny package, which has no docs/make.jl, that's PackageOwner:

julia> add_feature(:changelog, pkg_destination)
ERROR: Cannot determine required fields: PackageOwner.
      Pass them via the `data` argument or run `BestieTemplate.apply` first.

Pass whatever it names through the data argument: add_feature(:changelog, pkg_destination, Dict("PackageOwner" => "JuliaBesties")).

As with add-feature from the CLI, this overwrites the feature's files outright, and a git repository is your only way to undo it. See the BestieTemplate.add_feature docstring for the full list of features and their required answers, and the Full guide for how the recorded template version is affected.