Your AI chat gets a real computer of its own.

Files, a browser, and somewhere to run code. It can build things, look stuff up online and keep your work as you go. Turn a chat you already had into a bot that does the job again tomorrow.

claude mcp add husk -- npx -y @husk-ai/mcp

One command. Nothing else to edit.

Free. No account, no card. Apache-2.0 · works with Claude Code, Cursor, Zed, or anything speaking MCP

An AI chat panel with a short exchange in it, wired by a cable to a small computer below, whose port is lit.

Keep scrolling
windows laptop · no docker daemon · no api key
$ husk up demo --provider local
✓ demo is up
  provider   local  (WSL2 (Ubuntu))
  isolation  guardrails only — not a sandbox
  workdir    /work

$ husk exec demo -- 'uname -sr; echo hello > /work/note.txt; cat /work/note.txt'
Linux 6.18.33.2-microsoft-standard-WSL2
hello

$ husk exec demo -- 'sudo rm -rf /'
error refused: privilege escalation
hint:  add a pattern to guardrails.allowCommands in husk.yaml if this is intentional

That ran on a Windows laptop with no Docker and no API key. The local provider found WSL2 and gave it a real kernel and a real /work. Then it refused a command that would not have been recoverable, and said what to change if the refusal was wrong.

before and after one line

youclaude mcp add husk -- npx -y @husk-ai/mcp

the conversation now has

  • shellrun a command, get stdout, stderr and an exit code
  • read_fileread a path inside the workspace
  • write_filewrite a path inside the workspace
  • expose_portpublish a port the agent started listening on
$ husk exec demo -- 'uname -sr; echo hello > /work/note.txt; cat /work/note.txt'Linux 6.18.33.2-microsoft-standard-WSL2hello

a computer, for the rest of the conversation

claude mcp add husk -- npx -y @husk-ai/mcp

what it does

Husk does two things.

One binary. The first job hands a machine to an agent that does not have one. The second takes a conversation you already finished and keeps it running.

It gives an agent a computer.

A computer is a disposable Linux machine: shell, filesystem, ports, snapshots. Nothing is spun up until a tool actually needs one, and a stable key maps a conversation to the same machine, so its files survive across tool calls without you tracking ids.

A cold docker version takes about 800 ms, so provider probes are cached for 30 seconds. An agent that creates four machines in a row pays that once.

husk doctor · first run
$ npx -y @husk-ai/cli

husk 0.1.0 · first run · ~/.husk created

computer providers
  docker      unavailable   the daemon is not reachable
  podman      not found
  local       ready         guarded working directory
                          ~/.husk/workspaces -- guardrails, not a sandbox

model providers
  ollama      ready         gemma3, qwen2.5-coder
  anthropic   no key        set ANTHROPIC_API_KEY

selected      local + ollama/gemma3       free, on this machine, no account

no telemetry. nothing left this machine.
chat → husk.yaml → service
$ husk import                            # find your transcripts
$ husk distill tr_01hxyz --out triage.yaml   # chat -> agent spec
$ husk run triage.yaml "check the build"
$ husk serve                             # http, discord, cron, cli

It turns a chat you already had into a bot.

Husk reads a Claude Code, ChatGPT or Cursor transcript, walks parentUuid back from the last leaf to get the conversation as it actually ran rather than every dead end, and writes a husk.yaml you can diff.

The distiller runs with no API key. It mines the instructions you kept repeating, the answers you did not correct, and the tools you actually used, then reports what it could not determine instead of inventing it.

the whole install

One line gives your client a machine.

claude mcp add husk -- npx -y @husk-ai/mcp

One command. Nothing else to edit.

In Claude Code and Codex there is no second step and no config file to edit. Cursor, Zed and Antigravity have no add command of their own, so those get the block to paste and the path to paste it into — the tab above switches between them. Either way the client gets twenty tools against a real Linux machine — a shell, the filesystem, ports, and a browser — and that filesystem persists for the rest of the conversation.

The first tool result tells the model how isolated it is, because a model that believes it is contained when it is not will take risks it otherwise would not.

  • shellrun a command, get stdout, stderr and an exit code
  • read_fileread a path inside the workspace
  • write_filewrite a path inside the workspace
  • edit_filereplace an exact string, and fail loudly if it is missing or ambiguous
  • list_dirlist a directory
  • expose_portpublish a port the agent started listening on
  • computer_infokernel, cpus, memory, disk and network, so the model stops probing
  • browser_gotoopen a URL in a real Chromium and return the rendered text
  • browser_snapshotlist everything readable or clickable, each with a ref
  • browser_clickclick an element the snapshot named
  • browser_typetype into a field
  • browser_screenshottake a PNG, for checking a layout or showing a human

13 in all. A real Chromium inside the computer, driven by structured page text rather than pixels — which is why an agent can use it without seeing.

after the one line

Three things to ask it first.

The install is one line and then nothing tells you what changed. These are the three that show you the computer is real, in the order that makes the point fastest.

  1. What kernel are you on?

    It runs uname -sr in the machine and reads it back. The answer is Linux on a computer that did not exist a second ago, and it is not one the model could have guessed.

  2. Write a note to /work/note.txt, then read it back next turn.

    The filesystem persists for the rest of the conversation. A stable key maps the chat to the same machine, so nothing is tracked by you.

  3. Start a web server and give me the URL.

    expose_port publishes the port it started listening on and hands back a URL you can open. That is the moment the computer stops being an abstraction.

containment

husk doctor tells you which one you have.

Two of the five providers are not isolated in any meaningful sense. Availability.isolated is on the provider interface so that no part of this product ever has to be vague about which two.

Isolation, cost and the mechanism behind each claim. Never the word “secure” on its own.
providerisolationmechanismcostwhen it wins
dockerkernelnamespaces, cgroups, seccomp, --cap-drop ALL, read-only root, uid 1000free, localthe default when the daemon is up
podmankernelthe same boundary, rootlessfree, localLinux without a Docker daemon
localguardrails onlypath jail through realpath, scrubbed credentials, deny list, output caps, process-tree killfree, localnothing else is available
sshwhatever the remote isthe box you pointed it at — Husk cannot know and does not guessfree if you own the boxan Oracle Always Free ARM instance, a Pi, a VPS
flymicroVMa Firecracker machine, not a container on your kernelmeteredbursty parallel work, no local resources

Husk never silently substitutes a weaker provider for the one you asked for. Asking for --provider docker with the daemon down is an error, not a downgrade.

provider
docker
isolation
kernel
cost
free, local
when it wins
the default when the daemon is up

namespaces, cgroups, seccomp, --cap-drop ALL, read-only root, uid 1000. Drawn without WebGL — the shape carries the same reading.

guardrails, not a sandboxThe local provider pins the working directory, resolves every path through realpath and refuses escapes, strips credential-shaped environment variables, caps output, and kills the process tree on timeout. That stops accidents. It will not stop an adversary, and a prompt-injected model is closer to an adversary than to an accident.

the unit of value

What comes out is a file you can read.

Deliberate key order, block scalars, and a provenance header naming the transcript it came from. The file is optimised for review rather than for machines, because the first thing you will do with it is disagree with a line and change it.

Distil one, edit it, then run it on the CLI or serve it over HTTP, Discord, Slack or cron. The same file runs against Opus or against a local Gemma by changing one word.

triage.yaml
# Distilled from a Claude Code session where I kept asking the same
# questions about red builds. Most of the persona is text I had already
# typed into the chat four separate times.
apiVersion: husk/v1
name: ci-triage
model: sonnet
# Falls through to a local model rather than failing when the key is
# rate limited.
fallbackModels: [flash, gemma]

persona: |
  You triage CI failures for a TypeScript monorepo.

  Always read the failing job's log before forming an opinion. Quote the
  first line that actually failed -- not the last line, which is usually
  the runner giving up.

  Never rerun a job more than once. If it fails twice the same way, it is
  not a flake.

tools: [computer, files]

computer:
  flavor: node
  network:
    mode: egress
    allow: ['*.github.com']
  idleTimeoutSec: 600

limits: { maxSteps: 24, maxCostUsd: 0.25 }

triggers:
  - { type: http }
  - { type: cron, schedule: '*/15 * * * *', prompt: 'any red builds?' }

cost

The free path is the same path everything else is built on.

The local provider is the primitive. Docker, Podman, SSH and Fly are plugins behind the same interface, which means there is no code path in Husk that requires an account, a card or a network connection. Nothing is gated, nothing expires, and there is no edition of this product you are not already using.

There is no telemetry either. Not off by default — absent. No analytics, no crash reporter, no phone-home; the only network calls Husk makes are to the model provider you configured and to a registry when you pull an image. You can check that claim the same way we do, by reading the repository.

What a hosted tier would have to add before it was worth charging for.

  • no accountnothing to sign up for, nothing to log in to
  • no keyOllama runs gemma, qwen or llama on your machine for nothing
  • no Dockerthe local provider works without it, and says what you gave up
  • no telemetryabsent from the codebase, not disabled by a flag
  • Apache-2.0fork it, ship it, run it inside your company