Installing and Running Kiro Crew
September 4, 2026 · View on GitHub
This guide covers every way to install Kiro Crew, the first-run setup, how to verify the install, and how to troubleshoot the failures that actually happen.
Builds use plain pip + npm/Vite + pytest, driven by the repo-root
Makefile. There is no proprietary build tooling.
Platforms: macOS, Linux, and Windows. macOS and Linux use the
Makefile/setup.shpaths below. Windows runs natively from a Python source install (pip install -e ".[voice]", launched viapython -m kiro_crew gateway); all POSIX-only process, signal, file-lock and metrics calls route throughkiro_crew.platform_compat. See windows-install.md for the Windows walkthrough.
- Prerequisites
- Install paths
- Build targets
- First run
- Configuration
- Verify the install
- Running as a service
- Linux: the agent sandbox and unprivileged user namespaces
- Troubleshooting
- Uninstalling
- Removing user data
- Clean reinstall
- Data retention details
- Next steps
Prerequisites
| Requirement | Needed for | Floor |
|---|---|---|
| Python | Backend | >= 3.12 (requires-python in pyproject.toml; make build provisions a 3.12 .venv by default) |
| Node.js + npm | Building the dashboard | >= 22 (website/package.json engines; Node 24 LTS recommended); on x86_64 Amazon Linux 2, the glibc-217 fallback installs Node 24 because official builds need a newer glibc (no glibc-217 arm64 build is available) |
kiro-cli | Driving the LLM | Required; see below |
Node is only needed to build the dashboard. The prebuilt wheel, the DMG, the
AppImage, and the Linux .deb / .rpm packages all ship the dashboard already
bundled, so end users of those artifacts need neither Node nor a compiler.
Agent backend: kiro-cli (required)
Kiro Crew drives an LLM through the kiro-cli agent over the
Agent Client Protocol
(ACP). It is the only provider: agent.provider is fixed to acp, and the
gateway spawns kiro-cli acp --agent <name>.
Install kiro-cli per its own docs, put it on your PATH, and log in:
kiro-cli login
If kiro-cli is not on PATH, spawning a session fails with
kiro-cli not found in PATH. On the first dashboard launch the Set up Kiro
page walks through installing the CLI and completing device-code sign-in.
kirocrew doctor reports both the binary and the login state.
Embeddings: nothing to install
Semantic memory and the knowledge library need no setup step. Embeddings run
in-process through the vendored llama-cpp-python runtime, so there is no
separate server and no HTTP hop. On first start the gateway downloads the
Qwen3-Embedding-0.6B GGUF (about 610 MB) in the background over HTTPS, verifies
it against a pinned sha256, and installs it under ~/.kiro/crew/models/.
While the model is absent (first boot, download in flight, or a failed download), memory search degrades to keyword/FTS search and picks embeddings up automatically once the model lands, with no gateway restart. Two escape hatches exist for mirrored or airgapped installs:
KIROCREW_EMBED_MODEL_URL(ormemory.embed_model_url) points the download at a mirror. The sha256 pin still verifies whatever it fetches.KIROCREW_EMBED_MODEL_PATH(ormemory.embed_model_path) runs a local GGUF of your own instead. In that mode the default model is never downloaded.
memory.embedding_provider accepts only llama_cpp; any other value in an old
config is coerced to it on load.
Install paths
Which path on Linux
Start with the one-line install below. It is the smoothest Linux path and
the one that needs the fewest decisions: it puts kirocrew on your PATH at a
stable location, which is what makes kirocrew service install — and therefore
the AppArmor profile
the agent sandbox needs on Ubuntu 23.10+ — reachable in the first place. You
work in the dashboard through your browser at localhost:5476.
Install a desktop package (.deb / .rpm) in addition when you want the
things only the Electron shell provides: an application-menu entry and icon, a
native window with persisted geometry, a dock/taskbar badge, a system-wide hotkey
to summon the dashboard, a gateway that starts and stops with the app, and
in-app updates. The packages install to a fixed path under /opt, so the same
PATH and AppArmor mechanics that make the one-line install work apply to them
too.
The AppImage stays available for hosts where you cannot install a system
package (no root, an unsupported distro). It needs FUSE present, and because it
runs from a randomized temporary mount there is no durable path to attach an
AppArmor profile to or to point a kirocrew launcher at — so on a distro that
restricts unprivileged user namespaces it needs the extra manual step described
in the sandbox section. Prefer a package where you can.
| You want | Use |
|---|---|
| The dashboard, a terminal, scheduled work, a server | One-line install (a) |
| A desktop app on Debian/Ubuntu | .deb (d) |
| A desktop app on Fedora / RHEL / CentOS Stream / Amazon Linux 2023 | .rpm (d) |
| A desktop app with no root and no package manager | AppImage (d) |
| A container host | Docker (guide) |
a. One-line install (fastest)
Installs a prebuilt, sha256-verified wheel from the release CDN. No clone, no npm, no local build:
curl -fsSL https://download.crew.kiro.dev/cli.sh | sh
stable is the default channel. Track a faster one, or pin an exact version:
curl -fsSL https://download.crew.kiro.dev/cli.sh | sh -s -- --channel insider
curl -fsSL https://download.crew.kiro.dev/cli.sh | sh -s -- --version 0.1.0
stable suits everyone, insider is for power users who want features days to
weeks early and accept the new bugs that arrive with them, and nightly is
untested main HEAD for us and contributors. The
Release channels table has the full
comparison; re-running the installer with a different --channel is how a CLI
install moves between lanes.
The installer verifies the wheel's digest against the signed manifest and
refuses to install on a mismatch; there is no checksum-only fallback. It uses
pipx when available, otherwise it creates a managed venv beside the data
home (~/.kiro/crew-venv, override with KIROCREW_VENV) and symlinks
~/.local/bin/kirocrew at it. The venv is deliberately not nested inside the
data home, so no whole-home operation can ever delete the live interpreter. The
selected channel is recorded to ~/.kiro/crew/channel.
If the host has no Python 3.12+, the installer provisions one itself instead of
touching the system: it downloads a SHA-256-pinned uv
binary (or uses an already-installed uv on PATH), then installs a
python-build-standalone
CPython 3.12 into a user-owned directory beside the data home
(~/.kiro/crew-python, override with KIROCREW_PYTHON_DIR). No package
manager, no sudo, and the prebuilt interpreter runs on old-glibc distros
(CentOS 7) whose base repos never reach 3.10. Pass --managed-python (or set
KIROCREW_MANAGED_PYTHON=1) to always use the uv-provisioned interpreter and
skip the system ones entirely — useful when the system Python is fragile or
version-managed. The choice is sticky: it is recorded in the data home
(python-mode, next to channel), so later installer runs — including the
re-run kirocrew update performs — keep it without the flag; opt back out
with --system-python. The signed installer never pipes an unsigned
third-party script into a shell: uv is fetched as a tarball and verified
against pinned digests, exactly like the wheel itself. When it finishes it
prints the next step: kirocrew gateway to start now, or kirocrew service install to run it as a service.
b. From source (development)
Build the dashboard, install the backend into a local virtualenv (.venv), and
run the gateway straight out of src/:
make build # npm build + editable backend install into .venv
PYTHONPATH=src python -m kiro_crew gateway # -> http://localhost:5476
On Windows the same targets run through make.ps1, because make is not part
of a Windows install and the Makefile's recipes are POSIX-shaped
(.venv/bin/pip, rm -rf, cp -R, bash ensure-*.sh):
.\make.ps1 build # same two steps, same artifacts
$env:PYTHONPATH="src"; .\.venv\Scripts\python.exe -m kiro_crew gateway
The venv interpreter is named explicitly rather than a bare python: the
dependencies live only in .venv, and on Windows a bare python resolves to the
system interpreter (or the Microsoft Store alias stub), which would fail at
import. .\.venv\Scripts\Activate.ps1 first is the other way, after which
python and kirocrew both resolve inside the venv.
The two drivers expose the same target set, and
test/test_build_target_parity.py fails the build if one gains a target the
other lacks. Differences are confined to what the platform forces: a Windows
venv puts its executables in .venv\Scripts\, and the macOS-only
resign-macos-libs.sh step has no Windows counterpart.
make build runs two steps:
frontend:npm ci(ornpm install) +npm run buildinwebsite/, then copieswebsite/distintosrc/kiro_crew/static/distso the backend serves the SPA, and installswebsite/electron's own deps last — it is a separate npm package thewebsite/install never reaches, andnpm testinwebsite/needs it.backend: creates.venvand runs an editable install with thedevextra (pip install -e ".[dev]").
Both targets bootstrap their toolchain first (ensure-node.sh,
ensure-python.sh) and fall back to whatever is on PATH if that fails. The
backend target refuses to build a venv from an interpreter older than 3.10
rather than letting the install backtrack forever.
make.ps1 resolves the same toolchain but installs none of it: the bootstrap
scripts' install paths are curl … | sh, so on Windows it searches (py
launcher first, then PATH, skipping the Microsoft Store alias stub) and prints
the winget command to run if nothing usable is found. It honors the same
<data-home>/python-bin and node-bin-dir markers those scripts record. The
desktop and backend-bin targets are the exception: they delegate to
packaging/build-desktop.sh, which provisions its own uv and
python-build-standalone interpreter on every platform.
After the backend target runs, bin/kirocrew resolves its real install root,
sets KIROCREW_PROJECT_DIR, and delegates to .venv/bin/kirocrew. That console
script comes from the editable package metadata (kiro_crew._bootstrap:main),
so the virtual environment makes src/kiro_crew importable without the wrapper
modifying PYTHONPATH; caller-provided entries pass through unchanged.
Any CLI subcommand works the same way, for example
PYTHONPATH=src python -m kiro_crew setup or ... doctor.
The equivalent by hand:
git clone https://github.com/kirodotdev/KiroCrew.git
cd KiroCrew
cd website && npm install && npm run build && cd ..
pip install -e ".[voice]" # [voice] adds the optional speech-to-text extras
c. Self-contained pip wheel
Produce a wheel that bundles the pre-built dashboard, then install it anywhere with a suitable Python:
make wheel # builds the frontend, then python -m build --wheel -> dist/
pip install dist/*.whl
kirocrew gateway # -> http://localhost:5476
Kiro Crew is pure Python, so the wheel is platform-independent:
dist/kirocrew-<version>-py3-none-any.whl (for example
kirocrew-0.1.2-py3-none-any.whl). One wheel serves every OS. The dashboard is
folded in by the custom BuildWithFrontend build step in
setup.py, which also bundles CHANGELOG.md so the
dashboard's changelog view works on a wheel install with no source tree.
The pip install name is kirocrew; the import package is kiro_crew.
Installed console script:
| Command | Entry point |
|---|---|
kirocrew | kiro_crew._bootstrap:main |
pyproject.toml's [project.scripts] declares kirocrew and nothing else.
Because a [project] table exists, setuptools reads the entry points from
there and ignores setup.cfg's console_scripts, so kirocrew is the only
command installed on PATH.
Optional extras. Kiro Crew is not on PyPI, so pip install "kirocrew[voice]"
cannot resolve — install an extra's own distributions into the environment that
runs the gateway instead (e.g. pip install 'boto3>=1.34,<2' 'amazon-transcribe>=0.6,<1' 'pywhispercpp>=1.5,<2' for voice). The dashboard
prints the exact command, already pointed at the right interpreter.
| Extra | Adds | For |
|---|---|---|
voice | boto3, amazon-transcribe, pywhispercpp | Speech-to-text transcription |
otlp | opentelemetry-exporter-otlp-proto-http | OTLP/HTTP metrics export. Installing it does not enable egress; that still needs an explicit telemetry.otlp_endpoint |
perf | py-spy | Out-of-process profiling (kirocrew perf sample --pid). The in-process sampler needs nothing extra |
teams | PyJWT[crypto] | Microsoft Teams channel (validates the inbound Bot Framework RS256 JWT) |
dev | pytest, black, isort, flake8, mypy, ... | Contributor tooling; what make build installs |
make desktop and make backend-bin need no extra: both run
packaging/build-desktop.sh, which provisions a python-build-standalone
interpreter and pip-installs the project into it.
d. Bundled desktop app
A double-clickable app that embeds a python-build-standalone (PBS) interpreter plus uv-installed deps inside an Electron shell. End users need no Python, pip, npm, or Node:
make desktop
Output is a DMG (plus a zip) on macOS, an AppImage plus a .deb and an .rpm
on Linux, and an assisted NSIS Setup.exe on Windows, under
website/electron/dist/. The macOS DMG opens to a branded
drag-to-Applications layout carrying the opening animation's artwork. The
Windows wizard keeps native controls and its
per-user default while carrying matching Kiro Crew artwork through its sidebar
and header. On macOS the default is ONE universal DMG: the Electron shell is
lipo-merged, and the backend, which cannot be lipo-merged, ships as two complete
PBS trees selected at launch by process.arch. The x86_64 backend is built
under Rosetta 2, so a universal build needs an Apple-Silicon host;
UNIVERSAL=0 forces a faster host-arch-only build. Linux is always host-arch,
and the three Linux formats come from one backend tree packaged three times.
Installing a Linux desktop package
sudo apt install ./KiroCrew-x86_64.deb # Debian, Ubuntu
sudo dnf install ./KiroCrew-x86_64.rpm # Fedora, RHEL, CentOS Stream, AL2023
Either one installs to /opt/KiroCrew, registers the application-menu entry and
MIME database, refreshes the icon cache, links /usr/bin/kirocrew-desktop, and —
on a host whose AppArmor supports the bundled profile — installs and loads the
userns profile the agent sandbox needs, so no manual sandbox install-profile
step is required. The fixed install path is what makes all of that durable.
Updates arrive through the app (About → Check for updates), which downloads
the new package and hands it to dpkg / rpm. That needs root, so expect one
elevation prompt (pkexec or sudo) at install time — it is the package
manager doing the write, not the app. sudo apt remove kirocrew /
sudo dnf remove kirocrew uninstalls; see
Uninstalling for what happens to your data.
The AppImage needs no root and no package manager, which is the reason to pick
it, but it also needs FUSE present (sudo dnf install fuse on Amazon Linux
2023, which ships without it; --appimage-extract-and-run is the escape hatch)
and it runs from a randomized temporary mount, so it carries the manual
sandbox-profile step and the move-breaks-it caveat documented in the
sandbox section.
All three Linux formats are built from the same glibc floor as the build runner. Verified requirement at the time of writing is glibc 2.34, which covers Ubuntu 22.04+, Debian 12+, Fedora, CentOS Stream 9 and Amazon Linux 2023, and excludes Ubuntu 20.04, Debian 11 and Amazon Linux 2 — on those, use the one-line install instead.
Prebuilt downloads for the release channels are linked from the README. The Windows desktop installer remains a preview artifact; see windows-install.md for its current publishing and signing status. The source install remains the fully supported Windows path.
See desktop-app.md for the full pipeline (frontend, PBS provisioning, pip install, pruning, electron-builder) and how the app locates and launches the bundled backend.
e. Docker
For always-on servers the gateway also ships as a public multi-arch image on GHCR. See docker.md.
Build targets
Every target has the same name on both drivers: make <target> on macOS and
Linux, .\make.ps1 <target> on Windows.
| Target | What it does |
|---|---|
make build | Frontend (npm/Vite) + backend into .venv |
make frontend | Frontend only: npm build staged into src/kiro_crew/static/dist, plus website/electron deps |
make backend | Backend only: .venv + editable install with the dev extra |
make wheel | Self-contained pip wheel with the dashboard bundled, into dist/ |
make backend-bin | Frozen standalone backend binary (host arch only) |
make desktop | Full desktop app: DMG on macOS, AppImage on Linux, NSIS installer on Windows |
make test | Build, then run the pytest suite |
make clean | Remove build artifacts, dists, and caches |
Override the Python interpreter with make PY=python3.12 build, or
.\make.ps1 build -Py C:\path\to\python.exe.
Both desktop targets run packaging/build-desktop.sh on every platform,
including Windows, where make.ps1 invokes it through the Git for Windows bash:
the script already normalizes MSYS uname output and has a Windows PBS branch,
and CI's Windows lane calls it the same way. The plain build path needs no
bash. Note that a locally built Windows installer is unsigned — only CI's
signing lane has the signing identity — so SmartScreen shows an "unrecognized
app" interstitial.
First run
After installing by any path:
kirocrew setup # interactive wizard
kirocrew doctor # verify everything is wired up
kirocrew gateway # start the server, then open http://localhost:5476
From a source checkout, use PYTHONPATH=src python -m kiro_crew <subcommand>
in place of kirocrew.
What kirocrew setup asks
The wizard installs the agent config, then walks through the workspace
directory, timezone, dashboard URL, and (on macOS) the desktop app. It does NOT
configure any messaging channel: pass --slack to opt into the guided Slack
credential and slash-command setup. It also does NOT install a browser: browsing
is available when playwright-cli is on PATH, and you install it separately (see
Browser).
Want the Playwright CLI at your own shell? That is a separate tool from the Browser Mode above, and it has its own installer, which bootstraps Node when your machine has none and reports enterprise-registry failures (mirror login, proxy, blocked browser CDN) as specific remedies rather than a raw npm dump:
curl -fsSLO https://raw.githubusercontent.com/kirodotdev/KiroCrew/main/playwright-cli.sh
less playwright-cli.sh # read it before you run it
sh playwright-cli.sh --version 0.1.18
The download-and-read form is listed first on purpose: piping a script into a
shell is prohibited on many corporate machines, and raw.githubusercontent.com
itself is blocked or rate-limited on some — which is the same audience whose
network this script exists to cope with. If yours allows it, curl -fsSL … | sh
works as a one-liner; if it does not, take the file from a checkout or a release
and run it locally. Either way the script reaches only three hosts: the npm
registry (or the mirror you point it at), the Node mirror when it has to
bootstrap a toolchain, and the Playwright CDN for the browser binaries — that
last one only unless you pass --skip-browsers, and --download-host points it
at an internal mirror instead.
Windows uses playwright-cli.ps1 with the same flags in PowerShell spelling.
--help lists all of them; --dry-run prints the plan without changing anything.
Design notes and the exit-code table:
browser module spec.
Messaging channels are optional. The default wizard configures none, and the
web dashboard is fully functional without any messaging credentials. Connect a
channel later -- Slack (kirocrew setup --slack or
slack-setup.md),
Discord,
Telegram,
Teams,
Webex,
WeCom,
WeChat, or
WhatsApp --
when you want to reach the same agent away from your desk.
These flags narrow the wizard:
| Flag | Effect |
|---|---|
--agent-only | Install the agent config and stop, skipping the workspace and every credential prompt |
--slack | Run the guided Slack credential + slash-command setup (opt-in) |
--clean | Fresh agent config: ignore the existing kirocrew.json and regenerate from defaults instead of merging your MCP servers and tools forward |
--electron-only | Install only the macOS desktop app |
The two combine: kirocrew setup --agent-only --clean rebuilds the agent config
from scratch and touches nothing else. That is the fix for a broken or stale MCP
configuration, because without --clean the existing file is used as the base
so all user customizations survive.
Browser
Browsing is optional and installed separately. The agent drives a browser by
running playwright-cli commands, so it needs Node.js 20 or newer:
npm install -g @playwright/cli@latest
playwright-cli install-browser # --with-deps on Debian/Ubuntu only
playwright-cli install --skills agents --global
--with-deps installs OS libraries through apt and needs root. Playwright
implements it for apt alone, so on Fedora, RHEL, CentOS or Amazon Linux it
misfires against Ubuntu package names; install the libraries with your own
package manager instead. The Settings → Browser install button adapts to the
host and reports the command to run when it needs root — see
the browser module spec.
The dashboard's Browser panel embeds the CLI's own dashboard over loopback,
which shows the live session and lets you take over with real mouse and keyboard.
That is how you complete a CAPTCHA or a 2FA prompt, and how you log in once so a
session can be captured with playwright-cli state-save.
Installing the CLI makes browsing available; it does not auto-approve it.
There is no separate capability toggle because the CLI has no way to expose only
a subset of its verbs. Every playwright-cli shell command still follows the
ordinary approval flow. Under normal mode the first command prompts; you can
approve once, trust its command pattern for the session, or deliberately enable a
wider trust mode. This matters most for playwright-cli attach --extension, which
drives your own running Chrome with the sessions you are already logged into.
Configuration
- Config file:
~/.kiro/crew/config.json, managed withkirocrew config get/set/edit. - Credentials:
~/.kiro/crew/.envholding messaging-channel tokens (for Slack:SLACK_APP_TOKEN,SLACK_BOT_TOKEN,KIROCREW_OWNER_ID; other channels use their own keys). See slack-setup.md for creating the Slack app.
Environment variables
| Variable | Default | Purpose |
|---|---|---|
KIROCREW_HOME | ~/.kiro/crew | Data directory (config, credentials, databases) |
KIROCREW_PORT | 5476 | Port the gateway / dashboard listens on |
KIROCREW_EMBED_MODEL_URL | CDN default | Mirror for the embedding model download |
KIROCREW_EMBED_MODEL_PATH | unset | Run a local GGUF instead of the bundled model |
KIROCREW_PORT is an environment variable validated at CLI entry, not a config
key. --port on the CLI overrides it (--port auto binds an OS-assigned
ephemeral port). The dashboard.url config key only advertises a remote URL.
For the installed service the port is baked into the unit at install time — see
Running as a service for how to set and later change
it.
The data home lives under ~/.kiro/
Kiro Crew stores its data in ~/.kiro/crew, sharing the ~/.kiro/ base with
other Kiro-family apps. An existing top-level ~/.kirocrew install migrates
automatically on first launch: its data (config, credentials, session history,
databases) is copied into ~/.kiro/crew, overwriting any file already at
the same relative path, then verified, then the legacy data is deleted. There is
no rollback copy and no backup of anything overwritten.
Details worth knowing before you upgrade:
- Re-downloadable bulk content (
models/,cache/) is not copied; the new home regenerates it on first start, exactly as a fresh install does. - Virtual environments at the legacy root (
venv,.venv,venvs) are neither copied nor deleted, because a venv is not relocatable and may be the very interpreter running the migration. The legacy root survives to hold them. - If a live gateway holds either home's
gateway.lock, the move is skipped for that run and completes on the next clean cold start. - The migration only runs on the default path. Setting
KIROCREW_HOMEskips it entirely, so set it before upgrading if you want the two homes to stay separate.
There is no rollback. Once the move completes, ~/.kirocrew is gone, and an
older release knows nothing of ~/.kiro/crew, so it would start empty. Back up
first if you need to be able to go back:
cp -a ~/.kirocrew ~/.kirocrew.manual-backup
Verify the install
kirocrew doctor
doctor reports, section by section: the composed platform edition, the data
home (including a legacy-home conflict warning), Linux pod session bus, the
project directory, the agent config, configuration values (provider, model,
approval mode, dashboard URL), the managed MCP servers and their tool counts,
the runtime, vector memory and the in-process embedding model (including whether
the model URL is reachable), speech-to-text, the Slack integration,
loop-stall crash dumps, and connectivity.
Running as a service
For always-on operation (channel bots, cron jobs, background tasks):
kirocrew service install # systemd on Linux, launchd on macOS
kirocrew service status
kirocrew service uninstall
On Linux this writes /etc/systemd/system/kirocrew.service (sudo is prompted
for the unit file and the systemctl calls; the gateway itself runs as your own
user, never under sudo). When you are already root — a minimal container or
root login — no sudo binary is required. On macOS it writes a launchd plist
and needs no sudo.
The gateway runs untrusted agent tools, so it must run as a non-root user:
the installer sets User= to the account behind sudo ($SUDO_USER, else
$USER), and refuses to install a User=root service. From a bare root
login (or sudo with no $SUDO_USER), first create or pick a normal account and
install as it, e.g. sudo -u <user> KIROCREW_KIRO_BIN=... kirocrew service install (the official Docker image already runs as the kirocrew user).
Setting the service port
A system service inherits none of your shell environment, so export KIROCREW_PORT=… in your shell does not reach it. Set the port when you
install so it is baked into the unit:
KIROCREW_PORT=5477 kirocrew service install
To change it later without reinstalling, edit the overrides file the installer creates and restart:
sudo sed -i 's/^#\?KIROCREW_PORT=.*/KIROCREW_PORT=5477/' /etc/kirocrew/kirocrew.env
sudo systemctl restart kirocrew
/etc/kirocrew/kirocrew.env is read by the unit via EnvironmentFile=, so its
values override the install-time snapshot and survive a reinstall. Use this to
move the service off the default 5476 when that port is already taken (for
example by a local crew you also run on this host — there is one
kirocrew.service unit, so re-running service install updates it in place
rather than creating a second service).
The EnvironmentFile= directive only exists in units written by v0.2.0 or
later. Upgrading the package never rewrites an already-installed unit, so a
unit installed by an older release (v0.1.3 and earlier) silently ignores
/etc/kirocrew/kirocrew.env — editing it changes nothing. Check which kind you
have:
grep EnvironmentFile /etc/systemd/system/kirocrew.service
No output means the directive is missing. Either re-run kirocrew service install (it rewrites the unit in place, keeping the same service), or set
variables with a systemd drop-in,
which works on any unit version.
Setting other environment variables (systemd drop-in)
For variables the seeded overrides file does not cover — proxy settings are the
common case — use a systemd drop-in. Drop-ins are systemd's own override
mechanism: they apply to the unit no matter which release wrote it, and they
survive reinstalls, service install re-runs, and even
kirocrew service uninstall (which removes the unit but never touches
/etc/systemd/system/kirocrew.service.d/).
sudo mkdir -p /etc/systemd/system/kirocrew.service.d
sudo tee /etc/systemd/system/kirocrew.service.d/proxy.conf > /dev/null <<'EOF'
[Service]
Environment="HTTPS_PROXY=http://proxy.example.com:3128"
Environment="HTTP_PROXY=http://proxy.example.com:3128"
Environment="NO_PROXY=localhost,127.0.0.1"
EOF
sudo systemctl daemon-reload
sudo systemctl restart kirocrew
A new or edited drop-in is not picked up until systemctl daemon-reload runs —
restarting alone is not enough. Verify what the unit resolved to with
systemctl cat kirocrew (drop-ins are printed below the unit) or
systemctl show kirocrew --property=Environment.
For remote hosts, see remote-and-mobile.md.
Linux: the agent sandbox and unprivileged user namespaces
On Linux, Kiro Crew isolates the agent by entering a user namespace and then
a mount namespace, over-mounting credential paths such as ~/.aws and
~/.ssh so the agent cannot read them. If that sandbox cannot be built,
Kiro Crew refuses to run the agent rather than run it unisolated: spawns fail
closed. This is deliberate and is not something to work around casually.
Ubuntu 23.10 and newer ship kernel.apparmor_restrict_unprivileged_userns=1,
which moves any process that creates a user namespace into a restricted AppArmor
profile with no CAP_SYS_ADMIN. The first unshare succeeds, the second fails
with EPERM, and you see:
sandbox: unshare(NEWNS) failed: errno 1
The remedy: let service install add an AppArmor profile
kirocrew service install
Where, and only where, this mechanism is the one in play, the installer also
writes /etc/apparmor.d/kirocrew-userns and loads it. The profile grants
exactly one permission (userns) and is attached to the resolved kirocrew
launcher script (the same absolute path service install uses as ExecStart,
typically something like ~/.kiro/crew-venv/bin/kirocrew) — the same approach
stock Ubuntu already uses for chrome and brave. An earlier version of this
profile was named-but-unattached and applied purely via AppArmorProfile= in
the unit; that shipped first (#1210) but was found not to actually confine the
gateway's sandbox probe (#3463) — the directive labels only the unit's own
top-level process, and the probe runs in a child reached through a fork the
directive's labelling never reaches. The directive is no longer used.
This uses the sudo prompt service install already needs for the unit file, so
it costs no additional privilege, and it cannot fail your install: if the
profile cannot be written, loaded, or verified, you get a warning and the
install continues. kirocrew service uninstall unloads and removes it, so a
host is left as it was found rather than carrying an orphaned userns permission.
The installer skips the profile silently, with a reason it can print, when
AppArmor is not an active LSM, when the sysctl is not 1, when
apparmor_parser is absent, or when the parser is older than 4.x (the userns
rule needs 4.x or newer). So on Debian, Arch, RHEL and Amazon Linux nothing
changes.
Running the gateway outside systemd (for example kirocrew gateway in a
terminal) is covered only when the launch goes through the attached launcher
path: the kernel applies a path-attached profile at every execve() of that
exact file, unit or no unit, so once service install has attached the profile,
a foreground kirocrew gateway typed at a shell that resolves to the same
launcher script runs confined too. A launch that does not go through that
path — python -m kiro_crew, a different venv's entry point, a re-created venv
the profile has not been re-pointed at — stays unconfined, and kirocrew doctor
reports the attachment as stale in the re-created-venv case. Prefer running the
gateway as the service: it pins ExecStart to the attached path and restarts on
boot.
The AppImage (desktop app) needs its own profile
A .deb or .rpm install needs none of this section: the package's
post-install step writes and loads a userns profile attached to its own fixed
path under /opt, so the sandbox works on a stock Ubuntu 23.10+ host with no
manual step and nothing to re-point later. That fixed path is the whole
difference — everything below exists because an AppImage does not have one.
The profile above is applied by systemd, so it covers the installed service and nothing else. Launching the AppImage directly gives systemd no part to play: the app execs the bundled backend itself, so neither process gets a profile and agent spawns fail closed exactly as before. Attach a profile to the AppImage instead:
kirocrew sandbox install-profile --path ~/Applications/kirocrew.AppImage
If you only ever downloaded the AppImage, you have no kirocrew on your
PATH — the CLI is bundled inside the app, which is the whole point of that
download. Use the bundled copy instead. The sandbox error message in the app
prints the exact absolute path for you; it looks like this, and it is valid while
the app is running:
'/tmp/.mount_XXXXXX/resources/backend-dist/kirocrew-backend/bin/kirocrew' \
sandbox install-profile --path ~/Applications/kirocrew.AppImage
Do not prefix that with sudo. The command elevates only the three steps
that need it (install, apparmor_parser, aa-exec) and prompts you for a
password when it does; running the whole thing as root would execute application
code with privilege for no reason.
Then restart the app. To check whether the launch you are looking at is covered:
kirocrew sandbox status
This writes /etc/apparmor.d/kirocrew-launcher, granting the same single
userns permission — but attached to that executable path, which is how the
kernel can apply it at exec time with no cooperation from the process. The
backend the app spawns inherits it. It is the same mechanism stock Ubuntu uses
for /etc/apparmor.d/chrome, brave, 1password and Discord.
kirocrew sandbox remove-profile unloads and removes it.
Three things the command refuses to do, because an attachment is a permission grant keyed on a path:
- A path you do not own. An AppImage you downloaded is owned by you, which is
the case this serves. A root-owned binary in a system location is shared with
every user of the machine, so attaching there would hand the grant to all of
them - and no blocklist of shared runtimes can be complete (
java,mono,dotnet,php,wineand friends are all in the same position as/usr/bin/python3). If you need to confine a system-wide install, ship a packaged profile the way the distro does forchromeandbrave. - A world-writable location (
/tmp,/var/tmp,/dev/shm,/run, or any directory in the path whose permissions let others write). Anyone with a local account could put their own file at that path and inherit the grant. Keep the AppImage somewhere durable such as~/Applications. This also rules out the AppImage's own/tmp/.mount_XXXXXXruntime directory, which is a fresh random path on every launch and could never match twice. - A shared interpreter such as
/usr/bin/python3. That would grant unprivileged user namespaces to every program on the host that runs it.
Because the profile is attached to a path, moving or renaming the AppImage
silently stops it applying — the kernel reports no error, the profile just
never matches. kirocrew sandbox status detects that and names the stale path;
re-running install-profile re-points it. Replacing the file in place (an
in-place update) keeps working, since the path is unchanged.
Running the gateway in a terminal (kirocrew gateway) is not covered by
either profile. Use kirocrew service install and let systemd run it. There is
no correct profile to attach for a foreground run: the only executable involved
is a shared Python interpreter, and attaching there would hand unprivileged user
namespaces to every Python process on the machine.
Earlier versions of this page suggested
aa-exec -p kirocrew-userns -- kirocrew gateway. That does not work and has been removed. Entering a named profile requiresaa_change_onexec, which an unprivileged unconfined process is not permitted to do, andaa-execdoes not fail loudly when it cannot transition — it execs the command unconfined, so the gateway appears to start under the profile while running without it. Running it undersudo aa-execdoes transition, but then the gateway runs as root.
Please do not "fix" this by setting the sysctl to 0. That disables a kernel-wide protection for every application on the machine to satisfy one app-scoped need. The per-application profile exists precisely so you do not have to.
Other reasons user namespaces can be denied
The AppArmor profile addresses only the Ubuntu restriction. These are different mechanisms with different remedies, and they report different errnos. The sandbox probe names the failing step so you can tell them apart:
| Symptom | Mechanism | Remedy |
|---|---|---|
unshare(CLONE_NEWNS) fails EPERM, sysctl is 1 | Ubuntu >= 23.10 AppArmor userns restriction | kirocrew service install, or kirocrew sandbox install-profile for the AppImage (this page) |
unshare(CLONE_NEWUSER) fails ENOSPC / EUSERS | user.max_user_namespaces=0 (CIS-hardened host) | Raise that sysctl |
unshare fails and kernel.unprivileged_userns_clone=0 | Debian-family legacy knob (defaults to 1 since Debian 11) | Set it to 1 |
unshare fails EINVAL / ENOSYS | Kernel built without CONFIG_USER_NS | None short of a different kernel |
| Fails inside Docker/Podman | The container's seccomp filter denies unshare | Container run flags, not host config |
| RHEL/Fedora/Rocky/AL2023 | SELinux, not AppArmor | userns is enabled there; the profile is inert |
To see which step is failing on your host:
python3 -c "
import kiro_crew.sandbox as sb
sb.reset_backend(); print(sb.detect_backend(), sb._last_unshare_failure)"
kirocrew doctor reports the same verdict without the one-liner, and the
dashboard's Sandbox unavailable screen names the mechanism and the command
for it directly — the probe classifies the failing step into one of
apparmor_userns, max_user_namespaces, userns_denied or no_user_ns, which
is the row of the table above that applies to you.
Troubleshooting
Always start with kirocrew doctor.
AcpTimeoutError: ACP prompt timed out
The kiro-cli backend did not answer in time. Five common causes:
kiro-cliis not installed. The gateway raiseskiro-cli not found in PATH. Install it, or use the dashboard's Set up Kiro page.- Not logged in. Run
kiro-cli login. An expired session normally surfaces as the distinct, non-retryable "kiro-cli is not logged in" error rather than a timeout, so check this even when the message differs. - A broken or stale MCP config. Rebuild it with
kirocrew setup --agent-only --clean. A single unreachable MCP server can consume the whole initialization window. - First launch is genuinely slow. MCP servers can be slow to initialize, so the handshake allows up to 4 minutes before giving up. Later timeouts have their own watchdogs: a turn that streams text and then goes quiet for 90 seconds is treated as finished, and a dispatched tool that returns nothing at all for 10 minutes is treated as a dead stall and the agent is killed to recover the slot.
- The host needs a proxy and the service does not have one. On a
corporate network,
kiro-climust reach its backend through your proxy. A systemd service inherits none of your shell'sHTTPS_PROXY/HTTP_PROXYexports, so a gateway that works when run from your terminal can still time out as a service. Set the proxy variables on the unit with a systemd drop-in, thensudo systemctl daemon-reload && sudo systemctl restart kirocrew. Agent sessions inherit the service environment, so this fixes them. One known gap: the first-run setup gate's login probe currently filters proxy variables out even when the unit carries them, so it can stay stuck on "Sign in to Kiro CLI" on a proxied host — that is issue #2648.
Memory or knowledge search returns nothing
The embedding model is probably still downloading. Check the Vector Memory
section of kirocrew doctor, which reports the model state and whether the
model URL is reachable, and look for the GGUF under ~/.kiro/crew/models/.
Search falls back to keyword matching until the model lands, then switches over
on its own with no restart. For an airgapped or firewalled host, point
KIROCREW_EMBED_MODEL_URL at a mirror; the sha256 pin still verifies the file.
The gateway will not start
kirocrew doctor
kirocrew gateway --port auto # bind an OS-assigned port if 5476 is taken
Uninstalling
Uninstalling removes the Kiro Crew binary and its runtime but preserves your
data home (~/.kiro/crew) — configuration, credentials, memory, sessions,
apps, and the audit chain remain intact. This is intentional: reinstalling picks
up where you left off without re-running setup or losing history.
Before uninstalling, stop any running gateway and remove the system service if one is installed:
kirocrew stop # stop a running foreground gateway
kirocrew service uninstall # removes the systemd unit / launchd plist
Then follow the section matching your install method.
One-line install via cli.sh (pipx)
If cli.sh used pipx (the default when pipx is on PATH):
pipx uninstall kirocrew
One-line install via cli.sh (managed venv)
If pipx was not available, cli.sh created a managed venv and a symlink.
Remove both:
rm -f ~/.local/bin/kirocrew
rm -rf "${KIROCREW_VENV:-${KIROCREW_HOME:-$HOME/.kiro/crew}-venv}"
If you set KIROCREW_VENV to a custom path, verify its contents before
removing it — cli.sh overlays that directory with venv files, and an rm -rf
on a path you already used for something else will take that too.
pip / pip wheel install
pip uninstall kirocrew
If installed in a dedicated virtualenv:
rm -rf /path/to/your/venv
From source (development)
Remove the editable install and the build artifacts:
# Chained so a failed `cd` (wrong path) can never run `rm -rf` in your current directory:
cd /path/to/KiroCrew \
&& pip uninstall kirocrew \
&& rm -rf .venv build dist # editable install, local venv, and build outputs
macOS desktop app (DMG / zip)
- Quit Kiro Crew from the menu bar or Dock.
- Drag KiroCrew.app from
/Applicationsto the Trash (orrm -rf).
There is no installer package or receipt to clean — the DMG is a drag-install.
Linux AppImage
Delete the AppImage file wherever you placed it:
rm -f ~/Applications/KiroCrew-x86_64.AppImage # or wherever you saved it
Windows (NSIS installer)
Use Settings → Apps → Installed apps, find "Kiro Crew", and click
Uninstall. The NSIS uninstaller removes the application directory and
shortcuts but does not touch ~/.kiro/crew.
Docker
docker stop kirocrew && docker rm kirocrew # graceful stop, then remove
docker rmi ghcr.io/kirodotdev/kirocrew:stable # remove the image (match the tag you pulled)
docker stop sends SIGTERM and gives the gateway time to run its shutdown
flush; docker rm -f sends SIGKILL immediately, which can drop up to one
5-second flush interval of recent session state.
Removing user data
Uninstalling via any method above leaves your data home intact. To also remove all user data:
# Back up first — this is irreversible. `kirocrew snapshot` only captures
# memory/config/skills/workspace, not `.env`, credentials, or installed apps,
# so a full copy of the data home is the only complete backup. Chained with
# `&&` so a failed copy (e.g. disk full) blocks the delete rather than racing
# ahead of it. Point the copy at a location you control OUTSIDE the data home:
cp -a "${KIROCREW_HOME:-$HOME/.kiro/crew}" ~/kirocrew-backup \
&& rm -rf "${KIROCREW_HOME:-$HOME/.kiro/crew}"
The backup is a full copy of your credentials (.env), signing keys, and
session data, and it does NOT inherit the agent's path protections that guard
the live data home — store it somewhere the agent cannot reach and delete it
once the reinstall is confirmed good.
This deletes configuration, credentials (.env), session history, memory
databases, installed apps, and the embedding model cache.
Docker: the commands above target a host data home. A Docker install keeps everything in the
kirocrew-homenamed volume instead, so remove that rather than~/.kiro/crew:docker volume rm kirocrew-home(ordocker compose down -v).
Note: App Kit data is preserved per-app by default. To remove an individual app's data before or instead of purging the whole home:
kirocrew app uninstall NAME --purge-data
Clean reinstall
A clean reinstall removes both the binary and the data home, then installs
fresh. Use this when kirocrew doctor reports issues that setup cannot fix,
or when you want a completely fresh start.
# 1. Stop any running gateway, then remove the service
kirocrew stop # stop a foreground gateway (service uninstall won't)
kirocrew service uninstall 2>/dev/null
# 2. Uninstall the binary (use the matching command from above)
pipx uninstall kirocrew # or: pip uninstall kirocrew, rm the AppImage, etc.
# 3. Back up and remove the data home (chained so a failed copy blocks the delete)
cp -a "${KIROCREW_HOME:-$HOME/.kiro/crew}" ~/kirocrew-backup \
&& rm -rf "${KIROCREW_HOME:-$HOME/.kiro/crew}"
# 4. Reinstall
curl -fsSL https://download.crew.kiro.dev/cli.sh | sh
# 5. Run first-time setup
kirocrew setup
kirocrew doctor
Replace step 4 with your preferred install method (pip wheel, source build, desktop app) as described in the Install paths section above.
Data retention details
For reference, the data home structure and what each uninstall path touches:
kirocrew service uninstallremoves only the systemd unit (plus the AppArmor profile it installed) or the launchd plist.- Python and npm package removal has no
preuninstallorpostuninstallcleanup hook. - The macOS DMG/zip and the Linux AppImage have no cleanup hook, so removing the application bundle or image leaves the data home intact.
- A Linux
.deb/.rpmremoval DOES run the package's own post-remove step, which drops/usr/bin/kirocrew-desktopand the installed AppArmor profile. It deliberately leaves the data home alone:~/.kiro/crewholds your sessions, memory and credentials, so it is yours to remove (see Removing user data), not the package manager's. - App Kit uninstall preserves
apps/<name>/data/by default. Deleting that app data is a separate, explicit action:kirocrew app uninstall NAME --purge-data, or unchecking Keep app data in the confirmation dialog.
Windows NSIS uninstaller behavior. nsis.oneClick is false and
nsis.deleteAppDataOnUninstall is left false, so the uninstaller removes only
the application install directory and its shortcuts; it never resolves or removes
the Kiro Crew home, which lives outside the install directory. Each signed Windows
installer must pass an install, create-sentinel-under-~/.kiro/crew,
uninstall, verify-sentinel smoke test before release. A separate Kiro-family
uninstaller could remove the parent ~/.kiro/ directory; it must exclude
~/.kiro/crew or prompt explicitly. That release-blocking cross-product
sign-off is tracked in
issue #355.
Next steps
- Slack setup: create and configure the Slack app.
- Other channels: Discord, Telegram, Teams, Webex, WeCom, WeChat, and WhatsApp.
- Remote and mobile access: 24/7 operation on a remote host, and reaching the dashboard from a phone.
- Architecture overview: system diagrams and the component map.
- Security deep dive: sandbox, governance, and denied commands.
- App Kit guide: build apps that extend Kiro Crew.
- CONTRIBUTING.md: development setup and the PR workflow.