Installation
Choose a route in the deployment matrix first. Local, managed NixOS, ordinary Docker, and the optional OCI cage have different credential and process boundaries. Policy can change which tools work.
Release availability
Nothing has been published to a package registry. There is no published Python package or prebuilt Cowboy image. This page is the maintained release availability statement; all installation routes below build from source.
Start with a checkout and Nix with flakes enabled:
git clone https://github.com/dmadisetti/cowboy.git
cd cowboy
Keep the revision and lock file used for a deployment. The commands below run from this checkout unless they explicitly refer to your host configuration.
Local evaluation
Build the CLI and the repository’s Zellij variant:
nix build .#get-cowboy --out-link /tmp/cowboy-cli
nix build --impure --expr '
let f = builtins.getFlake (toString ./.);
in (import f.inputs.nixpkgs {
system = builtins.currentSystem;
overlays = [ f.overlays.zellij ];
}).zellij' --out-link /tmp/cowboy-zellij
export PATH=/tmp/cowboy-cli/bin:/tmp/cowboy-zellij/bin:$PATH
read -rsp 'Anthropic API key: ' ANTHROPIC_API_KEY
export ANTHROPIC_API_KEY
cowboy --model anthropic:claude-opus-4-5-20251101
The Zellij overlay supplies the memory limit used by the harness. The key is in the launching environment. The CLI packages its harness WASM; a plain Python install from the checkout does not stage that artifact.
In Zellij, send:
Read README.md and summarize what this project does. Do not change files.
Expect tool activity and a model reply in the session, not a predetermined answer. File and shell tools run with your permissions. From another shell in the same environment, stop it with:
cowboy stop cowboy
For a local headless evaluation, build Montana and the component explicitly:
nix build .#montana --out-link /tmp/cowboy-montana
nix build .#agent-component-lite --out-link /tmp/cowboy-component
export MONTANA_BIN=/tmp/cowboy-montana/bin/montana
export MONTANA_WASM=/tmp/cowboy-component/share/cowboy/cowboy-agent.wasm
cowboy serve --model anthropic:claude-opus-4-5-20251101
This prints a Unix socket connection command. Connect to that socket and send one JSON line:
{"submit":"Say hello and describe your available tools."}
The socket emits display frames containing activity and the answer. Stop the
unnamed headless instance with cowboy stop agent. This path still holds real
keys and runs with your permissions; headless operation adds no confinement.
Managed NixOS
Use an existing Linux/x86-64 NixOS host configuration. Add Cowboy as a flake
input, import the Cowboy and Home Manager modules into that host’s module
list, and keep its lock file under version control. The fragment below assumes the host
already imports agenix and has an operator account named alice; substitute
your operator name. The encrypted key must be decryptable by this host.
# Add to the inputs of your host flake:
inputs.cowboy.url = "github:dmadisetti/cowboy";
# Include in the host's nixosSystem modules list:
modules = [
./configuration.nix
cowboy.nixosModules.default
cowboy.inputs.home-manager.nixosModules.home-manager
./cowboy-agent.nix
];
Save this module as cowboy-agent.nix beside the host flake:
{ lib, ... }:
{
programs.fish.enable = true;
services.cowboy.broker = "alice";
services.cowboy.agents.dev = {
enable = true;
user = "dev";
uid = 1338; # Choose an unused UID.
model = "anthropic:claude-opus-4-5-20251101";
daemon.enable = true;
daemon.expose = 4312;
};
age.secrets.anthropic-key = {
file = ./secrets/anthropic-key.age;
owner = "cowboy-proxy";
};
services.cowboy.secretsProxy.domainMappings = lib.mkForce {
"api.anthropic.com" = {
secretPath = "/run/agenix/anthropic-key";
headerName = "x-api-key";
};
};
}
The encrypted file is part of your host configuration; the plaintext key never belongs in Nix text or the store. Its runtime reference is the proxy mapping’s secret path. Restricting the mapping to this provider avoids provisioning unneeded provider and search credentials.
Build and activate from your host configuration directory, replacing HOST with its NixOS configuration name:
sudo nixos-rebuild switch --flake .#HOST
systemctl status cowboy-serve-dev --no-pager
cowboy connect 127.0.0.1:4312#/var/lib/cowboy/expose/dev.token
Run the connection command as the configured operator. It opens the Zellij
client to the managed agent. Send “Say hello and describe your available
tools.” Expect activity and a reply there; inspect service diagnostics with
journalctl -u cowboy-serve-dev. The localhost control token grants control,
including the ability to answer approval prompts. A read-only observer needs
the separate observer endpoint and token.
The daemon runs Montana directly under systemd as dev, with its per-agent
component, namespace, proxy, Sheepdog, and shared service envelope. It does not
invoke the OCI runtime. To leave the daemon stopped:
sudo systemctl stop cowboy-serve-dev
A socket quit is insufficient: the unit restarts automatically. Set
daemon.autostart = false and rebuild if it should remain off at boot.
Docker
Build on a Nix machine matching the target image architecture, then load the archive on the Docker host. The target host needs Docker, not Nix:
nix build .#docker-image --out-link /tmp/cowboy-image
docker load < /tmp/cowboy-image
docker run -it --name cowboy-eval \
-e XDG_DATA_HOME=/etc/cowboy/data \
-v cowboy-etc:/etc/cowboy \
-v cowboy-workspace:/opt/workspace \
cowboy:latest
For separate machines, transfer the image archive before loading it. On first
boot the wizard asks for provider, model, and key. It writes the key with mode
0600 into the configuration volume, then opens the setup agent in Zellij.
Tell it what work you want help with, your communication preferences, and when
it should ask before acting. It saves the agreed profile to
/opt/workspace/.cowboy/prompt.md; an otherwise empty workspace is normal.
Choosing a role such as calendar assistant does not authorize or configure a
calendar integration. Setup should state which capabilities work and which
still need access, while preserving existing workspace files.
The explicit data directory keeps session state in the named volume, including
on later starts. Tools run as container root with ordinary Docker isolation;
there is no managed credential proxy or Cowboy cage.
When the profile is saved, stop and resume from the Docker host. The normal agent loads that profile and resumes the conversation from persistent state:
docker stop cowboy-eval
docker start -ai cowboy-eval
Without a TTY or staged settings, a fresh image exits with “no configuration found.” For a settings-based headless service, the CLI can stage a bootstrap settings file and build a per-agent generation. That route is distinct from the interactive wizard. Its current launcher mounts config and workspace but does not set a persistent Montana data directory; account for that before relying on it for durable sessions. See daily operation.
Optional OCI cage
This specialized route requires Linux/x86-64, Docker, a source checkout, and a
registered Cowboy runtime with its imageless resolver. Follow the registration
instructions in crates/runtime/smoke.sh and the
OCI contract.
Registration changes Docker’s daemon configuration; it is not supplied by
installing the CLI.
Once the runtime is registered, prepare the Cowboy payload and the placeholder image, then launch from the checkout with the CLI available:
nix build .#cowboy-agent-seed --out-link /tmp/cowboy-seed
nix build .#cowboy-agent-rootfs --no-link
tar -C /tmp/cowboy-seed/rootfs -c . | docker import - cowboy-imageless:latest
read -rsp 'OpenRouter API key: ' OPENROUTER_API_KEY
export OPENROUTER_API_KEY
cowboy serve demo --sandbox cage --expose 4210
The companion currently injects only OpenRouter credentials; another provider’s key will not work here. It holds the real key and exposes egress through Unix sockets. Docker runs the payload with the Cowboy runtime and networking disabled; the runtime launches linked Montana under the bundle’s policy.
Use the printed cowboy connect command and send the same hello request.
Expect display frames in the client. The component and model come from the
seed configuration. Stop the cage and its companions with cowboy stop demo.
The companion Redis has no persistent volume; this is not the managed NixOS
service’s persistence contract.
Continue with First request and daily operation.