简体中文 · English
A self-hosted control plane for a team's personal AI agents.
AgentKin shows which personal agents are reachable and lets a teammate ask them questions. Endpoint machines make outbound connections to a self-hosted NATS JetStream broker, so they need no public inbound port, Tailscale, or third-party identity provider.
flowchart LR
UI["Browser"] --> API["AgentKin control plane"]
API --> DB["Persistent task store"]
API <--> NATS["NATS JetStream"]
NATS <--> C1["Connector: member A"]
NATS <--> C2["Connector: member B"]
C1 --> A1["Local OpenAI-compatible agent"]
C2 --> A2["Local OpenAI-compatible agent"]
JetStream persists device-scoped tasks and events. A Connector acknowledges a task only after its result is accepted by the broker. Heartbeats expire after 90 seconds. The initial adapter works with OpenClaw and other OpenAI-compatible local endpoints.
| Component | Control plane / server | Endpoint machine |
|---|---|---|
| AgentKin web/API | Required | No |
| NATS JetStream | Required (one central deployment) | No |
| AgentKin Connector | No | Required |
| Node.js 22+ | Required | Required |
| OpenClaw or compatible agent | No | Required |
The control-plane machine does not need OpenClaw unless it also acts as an endpoint.
docker compose up -d natsThe included password is development-only. Change it in deploy/nats/nats-server.conf and use TLS plus per-Connector users before exposing the broker.
npm install
Copy-Item config\members.example.json config\members.json
$env:NATS_URL = "nats://127.0.0.1:4222"
$env:NATS_USER = "agentkin"
$env:NATS_PASSWORD = "replace-with-a-strong-password"
npm run serverOpen http://127.0.0.1:4310.
Run on the endpoint machine:
npm install
$env:NATS_URL = "nats://your-server:4222"
$env:NATS_USER = "agentkin"
$env:NATS_PASSWORD = "replace-with-a-strong-password"
$env:AGENTKIN_MEMBER_ID = "xiaowang"
$env:AGENTKIN_CONNECTOR_ID = "xiaowang-laptop"
$env:AGENT_BASE_URL = "http://127.0.0.1:18789"
$env:AGENT_TOKEN = "local-agent-token"
$env:AGENT_MODEL = "openclaw/main"
npm run connectorThe Connector only calls the loopback agent endpoint. It sends questions and answers through your NATS server.
- Put NATS behind TLS/WSS on port 443 when endpoint networks restrict custom ports.
- Issue a separate credential for each Connector and restrict it to that member's task, result, and heartbeat subjects.
- Keep the monitoring port
8222bound to localhost. - Restrict local agent tools; require approval for shell, file writes, external messages, and destructive actions.
- Back up the NATS JetStream volume and the control plane
data/tasks.json. - Do not place tokens, credentials, questions, or answers in Git.
See SECURITY.md.
npm test
node --check src/server.js
node --check connector/main.jsWith a test broker configured through NATS_URL, NATS_USER, and NATS_PASSWORD:
npm run test:integrationThe transport boundary is isolated from task and HTTP logic so more agent adapters can be added without changing the control plane.
- Agent directory and heartbeat presence
- Durable JetStream task delivery
- Persistent task status and result polling
- OpenAI-compatible Connector adapter
- Device enrollment and automatic scoped credential issuance
- Human approval policies and audit UI
- Hermes, Claude Code, Cursor, MCP, and A2A adapters
- PostgreSQL storage for multi-instance deployments