---
title: "Self-host Kanzo, one kanban board for you and your agents"
description: "Run Kanzo on an exe.dev VM: one private kanban board that you use in the browser and Claude Code, Codex and Shelley use over MCP, from any VM or laptop."
url: https://exe.dev/deploy/kanzo
category: "AI agents"
updated: 2026-11-02
---

# Self-host Kanzo, one kanban board for you and your agents

One kanban board, behind your exe.dev login, that all your agents work from.

- **Software:** Kanzo (https://github.com/emanuele-em/kanzo)
- **Source:** https://github.com/emanuele-em/kanzo
- **License:** AGPL-3.0
- **Time:** 5 minutes
- **Example VM name:** `my-kanzo` (yours will differ; on the VM, `hostname` prints it)
- **Machine-readable:** https://exe.dev/deploy/kanzo/manifest.json

## What you get

- Kanzo 0.3 at `https://my-kanzo.exe.xyz/`, behind your exe.dev login, restarted on failure and after a reboot.
- MCP at `https://my-kanzo.exe.xyz/mcp` for Claude Code, Codex, Shelley and other agents, with an exe.dev VM token.
- The board in `~/kanzo`, backed up nightly to `~/backups`, with a restore checked in a scratch directory.

Running on the VM:

- **Kanzo 0.3**: one binary in `~/.cargo/bin`: the board, its API and MCP at `/mcp`, as a systemd user service, port 4242, data in `~/kanzo`
- **nginx**: hands Kanzo the exe.dev proxy's requests as local ones, refusing other sites' pages, port 8000
- **Nightly backup**: a systemd timer; keeps two weeks, data in `~/backups`

How it is reached:

- https://my-kanzo.exe.xyz/ (private): the board, behind your exe.dev login
- https://my-kanzo.exe.xyz/mcp (private): MCP for agents anywhere, with a VM token
- https://kanzo.int.exe.xyz/mcp (private): the same, for agents on your other VMs, with no token on them (VM-to-VM integration)

## Deploy with Shelley

Open https://exe.dev/new?prompt=Set%20up%20Kanzo%20on%20this%20VM%20by%20following%20the%20exe.dev%20recipe%20at%20https%3A%2F%2Fexe.dev%2Fdeploy%2Fkanzo.md%20from%20top%20to%20bottom.%0A%0AThe%20recipe%27s%20example%20VM%20name%20is%20my-kanzo.%20This%20VM%27s%20name%20is%20the%20output%20of%20%60hostname%60%3A%20use%20it%20wherever%20the%20recipe%20writes%20my-kanzo.%20Skip%20the%20step%20that%20creates%20the%20VM%3B%20you%20are%20on%20it.%0A%0AYou%20are%20done%20when%20all%20of%20these%20are%20true.%20Check%20each%20one%20yourself%3A%0A-%20Kanzo%200.3%20at%20%60https%3A%2F%2Fmy-kanzo.exe.xyz%2F%60%2C%20behind%20your%20exe.dev%20login%2C%20restarted%20on%20failure%20and%20after%20a%20reboot.%0A-%20MCP%20at%20%60https%3A%2F%2Fmy-kanzo.exe.xyz%2Fmcp%60%20for%20Claude%20Code%2C%20Codex%2C%20Shelley%20and%20other%20agents%2C%20with%20an%20exe.dev%20VM%20token.%0A-%20The%20board%20in%20%60~%2Fkanzo%60%2C%20backed%20up%20nightly%20to%20%60~%2Fbackups%60%2C%20with%20a%20restore%20checked%20in%20a%20scratch%20directory.%0A%0ARead%20the%20whole%20recipe%2C%20closed%20details%20included%2C%20and%20follow%20%22Set%20up%20by%0Ahand%22%20in%20order%2C%20skipping%20VM%20creation%3B%20the%20walkthrough%20above%20it%20is%20for%0Athe%20owner.%20Never%20make%20the%20VM%20public%20or%20turn%20on%20Kanzo%27s%20%22Share%20this%0Aboard%22%3A%20Kanzo%20has%20no%20logins%2C%20so%20exe.dev%27s%20proxy%20is%20its%20only%20lock.%20On%20an%0Aexisting%20VM%2C%20ask%20before%20replacing%20anything%20on%20port%208000.%20The%20VM%20can%27t%0Areach%20its%20own%20https%3A%2F%2F%3Cvm%3E.exe.xyz%2C%20so%20checks%20use%20localhost%20with%20the%0AHost%20header%20as%20written.%20Delete%20the%20project%20you%20create%20while%20checking.%0ADon%27t%20reboot%20or%20restore%20over%20live%20data.%20Finish%20with%20the%20board%27s%20URL%2C%20the%0A%60ssh-key%20generate-api-key%60%20command%20to%20run%20on%20the%20owner%27s%20computer%2C%20and%0Athe%20%22Connect%20your%20agents%22%20section%20to%20follow%20next.%0A%0AFinish%20with%20the%20URLs%20I%20should%20open%20and%20these%20commands%2C%20which%20only%20I%20can%20run%2C%20from%20my%20own%20computer%20%28with%20this%20VM%27s%20name%20in%20them%29%3A%0A%20%20ssh%20exe.dev%20ssh-key%20generate-api-key%20--vm%3Dmy-kanzo%20--label%3Dkanzo-agents%20--exp%3D90d%0A to create a VM whose agent, Shelley, follows this recipe. From a terminal:

```sh
curl -fsSL https://exe.dev/deploy/kanzo/prompt.txt | ssh exe.dev new --prompt=/dev/stdin
```

Then, on your own computer:

```sh
ssh exe.dev ssh-key generate-api-key --vm=my-kanzo --label=kanzo-agents --exp=90d
```

Or follow the steps below by hand.

[Kanzo](https://github.com/emanuele-em/kanzo) is a kanban board and an
MCP server in one small program. You add tasks on the board in your
browser; your coding agents take the next one, move it to *doing*, comment
on what they did and move it to *review*. Mark a task **Human** and agents
leave it to you.

On your laptop, it's a board for the agents on your laptop. On an exe.dev
VM, it's one board for all of them: Claude Code on one VM, Codex on
another, Shelley, and you from any browser, at one HTTPS address. Kanzo
has no logins of its own, so it must never face the internet bare; behind
exe.dev's [HTTPS proxy](/docs/proxy) only you and your agents' tokens get
in. The VM is always on and keeps the board on its disk.

## Open the board

Open `https://my-kanzo.exe.xyz/` and sign in to exe.dev if asked. Press
**New project**, name it after a repository (`api`), then press `n` to
add a few tasks. Under the project's ⋯ menu, link its GitHub repository
(`you/api`): agents that run Kanzo locally find the project by it.

Leave **Share this board** (the share icon) off. That's Kanzo's own
sharing for a home network, without logins; here exe.dev does the
sharing. To give a teammate the board, [share the VM](/docs/sharing) with
their email; they'll sign in with exe.dev.

## Connect your agents

Agents can't sign in with a browser, so they send a VM token instead.
On your computer (`--exp` sets when it expires):

```bash
ssh exe.dev ssh-key generate-api-key --vm=my-kanzo --label=kanzo-agents --exp=90d
```

exe.dev's proxy checks the token in `X-Exedev-Authorization` and removes
it before the request reaches the VM
([HTTPS tokens for VMs](/docs/https-tokens-for-vms)). Below, replace
`exe1.paste-yours-here` with yours.

**Claude Code**, on your computer or on a [Claude Code VM](/deploy/claude-code):

```bash
claude mcp add --transport http --scope user kanzo https://my-kanzo.exe.xyz/mcp \
  --header "X-Exedev-Authorization: Bearer exe1.paste-yours-here"
claude mcp list
```

Expect `kanzo: https://my-kanzo.exe.xyz/mcp (HTTP) - ✔ Connected`.

**Codex**, in `~/.codex/config.toml`:

```toml
[mcp_servers.kanzo]
url = "https://my-kanzo.exe.xyz/mcp"
http_headers = { "X-Exedev-Authorization" = "Bearer exe1.paste-yours-here" }
```

**Shelley**, on any of your VMs:

```bash
shelley mcp add kanzo -d "Kanzo: my kanban board" \
  -H "X-Exedev-Authorization: Bearer exe1.paste-yours-here" \
  https://my-kanzo.exe.xyz/mcp
shelley mcp call kanzo.list_projects
```

**Other clients:** any MCP client that speaks Streamable HTTP and can
send a header.

### Agents on your other VMs, with no token

For agents on your other exe.dev VMs, a
[VM-to-VM integration](/docs/integrations-vm-to-vm) adds the token at
exe.dev's edge, so it never sits on the agent's VM. On your computer, for
an agent on `my-claude-code`:

```bash
ssh exe.dev integrations add http-proxy --name kanzo \
  --target https://my-kanzo.exe.xyz/ --peer --attach vm:my-claude-code
```

Then, on that VM, connect with no header:

```bash
claude mcp add --transport http --scope user kanzo https://kanzo.int.exe.xyz/mcp
```

To give the same board to more VMs, attach the same integration to each
(`ssh exe.dev integrations attach kanzo vm:my-codex`), or to a tag.

### Agents on the Kanzo VM itself

The Kanzo VM is a fine place to run agents too. There they can start
Kanzo's own MCP server, which also finds the project from the git remote
of the folder they work in:

```bash
claude mcp add kanzo --scope user -- kanzo mcp
codex mcp add kanzo -- kanzo mcp
```

## Try it

Ask your agent, in a repository's folder:

> Take the next task from kanzo in project api and do it. Sign your
> comments as claude@my-claude-code.

The card moves to **Doing** on your board within seconds, then to
**Review** with the agent's notes. Over HTTP, Kanzo can't see which
folder the agent is in, so name the project; and it signs comments with
whatever name the agent gives, so ask for one per agent.

<figure>
<img src="https://exe.dev/deploy/kanzo/board.png" alt="The Kanzo board at an exe.xyz address: a task in Review, opened, with a comment from Claude Code signed claude@kanzo-agent-hub describing the /health endpoint it wrote" width="1280" height="800" loading="lazy">
<figcaption>Claude Code on another VM took api#3, wrote the code, and left it in Review with a note.</figcaption>
</figure>

Other things to ask:

> Break the README's roadmap into kanzo tasks in project web, one per
> feature, tagged ui or api.

> What's in review on kanzo? Summarize each task's last comment.

## The nuts and bolts

Happy with what Shelley set up? Stop here. Below are the steps it
followed, and maintenance for later.

<details id="create-the-vm" data-manual-setup class="dp-details">
<summary>Set up by hand</summary>

### Create the VM

On your computer (pick another name if `my-kanzo` is taken):

```bash
ssh exe.dev new --name=my-kanzo
ssh my-kanzo.exe.xyz
```

Everything else runs **on the VM**.

### Install Kanzo

Kanzo's installer puts the program in `~/.cargo/bin`, the one place it
can update itself:

```bash
curl -LsSf https://github.com/emanuele-em/kanzo/releases/download/v0.3.0/kanzo-installer.sh | sh
. ~/.cargo/env
kanzo --version
```

Expect `kanzo 0.3.0`. Keep it running as a systemd user service, started
at boot even when no one is logged in:

```bash
kanzo service install
sudo loginctl enable-linger exedev
```

The first run creates `~/kanzo`, with the board in `kanzo.db` and
settings in `config.toml`. Kanzo listens on `127.0.0.1:4242` only; leave
it there.

### Put it behind the exe.dev proxy

Kanzo refuses requests addressed to any name but `localhost` and pages
from any origin but its own `http://` one, to stop other websites from
reaching it through your browser. So nginx takes exe.dev's proxy traffic
on port 8000, does that check against the VM's HTTPS address instead,
and passes the request on as a local one. This replaces the image's
default site:

```bash
sudo tee /etc/nginx/sites-available/kanzo >/dev/null <<'EOF'
server {
    listen 8000 default_server;
    listen [::]:8000 default_server;
    server_name _;
    client_max_body_size 32m;
    location / {
        # exe.dev's proxy signs people in. Refuse pages from other sites,
        # then hand Kanzo a local request, which is all it accepts.
        set $same_site 0;
        if ($http_origin = "") { set $same_site 1; }
        if ($http_origin = "https://$host") { set $same_site 1; }
        if ($same_site = 0) { return 403; }
        proxy_pass http://127.0.0.1:4242;
        proxy_http_version 1.1;
        proxy_set_header Host localhost:4242;
        proxy_set_header Origin "";
        proxy_set_header Connection "";
        proxy_buffering off;
        proxy_read_timeout 1h;
    }
}
EOF
sudo rm -f /etc/nginx/sites-enabled/default
sudo ln -sf /etc/nginx/sites-available/kanzo /etc/nginx/sites-enabled/kanzo
sudo nginx -t && sudo systemctl enable --now nginx && sudo systemctl reload nginx
```

### Check it

As exe.dev's proxy reaches it: the board, a write from the board's own
page, a write from another site's page, and MCP:

```bash
H="Host: $(hostname).exe.xyz"; J='Content-Type: application/json'
curl -s -o /dev/null -w 'board %{http_code}\n' -H "$H" http://localhost:8000/
curl -s -o /dev/null -w 'same site %{http_code}\n' -H "$H" -H "$J" \
  -H "Origin: https://$(hostname).exe.xyz" -d '{"slug":"setup-check"}' http://localhost:8000/api/projects
curl -s -o /dev/null -w 'other site %{http_code}\n' -H "$H" -H "$J" \
  -H 'Origin: https://example.com' -d '{"slug":"nope"}' http://localhost:8000/api/projects
curl -s -o /dev/null -w 'mcp %{http_code}\n' -H "$H" -H "$J" -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"check","version":"1"}}}' \
  http://localhost:8000/mcp
curl -s -o /dev/null -w 'cleanup %{http_code}\n' -X DELETE http://localhost:4242/api/projects/setup-check
```

Expect `200`, `200`, `403`, `200` and `200`.

### Back up nightly

This script copies the board with `sqlite3 .backup` (safe while Kanzo
and agents write), checks the copy, adds the settings and pasted images,
and keeps the 14 newest:

```bash
mkdir -p ~/bin ~/backups
cat > ~/bin/kanzo-backup <<'EOF'
#!/bin/bash
# Back up ~/kanzo to ~/backups/kanzo-<time>.tar.gz. Keeps the 14 newest.
set -euo pipefail
umask 077
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
sqlite3 "$HOME/kanzo/kanzo.db" ".backup '$work/kanzo.db'"
[ "$(sqlite3 "$work/kanzo.db" 'PRAGMA integrity_check')" = ok ]
cp "$HOME/kanzo/config.toml" "$work/"
[ -d "$HOME/kanzo/images" ] && cp -r "$HOME/kanzo/images" "$work/"
out="$HOME/backups/kanzo-$(date -u +%Y%m%d-%H%M%S).tar.gz"
tar -czf "$out.part" -C "$work" .
mv "$out.part" "$out"
ls -1t "$HOME"/backups/kanzo-*.tar.gz | tail -n +15 | xargs -r rm --
echo "$out"
EOF
chmod +x ~/bin/kanzo-backup
```

Run it nightly, around 03:30 UTC:

```bash
sudo tee /etc/systemd/system/kanzo-backup.service >/dev/null <<'EOF'
[Unit]
Description=Back up the Kanzo board to ~/backups

[Service]
Type=oneshot
User=exedev
ExecStart=/home/exedev/bin/kanzo-backup
EOF
sudo tee /etc/systemd/system/kanzo-backup.timer >/dev/null <<'EOF'
[Unit]
Description=Back up the Kanzo board nightly

[Timer]
OnCalendar=*-*-* 03:30:00 UTC
RandomizedDelaySec=15m
Persistent=true

[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now kanzo-backup.timer
```

Make one now and check that it opens, in a scratch directory:

```bash
backup=$(~/bin/kanzo-backup)
rm -rf /tmp/restore-check && mkdir /tmp/restore-check
tar -xzf "$backup" -C /tmp/restore-check
sqlite3 /tmp/restore-check/kanzo.db 'PRAGMA integrity_check; SELECT count(*) FROM projects;'
rm -rf /tmp/restore-check
```

Expect `ok` and a number of projects. Copy `~/backups` off the VM now
and then; otherwise the VM's disk holds the only copy.

</details>

<details id="back-up-and-restore" class="dp-details">
<summary>Back up and restore</summary>

On the VM, `~/bin/kanzo-backup` backs up now and prints the archive's
path. To copy the backups to your computer:

```bash
scp 'my-kanzo.exe.xyz:backups/kanzo-*.tar.gz' .
```

To restore one, on the VM, stop Kanzo, set the current board aside, and
unpack:

```bash
backup=~/backups/kanzo-20261102-033012.tar.gz
systemctl --user stop kanzo
mv ~/kanzo ~/kanzo.before-restore-$(date +%s)
mkdir ~/kanzo && tar -xzf "$backup" -C ~/kanzo
systemctl --user start kanzo
```

On a new VM, follow [Set up by hand](#create-the-vm) first, then copy
the archive over with `scp` and restore it the same way. Delete
`~/kanzo.before-restore-*` once you're happy.

Kanzo can also keep the board in a private git repository of yours
(`kanzo sync`). That's meant for carrying a board between computers you
use one at a time, not for a board several computers use at once.

</details>

<details id="update" class="dp-details">
<summary>Update</summary>

Back up first. Then, on the VM:

```bash
kanzo update
```

It installs the latest release over `~/.cargo/bin/kanzo` and restarts the
service. The board's sidebar offers new versions too, with one click.
Kanzo is pre-1.0 and releases often; read the
[release notes](https://github.com/emanuele-em/kanzo/releases) before
updating a board you rely on.

</details>

<details id="troubleshooting" class="dp-details">
<summary>Something not working?</summary>

On the VM, Kanzo's status and log, and nginx's:

```bash
systemctl --user status kanzo --no-pager
journalctl --user -u kanzo -n 50 --no-pager
sudo tail -n 20 /var/log/nginx/error.log
```

**`kanzo does not answer requests from other sites`.** The request
reached Kanzo without going through nginx, for example at
`https://my-kanzo.exe.xyz:4242/`. Use `https://my-kanzo.exe.xyz/`.

**A plain `403 Forbidden` from nginx.** A page from another site, or an
address other than `https://my-kanzo.exe.xyz`, tried to change the board.
A custom domain needs its own `if ($http_origin = ...)` line.

**An agent gets `401` or an HTML login page.** No valid token reached
exe.dev. Check the header name, the `Bearer` before the token, and that
the token is for this VM and hasn't expired.

**nginx won't start.** Something else listens on port 8000:
`sudo ss -ltnp | grep ':8000'` shows what. Stop it, or move it to
another port, then `sudo systemctl restart nginx`.

**`502 Bad Gateway`.** Kanzo isn't running: check its status and log
above, then `systemctl --user restart kanzo`.

**The agent says to pass `project`.** Over HTTP, Kanzo can't tell which
repository the agent is in. Name the project in your request, or ask the
agent to call `list_projects`.

</details>

## Frequently asked questions

### What is Kanzo?

A kanban board and an MCP server in one 4.5 MB Rust program, by Emanuele Micheletti, first released in October 2026. You use the board in a browser; agents take tasks, move cards and comment over MCP. It's young and changes daily: this page was tested with 0.3.0.

### Kanzo can share a board by itself. Why put it behind exe.dev?

Kanzo's sharing (`kanzo share on`, `kanzo join`) has no logins: anyone who can reach the port can read and change the board, so its README says to share only on a network you trust. On exe.dev, the board and its MCP endpoint answer only you, people you [share the VM with](/docs/sharing), and agents holding a VM token or a VM-to-VM integration.

### Can I use kanzo join from my laptop instead?

Not through exe.dev's proxy: `kanzo join` speaks plain HTTP to an address and can't send a token. Put the VM and your computers on [Tailscale](/docs/integrations-tailscale-wif), turn on sharing on the VM, and join its Tailscale address; anyone on your tailnet then has the board, with no login. Connecting agents over MCP, as above, needs neither.

### Does Kanzo know who changed what?

Not by itself. Comments from the board are signed "me", whoever is signed in, and comments over HTTP MCP are signed with the name the agent gives, so ask agents to sign theirs. exe.dev's proxy does know who called (`X-ExeDev-Email`, `X-Exedev-Source-Vm`), but Kanzo doesn't record it.

### How do agents know which project to use?

An agent running `kanzo mcp` on its own computer finds the project from its repository's git remote. Over HTTP, Kanzo can't see the agent's folder, so the agent has to name the project; Kanzo tells it so and lists them. Say "in project api" in your request.

### What does it cost?

Kanzo is free (AGPL-3.0) and runs no model, so just your [VM plan](https://exe.dev/pricing); it uses a few megabytes of memory and can share a VM with other things. Your agents' model use bills wherever those agents run.


## Related

- [Host a remote MCP server](https://exe.dev/deploy/mcp-server.md): Tools for all your agents, on a computer of their own. Private until you say.
- [Self-host Executor, the open-source MCP gateway](https://exe.dev/deploy/executor.md): Add your tools once; every agent reaches them through one private MCP URL.
- [Run Claude Code on a remote server](https://exe.dev/deploy/claude-code.md): A computer for Claude. A breather for your laptop.
- [Run Codex on a remote server](https://exe.dev/deploy/codex.md): A computer for Codex. An early night for your laptop.
- [Running Agents](https://exe.dev/deploy/agents.md): Use exe.dev VMs as a sandbox
- [Host OpenClaw](https://exe.dev/deploy/openclaw.md): An AI sidekick with its own computer. Your laptop can take a nap.
