Long-lived crush agents running as Kubernetes Deployments. One operator. Many drones. One shared link - the vinculum.
“The processing device at the core of every Borg vessel. It interconnects the minds of all the drones. It purges individual thoughts and disseminates information relevant to the Collective.”
“It brings order to chaos.”
– Seven of Nine and Kathryn Janeway
Spinning up a fresh pod for every prompt is wasteful. Vinculum runs each Agent as a long-lived pod with an open crush session and a persistent workspace - so context survives, PVCs survive, and cold-start disappears.
A pod per Agent - no per-prompt cold-start. Crush session + /workspace PVC survive restarts.
Declarative Agent, Task, AgentSchedule, MCPServer CRDs. One operator reconciles them into Deployments, PVCs, RBAC, Services.
Azure OpenAI, Anthropic, OpenAI, or bring-your-own - a provider is just a labeled Secret.
Port-forwards through your active kubecontext - no exposed operator endpoint, no long-lived local state.
Six CRDs. Everything else is derived.
Long-running agent drone. Model, provider secret ref, instructions, workspace size, attached MCP servers, orchestrator + peer flags. Operator creates Deployment, Service, PVC, RBAC.
A unit of work. Prompt, fresh, workspace mode (shared or ephemeral), timeout, artifacts, env. Serial execution per Agent.
Async chat between Agents. to, body, optional inReplyTo for threads. Browsable via kubectl get messages — replies arrive as new Messages, not return values.
Cron trigger that stamps Tasks from a template. Concurrency policy: Allow, Forbid, Replace.
Reusable Model Context Protocol server - stdio or http. Attach by name to any Agent. secretRef wired as envFrom.
Inbound GitHub webhooks turned into Tasks. HMAC-verified, event/branch-filtered, with ${event.*} template substitution into the rendered Task.
Any Kubernetes cluster. Any active context. Helm chart + Homebrew CLI.
Helm OCI install - no repo add, no values overrides required for a default run.
helm install vinculum oci://ghcr.io/florianwenzel/helm/vinculum \ --version 0.6.0 \ -n vinculum-system --create-namespace
Homebrew tap for macOS + Linux. Prebuilt binaries available for all platforms on every release.
brew install FlorianWenzel/vinculum/vnclm
Drop API keys into a labeled Secret. Wizard handles the labeling + encoding.
vnclm create provider # interactive wizard
Pick a model, point at a provider, optionally attach MCP servers. Operator provisions the pod.
vnclm create agent # wizard
Streams live. Blocks until terminal phase. Run again later - crush picks up the session, history intact.
vnclm ctx set-agent locutus vnclm run "Compose a haiku about the Borg collective."
kubectl-shaped verbs. Interactive wizards. Per-invocation port-forward. No exposed endpoints.
vnclm ctx show | set-agent <name> | clear-agent vnclm get agents|tasks|schedules|providers|mcps [name] [-o table|wide|json|yaml] vnclm delete <kind> <name> [--yes] vnclm create provider|agent|task|schedule|mcp # wizard vnclm create -f manifest.yaml # apply (multi-doc) vnclm logs <task> [-f] vnclm run "<prompt>" [--agent] [--fresh] [--timeout N]
Declare a repo on the Agent and a branch / PR on the Task. The operator clones on pod start; the agent wraps each crush run with the git workflow — fetch, branch, commit, push, and (for GitHub) open a PR via the REST API.
git-clone init container that hydrates /workspace/<path> on pod start. Cached on the PVC; restarts just git fetch --prune.id_ed25519) and/or an HTTPS token. Either, both, or neither.baseBranch, headBranch, commitMessage, prTitle, prBody, skipPR — all optional, sensible defaults.Succeeded with reason=NoChanges. No branch, no commit, no PR — no noise.# Agent — clones acme/api on pod start, authenticates with a PAT apiVersion: vinculum.dev/v1alpha1 kind: Agent metadata: name: coder spec: model: openrouter/anthropic/claude-sonnet-4.6 providerSecretRef: { name: openrouter-provider-keys } repo: url: https://github.com/acme/api.git branch: main path: app gitCredentials: tokenSecretRef: { name: acme-github-pat } userName: "Vinculum Bot" userEmail: "bot@acme.test" --- # Task — implement a feature, ship a PR apiVersion: vinculum.dev/v1alpha1 kind: Task metadata: name: add-v2-health spec: agentRef: coder prompt: "Add a /v2/health endpoint that returns {status:'ok'}." git: baseBranch: main headBranch: feat/v2-health commitMessage: "feat: add /v2/health endpoint" prTitle: "Add /v2/health endpoint"
Or from the CLI vnclm run "implement /v2/health" --base-branch main --head-branch feat/v2-health --pr-title "Add /v2/health". skipPR: true commits + pushes without opening a PR — for GitLab / Bitbucket / self-hosted hosts.
Flip orchestrator: true on any Agent and it becomes a master. A stdio MCP server baked into the image — vnclm-mcp — wires the operator's in-cluster API into the running crush session, so the LLM can decompose work and farm it out to peer drones.
stdoutTail / stderrTail / exitCode.Succeeded / Failed / TimedOut, or hit timeoutSeconds.# bundled stdio MCP — the binary ships in the agent image apiVersion: vinculum.dev/v1alpha1 kind: MCPServer metadata: name: vinculum spec: command: vnclm-mcp enabled: true --- # worker — runs whatever locutus delegates to it apiVersion: vinculum.dev/v1alpha1 kind: Agent metadata: name: drone-7 spec: model: openrouter/anthropic/claude-haiku-4.5 providerSecretRef: { name: openrouter-provider-keys } --- # master — orchestrator flag flips on VINCULUM_OPERATOR_URL + the MCP apiVersion: vinculum.dev/v1alpha1 kind: Agent metadata: name: locutus spec: orchestrator: true model: openrouter/anthropic/claude-sonnet-4.6 providerSecretRef: { name: openrouter-provider-keys } mcpServerRefs: [vinculum]
Trust boundary The operator's in-cluster API has no auth — the namespace is the trust boundary. The orchestrator flag gates env injection, not network reachability. Isolate orchestrators in their own namespace when stricter separation matters.
Orchestrators dispatch work. Peers exchange messages. Every Agent ships with peer: true by default — the bundled MCP exposes a tiny async chat surface so a dev drone can ask a PO drone "how should I proceed?" or a QA drone can poke a dev drone about its PR. Conversations are first-class K8s resources: kubectl get messages lists every back-and-forth, and replies thread via inReplyTo.
inReplyTo to thread; pass name to control the resource ID.vinculum.dev/role label.status.replyMessages lists every Message that set inReplyTo to it — the thread, both directions.# Bundled vinculum MCP — wires send_message into each drone's crush session apiVersion: vinculum.dev/v1alpha1 kind: MCPServer metadata: { name: vinculum } spec: { command: vnclm-mcp, enabled: true } --- # peer: true is the schema default — no orchestrator flag needed apiVersion: vinculum.dev/v1alpha1 kind: Agent metadata: { name: dev-7 } spec: model: openrouter/anthropic/claude-sonnet-4.6 providerSecretRef: { name: openrouter-provider-keys } mcpServerRefs: [vinculum] --- apiVersion: vinculum.dev/v1alpha1 kind: Agent metadata: { name: qa-3 } spec: model: openrouter/anthropic/claude-haiku-4.5 providerSecretRef: { name: openrouter-provider-keys } mcpServerRefs: [vinculum]
Async by design No await_reply. When peer-b replies to peer-a's message, the reply lands as a fresh inbound Message that fires a new crush turn on peer-a — the way a teammate's Slack ping wakes you up. To opt out entirely, set peer: false on the Agent.
A WebhookTrigger turns inbound GitHub webhooks into Tasks. The operator verifies the HMAC signature against a per-trigger Secret, matches the event against your filter, substitutes ${event.*} placeholders into the task template, and stamps the Task. Open a PR — your review agent commits its read.
apiVersion: vinculum.dev/v1alpha1 kind: WebhookTrigger metadata: name: acme-pr-review spec: source: github events: [pull_request.opened, pull_request.synchronize] filter: repo: acme/api branch: main secretRef: { name: acme-gh-webhook } # key "secret" = HMAC shared secret agentRef: coder taskTemplate: prompt: "Review PR #${event.pr.number} (${event.pr.title})." fresh: true git: baseBranch: ${event.pr.head} headBranch: review/pr-${event.pr.number} prTitle: "review: PR #${event.pr.number}"
Exposure The operator's /webhook/github is on the same in-cluster Service as the rest of the API. Wire your own Ingress / tunnel / LB — vinculum doesn't bake one in so you stay in control of TLS, hostnames, and any extra auth.
Give agents extra tools by declaring MCPServer resources - stdio processes or HTTP endpoints - and attaching them by reference. One MCPServer, many agents.
# stdio MCP - filesystem over the agent's /workspace PVC vnclm create mcp --name filesystem --command npx \ --arg -y --arg @modelcontextprotocol/server-filesystem --arg /workspace \ --enabled # http MCP with a secret injected as envFrom vnclm create mcp --name github --url https://api.githubcopilot.com/mcp/ \ --secret-ref github-mcp --enabled vnclm create agent # wizard → multiselect attaches MCPs