Files
kandev/apps/backend/internal/agentruntime/runtime.go
T
José Almeida 99404133d4 feat(backend): add SSH executor runtime
Run agents on any Linux box reachable over SSH: own VPS, homelab, EC2,
shared dev box. One SSH connection per (host, user, identity) shared
across all sessions on that host; each session gets its own remote
agentctl process, remote port, and SSH-tunneled local port. Mirrors the
local ~/.kandev/tasks/<task-dir>/<repo>/ layout on the remote so
multi-session tasks share a worktree and per-session runtime state lives
under the task dir.

Implements ExecutorBackend + RemoteSessionResumer + RemoteStatusProvider
+ Closeable. Host-key trust is explicit: the test endpoint observes a
fingerprint without pinning; the user trusts it in settings; subsequent
connects reject any mismatch. Auth via ssh-agent or IdentityFile only
(passphrase-protected keys must be loaded into ssh-agent). Parses
~/.ssh/config for HostName/Port/User/IdentityFile/ProxyJump inheritance.
agentctl is content-hash-cached on the remote (~/.kandev/bin/agentctl
plus a .sha256 sidecar) and uploaded only when local and remote differ.
Linux/amd64 only in v1, matching Docker's current state; arm64 is
called out as a cross-cutting follow-up.

See docs/specs/ssh-executor/spec.md.
2026-05-17 23:28:50 +01:00

36 lines
1.2 KiB
Go

// Package agentruntime defines the execution-environment taxonomy
// for kandev agents — the runtime backend that hosts an agent
// subprocess and its observable properties. It is a leaf package
// so any layer (task models, registry, lifecycle, individual agent
// implementations) can speak the same vocabulary without cycles.
package agentruntime
// Runtime identifies the execution backend that hosts an agent
// subprocess. Values match historical executor.Name strings so
// existing on-disk records (ExecutorRunning.RuntimeName) remain
// compatible.
type Runtime string
const (
RuntimeStandalone Runtime = "standalone"
RuntimeDocker Runtime = "docker"
RuntimeRemoteDocker Runtime = "remote_docker"
RuntimeSprites Runtime = "sprites"
RuntimeSSH Runtime = "ssh"
)
// IsContainerized reports whether the runtime hosts the agent
// subprocess inside a filesystem-isolated container/sandbox.
// Adding a runtime that returns true is the single place that
// decision gets reviewed; new constants default to host-mode.
func (r Runtime) IsContainerized() bool {
switch r {
case RuntimeDocker, RuntimeRemoteDocker, RuntimeSprites:
return true
default:
return false
}
}
func (r Runtime) String() string { return string(r) }