Sharing cells
Publish a cell definition, and take one cell out of someone else's repository.
A cell definition is a cell.yaml and, usually, a Containerfile beside it. Neither holds a credential, so both are meant to be published: what a cell reaches, what it is built from and which secrets it expects are exactly the things worth reading before you run one.
solitary clone is the other half of that. It takes one cell out of a repository, so a repository can show all of yours and someone else can take the two they want.
This repository is one: example cells are two complete definitions to clone.
Taking one
solitary clone balakin/nvim-cell # a repository that is one cell
solitary clone balakin/cells/claude # one cell out of a catalogue
solitary clone balakin/cells # a catalogue, unnamed: lists what is in itowner/repo is GitHub shorthand. Other accepted forms are an HTTPS URL, an SSH remote, or a local directory — and the cell inside it is named with a #fragment:
solitary clone https://gitlab.com/me/cells.git#rust
solitary clone git@github.com:me/cells.git#rust
solitary clone ../my-cells#claudeFetching is git clone, so your existing credentials, SSH agent and rewriting rules apply and a private repository needs no new configuration.
Two layouts, no flag
A cell.yaml at the repository's root means the repository is one cell, the shape a dotfiles repository has; it installs under the repository's own name. No root cell.yaml means the directories inside it are the cells, and naming one is how you pick:
$ solitary clone balakin/cells
github.com/balakin/cells holds 3 cells:
claude
go
rust
Take one with: solitary clone github.com/balakin/cells#claudeYou see what it asks for first
A cell names the secrets it wants, and running it hands them to an image someone else chose. So the definition is shown and the install is asked for:
Cell "claude" from github.com/balakin/cells
Claude Code with neovim and tmux, on a network that reaches anthropic,
github and npm and nothing else.
image build:./Containerfile
machine 4 cpus · 8GiB · 40GiB
base ubuntu-lts
command:
sleep infinity
user image default
resolvers 1.1.1.1, 8.8.8.8
secrets CLAUDE_API_KEY, GITHUB_TOKEN (optional)
set them with: solitary secrets claude
ports all reach host localhost
network 2 allowed
github.com
api.anthropic.com
Install it? [y/N]The sentence under the name is the definition's own description:, which is the one line here written by whoever published the cell. Write one for yours: it is what someone reads before they decide.
Nothing has started either way — up does that, afterwards. --yes skips the question and --list shows this without installing anything.
Install under your own name with --as:
solitary clone balakin/cells/claude --as workWhat is refused
A repository is written by someone else and its file names become paths on your machine, so what may be copied is decided here rather than by whatever the repository happens to contain. Anything refused is named rather than quietly skipped:
.env,*.envandvpn.confnever arrive. Those are the names that carry credentials, and a credential belongs to whoever runs a cell rather than to the cell. One in a published repository is a mistake in it, or an attempt to seed your machine with someone else's key.- A symlink is refused, at any depth. It is the one entry whose target need not be inside the repository.
.gitis left behind. A cloned cell is a copy, with no link back to where it came from.- What lands is written the way
initwrites a cell:0600, or0700for something the repository marked executable — a build context runs inside the machine, never here.
The definition is then parsed before it becomes a cell, so a broken one is refused rather than half-installed.
Updating one
Clone the same source again with --force:
solitary clone balakin/cells/claude --forceThat replaces the files the repository provides and leaves everything else in the cell's directory alone — your .env, your vpn.conf, anything you added. So an update keeps you authenticated, and solitary up claude afterwards is the whole of applying it.
Without --force, an existing cell of that name is refused before anything is fetched, naming both ways out: --as for a second copy, --force to replace this one.
Publishing yours
A repository of cells is one directory per cell, each holding its cell.yaml and whatever it builds from. Keep the credentials out of it:
# in a repo of cell definitions
.env
vpn.confA network.vpn: line is fine to publish — the file it names is deliberately absent, and whoever clones the cell supplies their own, from any provider, with no edit to cell.yaml. clone says so when it shows the definition.
The review also shows the full vm.provision script under a VM-root heading, before you install the definition. It runs before the network policy is loaded. Terminal control characters are displayed visibly. A build or VPN path outside the cell directory is refused, as are executable WireGuard hooks. A configured VPN file is withheld even with a custom filename. Build credential exclusions also apply when cloning. Git helper transports such as ext:: are refused, and HTTPS, SSH and local-file transports are the only ones enabled for the clone.