Loading image...Kiro

Product

  • About Kiro
  • IDE
  • CLI
  • Web
  • Mobile
  • Crew
  • Pricing
  • Downloads

For

  • Enterprise
  • Startups
  • Students

Community

  • Overview
  • Ambassadors
  • Discord
  • Events
  • Powers
  • Shop
  • Showcase

Resources

  • Docs
  • Blog
  • Changelog
  • FAQs
  • Report a bug
  • Suggest an idea
  • Billing support

Social

Site TermsLicenseResponsible AI PolicyLegalPrivacy PolicyCookie Preferences
Loading image...Kiro
  • Enterprise
  • Pricing
  • Docs
SIGN INDOWNLOADS
Loading image...Kiro

Get Started

InstallationAuthenticationYour first project

Models

OverviewAvailable modelsReasoning effort

Features

How Kiro works
Specs
Steering
Hooks
MCP
Permissions
Custom agents
Agent Skills
Powers
CompactionKiroignoreCheckpoints and rewind
Built-in tools
Configuration scopes

IDE 1.x

What's new in 1.0
Setup & First Run
Editor
Chat
Experimental
Troubleshooting0.x reference

CLI

What's new in 3.0
Setup & First Run
Terminal UI
Chat
Headless modeACPAuto complete
Experimental
2.x reference

Crew

Quick startInstallationRunning 24/7
Chat
Agent Capabilities
Features
Subagents
Scheduling
Artifacts
Multi-instance
Task Runner
Memory
Knowledge
Snapshot & restore
Interfaces
Apps
ConfigurationSecurityTroubleshooting

Web - Preview

Setup & First RunIdentity Center
Connect your repositories
Working with the agent
Autonomous modeAutomations
Sandbox

Mobile - Preview

Overview

Commands and Reference

CLI commandsSlash commandsBuilt-in toolsExit codesSettingsIDE keyboard shortcuts

Billing

OverviewManaging your subscriptionUpgrading your planDowngrading your planCancelling your planPurchasing add-on creditsManaging your paymentsManaging usage notificationsManaging your taxesContacting billing supportDeleting your accountRelated questions

Enterprise

ConceptsOnboarding quickstart
Connecting your identity provider
Subscribe your teamManage subscriptions
Governance
Monitor and track
SettingsManaged updatesBillingIAMSupported regions

Privacy and Security

OverviewData protectionCode referencesCompliance validationInfrastructure securityIAM permissionsFirewalls, proxies, and data perimetersVPC endpoints (AWS PrivateLink)

Guides

Overview
Language support
Learn by playing

Migration

Migrating from Q DeveloperMigrating from VSCodeUpgrading from Q CLI
  1. Docs
  2. Crew
  3. Features
  4. Multi-instance

Multi-instance


Run Crew on several remote hosts — dev boxes, EC2 instances, home servers — and drive them all from one hub gateway. Multi-instance opens SSH tunnels to each remote, mints short-lived dashboard tokens, and embeds each remote dashboard in a tab strip. The most-recently-used instances stay warm; the rest reconnect on demand.

Opt-in. Off by default.

Enable it

bash
kirocrew config set instances.enabled true kirocrew restart

When enabled, the gateway:

  1. Creates the instances registry + SshTunnelManager
  2. Scopes a CSP frame-src relaxation to the active loopback tunnel ports (so embedded remote dashboards can render — they're otherwise blocked by the strict frame-src 'self' blob:)

With the flag off, /api/instances/* returns 403 and the /instances page shows an opt-in hint.

How it works

┌── Hub gateway (this host) ──┐ │ /instances page (React) │ │ ├─ tab strip: Home · A · B │ │ ├─ warm <iframe>s per tab │ http://127.0.0.1:<local_port>/?token=… │ └─ Manage panel │ add / connect / diagnose / restart / remove │ │ │ instances/ package │ │ ├─ registry │ ~/.kiro/crew/instances.json │ ├─ port_allocator │ loopback ports from base 7778 │ ├─ token_mint │ ssh <host> kirocrew token → JWT (never logged) │ ├─ ssh_tunnel_manager │ supervised ssh -N -L, probe, self-heal, refresh │ └─ diagnostics │ ssh → remote-dashboard → local-forward ladder └──────────────────────────────┘ │ ssh -N -L 127.0.0.1:<local>:127.0.0.1:<remote> ▼ ┌── Remote gateway ────────────┐ │ kirocrew gateway bound to │ │ 127.0.0.1:<remote_port> │ └──────────────────────────────┘

Each instance you add produces a supervised ssh -N -L child. The tunnel forwards 127.0.0.1:<local> → remote 127.0.0.1:<remote>. The hub mints a dashboard token on the remote over SSH and embeds the remote dashboard in an iframe at the loopback URL.

The lifecycle

  1. Connect — POST /api/instances/{id}/connect allocates a loopback port, mints a token on the remote over SSH, starts ssh -N -L, waits until the local forward accepts a connection, then returns the live status
  2. Warm set — up to warm_set_cap (default 5) most-recently-used instances stay warm with a live tunnel + WebSocket. Connecting beyond the cap lazily evicts the least-recently-used
  3. Health probe — while connected, a probe polls the loopback forward every 30 s; after 3 consecutive failures it tears the child down so recovery fires
  4. 2-tier self-heal — on unexpected exit: tier 1 rebuilds the tunnel reusing the existing token; tier 2 re-mints the token then rebuilds. Capped at 8 attempts with capped-exponential backoff (~2 min window)
  5. Proactive token refresh — a per-instance loop re-mints the token at 0.8 of its TTL, ahead of the ~20h cap
  6. Diagnose / restart — ?diagnose=1 runs a failure-probe ladder on demand; POST .../restart restarts the remote gateway over SSH

Adding an instance

Open Instances in the dashboard, click Add, fill in:

FieldDescription
NameAny label (e.g. "Dev box 1")
SSH host / aliasWhat you'd type after ssh — see below
Remote portRemote gateway's port (default 7777)
Token TTLDefault 20 h

The ssh_host field accepts:

  • A hostname or FQDN (dev-1.example.com)
  • A user + host (ec2-user@10.0.1.5)
  • An SSH config alias (my-ec2)

Any option starting with - is rejected (injection guard).

Remote host types

The only per-remote knob is ssh_host. Anything ssh can reach non-interactively works.

Dev host / home server

Use your SSH config alias or user@hostname. As long as a key in your ssh-agent covers auth, BatchMode succeeds without prompting.

EC2 and other key-based hosts

Configure an SSH alias in ~/.ssh/config on the hub, then reference the alias:

Host my-ec2 HostName ec2-1-2-3-4.compute-1.amazonaws.com User ec2-user IdentityFile ~/.ssh/my-key.pem # Optional: reach a private instance through a bastion ProxyJump bastion-host # Or via SSM Session Manager: # ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p"

Then add an instance with my-ec2 as the SSH host.

Prerequisites on the hub:

  • A passphrase-less key or an ssh-agent holding it (BatchMode won't prompt)
  • kirocrew installed and a gateway running on the EC2 instance's loopback port

What's supported

NeedStatusHow
Custom login user✅user@host or ssh-config User
FQDN / IP✅direct ssh_host value
Identity file (-i)⚠️ via ssh config onlyIdentityFile in a Host block
Non-22 SSH port⚠️ via ssh config onlyPort in a Host block
Bastion / ProxyJump⚠️ via ssh config onlyProxyJump / ProxyCommand
SSM-only instances⚠️ via ssh config onlyProxyCommand with aws ssm start-session

Managing instances

The Manage panel gives you these per-instance actions:

  • Connect — open a tunnel + iframe
  • Disconnect — tear down the tunnel
  • Diagnose — run the failure-probe ladder and report the first broken link
  • Restart — restart the remote gateway over SSH (service-aware)
  • Edit — change name / host / port / TTL
  • Remove — disconnect then delete

Security model

Every route in /api/instances/* is gated by _guard():

  • Deny-by-default — reject Slack-origin requests (403)
  • Owner-only — require request["user"] (authenticated dashboard session)
  • Feature-gated — require instances.enabled: true
  • SEL-audited — every call (success and denial) emits an audit event

Beyond the guard:

  • Loopback-only forwards — ssh -N -L 127.0.0.1:<local>:127.0.0.1:<remote>
  • No local shell — ssh is always invoked with an argv list; ssh_host cannot inject local shell syntax
  • Charset-validated inputs — ssh_host and remote_bin rejected if they contain shell metacharacters or lead with -
  • Short-lived tokens — ≤20 h, returned only in-memory to the caller, never logged, never in list/status payloads
  • postMessage origin check — the parent validates every embedded-frame event.origin against the exact http://127.0.0.1:<port> of a currently-warm tunnel before trusting an unread-count message

Configuration

Under instances.*:

KeyDefaultMeaning
instances.enabledfalseMaster opt-in
instances.warm_set_cap5Max instances kept warm at once
instances.tunnel_base_port7778First local loopback port for ssh -L
instances.max_recovery_attempts8Consecutive self-heal attempts before giving up
instances.recover_backoff_max_secs30Cap on exponential backoff between self-heal attempts
instances.probe_failure_threshold3Consecutive probe failures before triggering recovery

Troubleshooting

SymptomFix
/instances shows "multi-instance management is off"instances.enabled is false — set it and restart
Iframe is blankCSP frame-src relaxation only applies to active tunnel ports; ensure the instance is connected
Connect fails with SSH auth errorRefresh your SSH credentials (re-add key to ssh-agent); tunnels self-heal once SSH is restored
Connect failsUse Diagnose — the ladder reports the first broken link (ssh_unreachable, remote_down, or tunnel_down)
Instance keeps droppingHealth probe + 2-tier self-heal retry over ~2 min; if it gives up, diagnosis runs automatically. Check the remote gateway and SSH stability
An instance silently disappeared from the warm setLRU-evicted (warm set full). Raise instances.warm_set_cap or reconnect on demand
Page updated: August 4, 2026
Artifacts
Task Runner