rototo
DocsReference
Reference

Package Sources

Every time you run a rototo command, or load config from an app, the very first question is the same: where is the package? That answer is a package source - a short string that tells rototo where to go and get your config.

The nice part is that it's one string, and it works the same everywhere. The app-config you type after rototo lint is the same thing you put in ROTOTO_PACKAGE_SOURCE for your running service, and the same thing you hand to Package.load(...) in code. Learn it once and you're done.

This page walks through every shape that string can take.

The shortest one: a folder on your machine

Most of the time, especially while you're editing, the package is just a folder sitting on your disk. So the source is just the path to that folder:

rototo lint app-config
rototo lint ./packages/checkout
rototo lint /home/me/work/runtime-config

Relative or absolute, both are fine. No prefix, no ceremony - if it looks like a path, rototo treats it as a path.

And if you don't pass anything at all, rototo is helpful about it: it looks in the current folder, then the one above it, and so on, until it finds a rototo-package.toml. So when you're already standing inside your package, you can just say:

rototo lint

If you ever want to be explicit that it's a local path - say, in a script where you'd rather not leave it to guessing - you can spell it out with file://:

rototo lint file:///home/me/work/runtime-config

It means exactly the same thing as the plain path. One small catch: the file:// form is just a folder, so it doesn't take any of the #... extras described below. If you find yourself wanting those, you probably want a git source instead.

Loading straight from a git repo

Here's where it gets useful. Your config lives in git - that's the whole point - so you can point rototo straight at the repo without cloning it yourself first. You do that by sticking git+ in front of the repo URL:

# over HTTPS
rototo lint git+https://github.com/acme/runtime-config.git

# over SSH
rototo lint git+ssh://git@github.com/acme/runtime-config.git

# even a local bare repo
rototo lint git+file:///srv/git/runtime-config.git

rototo fetches the repo into a temporary spot, reads the package, and cleans up after itself. You don't manage the checkout.

Two things you'll almost always want to add: which version and which folder. That's what the part after the # is for.

The bit after the #: version and folder

A git source can carry two extra details, written as #ref:subdir:

Put together:

rototo lint git+https://github.com/acme/runtime-config.git#main:packages/checkout

Read that as: the runtime-config repo, on main, and the package is in packages/checkout.

You don't have to supply both. The colon is the divider, so:

A quick word on which ref to pick, because it changes how things behave later:

That last point matters for refreshing services: a moving ref is how config reaches a running fleet without redeploying; a pinned ref is how you guarantee an exact, reproducible build.

Loading a packaged-up archive over HTTPS

Pulling from git is great for small setups, but once you've got a real fleet, having every instance clone from GitHub on a schedule gets fragile - now your config depends on GitHub being up and on fetch behaving at scale. So for production, the usual move is to pack the package into a single .tar.gz file, drop it on an object store behind a CDN, and load that:

rototo lint https://config.acme.com/rototo/checkout/prod/current.tar.gz

(You build that archive with rototo package, which writes a deterministic tarball you can upload.)

An archive is already a self-contained, fixed thing, so there's no "ref" to pick

rototo lint https://config.acme.com/rototo/checkout/prod/current.tar.gz#:packages/checkout

Because an archive is just a file at a URL, the URL is what decides whether it moves or stays put:

One thing rototo won't do: plain http://

You can load over https://, but not plain http://. Same goes for git: git+https:// and git+ssh:// are fine, git+http:// is not. This isn't an oversight - config is exactly the kind of thing you don't want a network snoop or man-in-the-middle messing with, so the unencrypted forms are turned off on purpose. If you try one, rototo tells you to use https:// instead.

Private sources need a token

If your repo or archive is private, rototo needs a credential to fetch it. It uses a bearer token, and there are two ways to hand it over:

# as a flag
rototo lint git+https://github.com/acme/private-config.git --package-token "$TOKEN"

# or as an environment variable
ROTOTO_PACKAGE_TOKEN="$TOKEN" rototo lint git+https://github.com/acme/private-config.git

The environment variable is the friendlier choice for CI and for running services, since you set it once and forget it. The same token flows through to private HTTPS archives, too.

One habit worth keeping: when CI checks that production can really load the released package, use the same authenticated source production will use. That way you find out about a permissions problem in CI, not at 2am.

When one package builds on another

A package can stand on top of other packages - shared defaults, a common set of qualifiers, that sort of thing. It does that by listing other sources in its rototo-package.toml, and here's the part that matters for this page: those parent sources use the exact same grammar as everything above. A parent can be a local folder, a git repo with #ref:subdir, or an HTTPS archive.

Relative paths in that list are resolved against the package doing the extending, so a package and the parents it leans on can travel together. The mechanics of how the layers combine live in the package format reference; the only thing to remember here is that there's nothing new to learn about the sources themselves.

The whole grammar on one page

If you just want the cheat sheet:

You want to load…Write it like this
A folder on diskapp-config, ./pkg, /abs/path
Nearest package above you(omit the source entirely)
A folder, spelled outfile:///abs/path
A git repogit+https://…, git+ssh://…, git+file://…
A git repo, specific versiongit+https://…#main
A git repo, version + foldergit+https://…#main:packages/checkout
A git repo, folder onlygit+https://…#:packages/checkout
An HTTPS archivehttps://…/current.tar.gz
An HTTPS archive, folder insidehttps://…/current.tar.gz#:packages/checkout

And the things rototo will refuse: plain http://, git+http://, and a #... fragment on a file:// source.