Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.