Repository files navigation

CLRK

CLRK (we pronounce it as "clerk") is a Kubernetes-native runtime for LLM agents. It runs each agent in a gVisor sandbox and transparently intercepts all egress - LLM APIs, MCP, tool calls - without modifying agent code. That interception point gives you observability, policy enforcement, and routing-based cost control over agents you don't otherwise get to see inside.

CLRK egress control point

How it works

CLRK runs untrusted, framework-agnostic agent workloads in gVisor sandboxes. You describe an agent declaratively - a container image + a trigger + an egress policy - and CLRK schedules it onto a pool of sandbox workers. It brings its own scheduler, so agent startup isn't gated on pod-creation latency. Every byte in or out of the sandbox passes through a transparent proxy CLRK controls, so the platform sees and governs all LLM API calls, MCP traffic, and outbound tool calls without the agent code being aware of it. Yes, that includes TLS-encrypted connections.

The agent inside can be anything that makes HTTP(S) calls - a Python script using the OpenAI or Anthropic SDK, a Node MCP client, a shell one-liner. There is no required agent library; CLRK intercepts at the network and process boundary. See _examples/ for runnable agents (openai-bot, gemini-bot, cron-bot, jq-bot, MITM variants, and more).

Motivation

Running agents in production raises problems that general-purpose container orchestration does not solve on its own. CLRK is built to address them directly:

  • Observability. All I/O in and out of a sandbox is intercepted and logged, so LLM, MCP, and remote tool-call telemetry is auto-instrumented rather than bolted on per-framework.
  • Governance. Prevent sandbox escape and apply organization-wide policy (where an agent may connect, what credentials it may use) at the egress boundary.
  • Attribution. Tie agent loops back to the customer request or trigger that started them, captured as first-class Invocation records.
  • Zero-Trust Access. Give agents audited, authorized access to internal services instead of all-or-nothing network access.
  • Scalability. One model for both serverless bursts and long-lived "on-prem" Kubernetes fleets.
  • Reliability. Simple, robust retries, load-shedding, all outside of the Kubernetes control plane.

A deliberate design choice that follows from governance: credentials never live in the agent. API keys for AI providers, MCP servers, and internal services are injected by the egress MITM at request time, never via pod env, mounts, or args - so a compromised sandbox cannot exfiltrate them.

Architecture

CLRK ships two long-running binaries plus a CLI:

  • cmd/controller-manager - the control plane. Runs the controller-runtime reconcilers for the CRDs below and embeds an aggregated API server for the clrk.apoxy.dev group. Deployed as a Deployment on Kubernetes but can be run standalone. It also hosts UI dashboard.

  • cmd/worker - Manages sandbox lifecycle via gVisor/runsc, sets up per-sandbox network interception via our custom sentrystack plugin to be routed through the interception path. Linux-only (//go:build linux, CGO).

  • cmd/clrk - the operator/developer CLI: install, upgrade, dev, apply, get, logs, traces, status, run-task, context management, and a local-cluster dev loop.

Egress interception. Outbound traffic is captured transparently and sent through an EgressGateway - an Envoy-based data plane with TLS termination (MITM) and a custom filter. This is where telemetry is recorded, credentials are injected, and routing/governance policies (EgressL4Route, MCPRoute, AIProviderRoute, egress/credential/fallback-routing/logging/rate-limit policies) are applied.

Telemetry storage and export. Intercepted I/O becomes Invocation records backed by ClickHouse (via the ch-go driver) and can be consumed using /logs and /traces subresources as well as re-exported over OpenTelemetry sink.

TaskAgent vs DaemonAgentTaskAgent is for triggered, run-to-completion work (HTTP request or cron) multiplexed across shared worker pods. DaemonAgent is for long-lived agent processes with a restart policy.

APIs

CRDPurpose
TaskAgentShort-lived agent execution (request → sandbox → response)
DaemonAgentLong-lived agent process with restart policy
WorkerPoolFleet of worker pods (Deployment + Service)
EgressGatewayTransparent egress proxy with TLS termination modes
EgressL4RouteL4 egress routing rules
MCPRouteMCP protocol routing
AIProviderRouteAI-provider-specific egress routing
InvocationAttributed record of an intercepted agent call (ClickHouse-backed)

Repository layout

PathContents
api/clrk/v1alpha1/CRD types (Apache-2.0)
client/Generated Kubernetes clientset, listers, informers (Apache-2.0)
internal/controller/controller-runtime reconcilers
internal/worker/, internal/sandbox/sandbox lifecycle (Linux-only)
internal/eg*, internal/extproc/, internal/egress/Envoy egress data plane + interception
internal/clickhouse/, internal/chwriter/, internal/otel*telemetry storage and export
internal/install/, cmd/clrk/installer and CLI
codegen/code-generator config (update.sh, header boilerplate)

FAQ

Does my agent need to use a specific framework or SDK?

No. CLRK intercepts at the network and process boundary, so any agent that makes HTTP/S calls works. The provided examples use the OpenAI and Gemini SDKs, plain shell tools, and MCP clients.

Where do API keys live?

Not in the agent. Credentials are injected by the egress MITM at request time via a credential-injection policy - never in pod env, mounts, or args. A compromised sandbox has no secrets to leak. The secret material iself is safe and sound in a Kubernetes Secret.

How is the sandbox isolated?

Sandboxes run via gVisor (runsc) for a stronger syscall boundary, each in its own network namespace with all egress forced through the interception path.

Can I run it locally or do I need a Kubernetes cluster?

All batteries included! clrk dev brings up a local cluster and dev loop. This can also be used to run CLRK without a Kubernetes cluster nearby. clrk install / clrk upgrade manage a Kubernetes-based deployment.

Why are api/ and client/ licensed differently from the rest?

So you can build against the API and use the generated client without AGPL copyleft obligations. See License.

Where is CONTRIBUTING.md?

Currently, external contributions are not accepted. If you encounter a bug or have a feature request, please open an issue on the GitHub repository.

Was this tested? I can't find any tests!

We have tests, we swear! Currently they are coupled with our private build/test infrastructure and are not publicly available. We try to maintain minimum 70% unit test coverage and have integration tests for the public API.

Was this vibe-coded?

We rely on AI-assist but every output line is carefully reviewed and tested before being committed.

License

CLRK is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0); see LICENSE.

Exception: the api/ and client/ directories are licensed under the Apache License 2.0; see api/LICENSE and client/LICENSE. These cover the public API types (api/clrk/v1alpha1) and the generated Kubernetes client/SDK, so they can be imported and used without AGPL copyleft obligations.

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

CLRK

CLRK (we pronounce it as "clerk") is a Kubernetes-native runtime for LLM agents. It runs each agent in a gVisor sandbox and transparently intercepts all egress - LLM APIs, MCP, tool calls - without modifying agent code. That interception point gives you observability, policy enforcement, and routing-based cost control over agents you don't otherwise get to see inside.

CLRK egress control point

How it works

CLRK runs untrusted, framework-agnostic agent workloads in gVisor sandboxes. You describe an agent declaratively - a container image + a trigger + an egress policy - and CLRK schedules it onto a pool of sandbox workers. It brings its own scheduler, so agent startup isn't gated on pod-creation latency. Every byte in or out of the sandbox passes through a transparent proxy CLRK controls, so the platform sees and governs all LLM API calls, MCP traffic, and outbound tool calls without the agent code being aware of it. Yes, that includes TLS-encrypted connections.

The agent inside can be anything that makes HTTP(S) calls - a Python script using the OpenAI or Anthropic SDK, a Node MCP client, a shell one-liner. There is no required agent library; CLRK intercepts at the network and process boundary. See _examples/ for runnable agents (openai-bot, gemini-bot, cron-bot, jq-bot, MITM variants, and more).

Motivation

Running agents in production raises problems that general-purpose container orchestration does not solve on its own. CLRK is built to address them directly:

  • Observability. All I/O in and out of a sandbox is intercepted and logged, so LLM, MCP, and remote tool-call telemetry is auto-instrumented rather than bolted on per-framework.
  • Governance. Prevent sandbox escape and apply organization-wide policy (where an agent may connect, what credentials it may use) at the egress boundary.
  • Attribution. Tie agent loops back to the customer request or trigger that started them, captured as first-class Invocation records.
  • Zero-Trust Access. Give agents audited, authorized access to internal services instead of all-or-nothing network access.
  • Scalability. One model for both serverless bursts and long-lived "on-prem" Kubernetes fleets.
  • Reliability. Simple, robust retries, load-shedding, all outside of the Kubernetes control plane.

A deliberate design choice that follows from governance: credentials never live in the agent. API keys for AI providers, MCP servers, and internal services are injected by the egress MITM at request time, never via pod env, mounts, or args - so a compromised sandbox cannot exfiltrate them.

Architecture

CLRK ships two long-running binaries plus a CLI:

  • cmd/controller-manager - the control plane. Runs the controller-runtime reconcilers for the CRDs below and embeds an aggregated API server for the clrk.apoxy.dev group. Deployed as a Deployment on Kubernetes but can be run standalone. It also hosts UI dashboard.

  • cmd/worker - Manages sandbox lifecycle via gVisor/runsc, sets up per-sandbox network interception via our custom sentrystack plugin to be routed through the interception path. Linux-only (//go:build linux, CGO).

  • cmd/clrk - the operator/developer CLI: install, upgrade, dev, apply, get, logs, traces, status, run-task, context management, and a local-cluster dev loop.

Egress interception. Outbound traffic is captured transparently and sent through an EgressGateway - an Envoy-based data plane with TLS termination (MITM) and a custom filter. This is where telemetry is recorded, credentials are injected, and routing/governance policies (EgressL4Route, MCPRoute, AIProviderRoute, egress/credential/fallback-routing/logging/rate-limit policies) are applied.

Telemetry storage and export. Intercepted I/O becomes Invocation records backed by ClickHouse (via the ch-go driver) and can be consumed using /logs and /traces subresources as well as re-exported over OpenTelemetry sink.

TaskAgent vs DaemonAgentTaskAgent is for triggered, run-to-completion work (HTTP request or cron) multiplexed across shared worker pods. DaemonAgent is for long-lived agent processes with a restart policy.

APIs

CRDPurpose
TaskAgentShort-lived agent execution (request → sandbox → response)
DaemonAgentLong-lived agent process with restart policy
WorkerPoolFleet of worker pods (Deployment + Service)
EgressGatewayTransparent egress proxy with TLS termination modes
EgressL4RouteL4 egress routing rules
MCPRouteMCP protocol routing
AIProviderRouteAI-provider-specific egress routing
InvocationAttributed record of an intercepted agent call (ClickHouse-backed)

Repository layout

PathContents
api/clrk/v1alpha1/CRD types (Apache-2.0)
client/Generated Kubernetes clientset, listers, informers (Apache-2.0)
internal/controller/controller-runtime reconcilers
internal/worker/, internal/sandbox/sandbox lifecycle (Linux-only)
internal/eg*, internal/extproc/, internal/egress/Envoy egress data plane + interception
internal/clickhouse/, internal/chwriter/, internal/otel*telemetry storage and export
internal/install/, cmd/clrk/installer and CLI
codegen/code-generator config (update.sh, header boilerplate)

FAQ

Does my agent need to use a specific framework or SDK?

No. CLRK intercepts at the network and process boundary, so any agent that makes HTTP/S calls works. The provided examples use the OpenAI and Gemini SDKs, plain shell tools, and MCP clients.

Where do API keys live?

Not in the agent. Credentials are injected by the egress MITM at request time via a credential-injection policy - never in pod env, mounts, or args. A compromised sandbox has no secrets to leak. The secret material iself is safe and sound in a Kubernetes Secret.

How is the sandbox isolated?

Sandboxes run via gVisor (runsc) for a stronger syscall boundary, each in its own network namespace with all egress forced through the interception path.

Can I run it locally or do I need a Kubernetes cluster?

All batteries included! clrk dev brings up a local cluster and dev loop. This can also be used to run CLRK without a Kubernetes cluster nearby. clrk install / clrk upgrade manage a Kubernetes-based deployment.

Why are api/ and client/ licensed differently from the rest?

So you can build against the API and use the generated client without AGPL copyleft obligations. See License.

Where is CONTRIBUTING.md?

Currently, external contributions are not accepted. If you encounter a bug or have a feature request, please open an issue on the GitHub repository.

Was this tested? I can't find any tests!

We have tests, we swear! Currently they are coupled with our private build/test infrastructure and are not publicly available. We try to maintain minimum 70% unit test coverage and have integration tests for the public API.

Was this vibe-coded?

We rely on AI-assist but every output line is carefully reviewed and tested before being committed.

License

CLRK is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0); see LICENSE.

Exception: the api/ and client/ directories are licensed under the Apache License 2.0; see api/LICENSE and client/LICENSE. These cover the public API types (api/clrk/v1alpha1) and the generated Kubernetes client/SDK, so they can be imported and used without AGPL copyleft obligations.

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CLRK

CLRK (we pronounce it as "clerk") is a Kubernetes-native runtime for LLM agents. It runs each agent in a gVisor sandbox and transparently intercepts all egress - LLM APIs, MCP, tool calls - without modifying agent code. That interception point gives you observability, policy enforcement, and routing-based cost control over agents you don't otherwise get to see inside.

CLRK egress control point

How it works

CLRK runs untrusted, framework-agnostic agent workloads in gVisor sandboxes. You describe an agent declaratively - a container image + a trigger + an egress policy - and CLRK schedules it onto a pool of sandbox workers. It brings its own scheduler, so agent startup isn't gated on pod-creation latency. Every byte in or out of the sandbox passes through a transparent proxy CLRK controls, so the platform sees and governs all LLM API calls, MCP traffic, and outbound tool calls without the agent code being aware of it. Yes, that includes TLS-encrypted connections.

The agent inside can be anything that makes HTTP(S) calls - a Python script using the OpenAI or Anthropic SDK, a Node MCP client, a shell one-liner. There is no required agent library; CLRK intercepts at the network and process boundary. See _examples/ for runnable agents (openai-bot, gemini-bot, cron-bot, jq-bot, MITM variants, and more).

Motivation

Running agents in production raises problems that general-purpose container orchestration does not solve on its own. CLRK is built to address them directly:

  • Observability. All I/O in and out of a sandbox is intercepted and logged, so LLM, MCP, and remote tool-call telemetry is auto-instrumented rather than bolted on per-framework.
  • Governance. Prevent sandbox escape and apply organization-wide policy (where an agent may connect, what credentials it may use) at the egress boundary.
  • Attribution. Tie agent loops back to the customer request or trigger that started them, captured as first-class Invocation records.
  • Zero-Trust Access. Give agents audited, authorized access to internal services instead of all-or-nothing network access.
  • Scalability. One model for both serverless bursts and long-lived "on-prem" Kubernetes fleets.
  • Reliability. Simple, robust retries, load-shedding, all outside of the Kubernetes control plane.

A deliberate design choice that follows from governance: credentials never live in the agent. API keys for AI providers, MCP servers, and internal services are injected by the egress MITM at request time, never via pod env, mounts, or args - so a compromised sandbox cannot exfiltrate them.

Architecture

CLRK ships two long-running binaries plus a CLI:

  • cmd/controller-manager - the control plane. Runs the controller-runtime reconcilers for the CRDs below and embeds an aggregated API server for the clrk.apoxy.dev group. Deployed as a Deployment on Kubernetes but can be run standalone. It also hosts UI dashboard.

  • cmd/worker - Manages sandbox lifecycle via gVisor/runsc, sets up per-sandbox network interception via our custom sentrystack plugin to be routed through the interception path. Linux-only (//go:build linux, CGO).

  • cmd/clrk - the operator/developer CLI: install, upgrade, dev, apply, get, logs, traces, status, run-task, context management, and a local-cluster dev loop.

Egress interception. Outbound traffic is captured transparently and sent through an EgressGateway - an Envoy-based data plane with TLS termination (MITM) and a custom filter. This is where telemetry is recorded, credentials are injected, and routing/governance policies (EgressL4Route, MCPRoute, AIProviderRoute, egress/credential/fallback-routing/logging/rate-limit policies) are applied.

Telemetry storage and export. Intercepted I/O becomes Invocation records backed by ClickHouse (via the ch-go driver) and can be consumed using /logs and /traces subresources as well as re-exported over OpenTelemetry sink.

TaskAgent vs DaemonAgentTaskAgent is for triggered, run-to-completion work (HTTP request or cron) multiplexed across shared worker pods. DaemonAgent is for long-lived agent processes with a restart policy.

APIs

CRDPurpose
TaskAgentShort-lived agent execution (request → sandbox → response)
DaemonAgentLong-lived agent process with restart policy
WorkerPoolFleet of worker pods (Deployment + Service)
EgressGatewayTransparent egress proxy with TLS termination modes
EgressL4RouteL4 egress routing rules
MCPRouteMCP protocol routing
AIProviderRouteAI-provider-specific egress routing
InvocationAttributed record of an intercepted agent call (ClickHouse-backed)

Repository layout

PathContents
api/clrk/v1alpha1/CRD types (Apache-2.0)
client/Generated Kubernetes clientset, listers, informers (Apache-2.0)
internal/controller/controller-runtime reconcilers
internal/worker/, internal/sandbox/sandbox lifecycle (Linux-only)
internal/eg*, internal/extproc/, internal/egress/Envoy egress data plane + interception
internal/clickhouse/, internal/chwriter/, internal/otel*telemetry storage and export
internal/install/, cmd/clrk/installer and CLI
codegen/code-generator config (update.sh, header boilerplate)

FAQ

Does my agent need to use a specific framework or SDK?

No. CLRK intercepts at the network and process boundary, so any agent that makes HTTP/S calls works. The provided examples use the OpenAI and Gemini SDKs, plain shell tools, and MCP clients.

Where do API keys live?

Not in the agent. Credentials are injected by the egress MITM at request time via a credential-injection policy - never in pod env, mounts, or args. A compromised sandbox has no secrets to leak. The secret material iself is safe and sound in a Kubernetes Secret.

How is the sandbox isolated?

Sandboxes run via gVisor (runsc) for a stronger syscall boundary, each in its own network namespace with all egress forced through the interception path.

Can I run it locally or do I need a Kubernetes cluster?

All batteries included! clrk dev brings up a local cluster and dev loop. This can also be used to run CLRK without a Kubernetes cluster nearby. clrk install / clrk upgrade manage a Kubernetes-based deployment.

Why are api/ and client/ licensed differently from the rest?

So you can build against the API and use the generated client without AGPL copyleft obligations. See License.

Where is CONTRIBUTING.md?

Currently, external contributions are not accepted. If you encounter a bug or have a feature request, please open an issue on the GitHub repository.

Was this tested? I can't find any tests!

We have tests, we swear! Currently they are coupled with our private build/test infrastructure and are not publicly available. We try to maintain minimum 70% unit test coverage and have integration tests for the public API.

Was this vibe-coded?

We rely on AI-assist but every output line is carefully reviewed and tested before being committed.

License

CLRK is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0); see LICENSE.

Exception: the api/ and client/ directories are licensed under the Apache License 2.0; see api/LICENSE and client/LICENSE. These cover the public API types (api/clrk/v1alpha1) and the generated Kubernetes client/SDK, so they can be imported and used without AGPL copyleft obligations.

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CLRK

CLRK (we pronounce it as "clerk") is a Kubernetes-native runtime for LLM agents. It runs each agent in a gVisor sandbox and transparently intercepts all egress - LLM APIs, MCP, tool calls - without modifying agent code. That interception point gives you observability, policy enforcement, and routing-based cost control over agents you don't otherwise get to see inside.

CLRK egress control point

How it works

CLRK runs untrusted, framework-agnostic agent workloads in gVisor sandboxes. You describe an agent declaratively - a container image + a trigger + an egress policy - and CLRK schedules it onto a pool of sandbox workers. It brings its own scheduler, so agent startup isn't gated on pod-creation latency. Every byte in or out of the sandbox passes through a transparent proxy CLRK controls, so the platform sees and governs all LLM API calls, MCP traffic, and outbound tool calls without the agent code being aware of it. Yes, that includes TLS-encrypted connections.

The agent inside can be anything that makes HTTP(S) calls - a Python script using the OpenAI or Anthropic SDK, a Node MCP client, a shell one-liner. There is no required agent library; CLRK intercepts at the network and process boundary. See _examples/ for runnable agents (openai-bot, gemini-bot, cron-bot, jq-bot, MITM variants, and more).

Motivation

Running agents in production raises problems that general-purpose container orchestration does not solve on its own. CLRK is built to address them directly:

  • Observability. All I/O in and out of a sandbox is intercepted and logged, so LLM, MCP, and remote tool-call telemetry is auto-instrumented rather than bolted on per-framework.
  • Governance. Prevent sandbox escape and apply organization-wide policy (where an agent may connect, what credentials it may use) at the egress boundary.
  • Attribution. Tie agent loops back to the customer request or trigger that started them, captured as first-class Invocation records.
  • Zero-Trust Access. Give agents audited, authorized access to internal services instead of all-or-nothing network access.
  • Scalability. One model for both serverless bursts and long-lived "on-prem" Kubernetes fleets.
  • Reliability. Simple, robust retries, load-shedding, all outside of the Kubernetes control plane.

A deliberate design choice that follows from governance: credentials never live in the agent. API keys for AI providers, MCP servers, and internal services are injected by the egress MITM at request time, never via pod env, mounts, or args - so a compromised sandbox cannot exfiltrate them.

Architecture

CLRK ships two long-running binaries plus a CLI:

  • cmd/controller-manager - the control plane. Runs the controller-runtime reconcilers for the CRDs below and embeds an aggregated API server for the clrk.apoxy.dev group. Deployed as a Deployment on Kubernetes but can be run standalone. It also hosts UI dashboard.

  • cmd/worker - Manages sandbox lifecycle via gVisor/runsc, sets up per-sandbox network interception via our custom sentrystack plugin to be routed through the interception path. Linux-only (//go:build linux, CGO).

  • cmd/clrk - the operator/developer CLI: install, upgrade, dev, apply, get, logs, traces, status, run-task, context management, and a local-cluster dev loop.

Egress interception. Outbound traffic is captured transparently and sent through an EgressGateway - an Envoy-based data plane with TLS termination (MITM) and a custom filter. This is where telemetry is recorded, credentials are injected, and routing/governance policies (EgressL4Route, MCPRoute, AIProviderRoute, egress/credential/fallback-routing/logging/rate-limit policies) are applied.

Telemetry storage and export. Intercepted I/O becomes Invocation records backed by ClickHouse (via the ch-go driver) and can be consumed using /logs and /traces subresources as well as re-exported over OpenTelemetry sink.

TaskAgent vs DaemonAgentTaskAgent is for triggered, run-to-completion work (HTTP request or cron) multiplexed across shared worker pods. DaemonAgent is for long-lived agent processes with a restart policy.

APIs

CRDPurpose
TaskAgentShort-lived agent execution (request → sandbox → response)
DaemonAgentLong-lived agent process with restart policy
WorkerPoolFleet of worker pods (Deployment + Service)
EgressGatewayTransparent egress proxy with TLS termination modes
EgressL4RouteL4 egress routing rules
MCPRouteMCP protocol routing
AIProviderRouteAI-provider-specific egress routing
InvocationAttributed record of an intercepted agent call (ClickHouse-backed)

Repository layout

PathContents
api/clrk/v1alpha1/CRD types (Apache-2.0)
client/Generated Kubernetes clientset, listers, informers (Apache-2.0)
internal/controller/controller-runtime reconcilers
internal/worker/, internal/sandbox/sandbox lifecycle (Linux-only)
internal/eg*, internal/extproc/, internal/egress/Envoy egress data plane + interception
internal/clickhouse/, internal/chwriter/, internal/otel*telemetry storage and export
internal/install/, cmd/clrk/installer and CLI
codegen/code-generator config (update.sh, header boilerplate)

FAQ

Does my agent need to use a specific framework or SDK?

No. CLRK intercepts at the network and process boundary, so any agent that makes HTTP/S calls works. The provided examples use the OpenAI and Gemini SDKs, plain shell tools, and MCP clients.

Where do API keys live?

Not in the agent. Credentials are injected by the egress MITM at request time via a credential-injection policy - never in pod env, mounts, or args. A compromised sandbox has no secrets to leak. The secret material iself is safe and sound in a Kubernetes Secret.

How is the sandbox isolated?

Sandboxes run via gVisor (runsc) for a stronger syscall boundary, each in its own network namespace with all egress forced through the interception path.

Can I run it locally or do I need a Kubernetes cluster?

All batteries included! clrk dev brings up a local cluster and dev loop. This can also be used to run CLRK without a Kubernetes cluster nearby. clrk install / clrk upgrade manage a Kubernetes-based deployment.

Why are api/ and client/ licensed differently from the rest?

So you can build against the API and use the generated client without AGPL copyleft obligations. See License.

Where is CONTRIBUTING.md?

Currently, external contributions are not accepted. If you encounter a bug or have a feature request, please open an issue on the GitHub repository.

Was this tested? I can't find any tests!

We have tests, we swear! Currently they are coupled with our private build/test infrastructure and are not publicly available. We try to maintain minimum 70% unit test coverage and have integration tests for the public API.

Was this vibe-coded?

We rely on AI-assist but every output line is carefully reviewed and tested before being committed.

License

CLRK is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0); see LICENSE.

Exception: the api/ and client/ directories are licensed under the Apache License 2.0; see api/LICENSE and client/LICENSE. These cover the public API types (api/clrk/v1alpha1) and the generated Kubernetes client/SDK, so they can be imported and used without AGPL copyleft obligations.

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

CLRK

CLRK (we pronounce it as "clerk") is a Kubernetes-native runtime for LLM agents. It runs each agent in a gVisor sandbox and transparently intercepts all egress - LLM APIs, MCP, tool calls - without modifying agent code. That interception point gives you observability, policy enforcement, and routing-based cost control over agents you don't otherwise get to see inside.

CLRK egress control point

How it works

CLRK runs untrusted, framework-agnostic agent workloads in gVisor sandboxes. You describe an agent declaratively - a container image + a trigger + an egress policy - and CLRK schedules it onto a pool of sandbox workers. It brings its own scheduler, so agent startup isn't gated on pod-creation latency. Every byte in or out of the sandbox passes through a transparent proxy CLRK controls, so the platform sees and governs all LLM API calls, MCP traffic, and outbound tool calls without the agent code being aware of it. Yes, that includes TLS-encrypted connections.

The agent inside can be anything that makes HTTP(S) calls - a Python script using the OpenAI or Anthropic SDK, a Node MCP client, a shell one-liner. There is no required agent library; CLRK intercepts at the network and process boundary. See _examples/ for runnable agents (openai-bot, gemini-bot, cron-bot, jq-bot, MITM variants, and more).

Motivation

Running agents in production raises problems that general-purpose container orchestration does not solve on its own. CLRK is built to address them directly:

  • Observability. All I/O in and out of a sandbox is intercepted and logged, so LLM, MCP, and remote tool-call telemetry is auto-instrumented rather than bolted on per-framework.
  • Governance. Prevent sandbox escape and apply organization-wide policy (where an agent may connect, what credentials it may use) at the egress boundary.
  • Attribution. Tie agent loops back to the customer request or trigger that started them, captured as first-class Invocation records.
  • Zero-Trust Access. Give agents audited, authorized access to internal services instead of all-or-nothing network access.
  • Scalability. One model for both serverless bursts and long-lived "on-prem" Kubernetes fleets.
  • Reliability. Simple, robust retries, load-shedding, all outside of the Kubernetes control plane.

A deliberate design choice that follows from governance: credentials never live in the agent. API keys for AI providers, MCP servers, and internal services are injected by the egress MITM at request time, never via pod env, mounts, or args - so a compromised sandbox cannot exfiltrate them.

Architecture

CLRK ships two long-running binaries plus a CLI:

  • cmd/controller-manager - the control plane. Runs the controller-runtime reconcilers for the CRDs below and embeds an aggregated API server for the clrk.apoxy.dev group. Deployed as a Deployment on Kubernetes but can be run standalone. It also hosts UI dashboard.

  • cmd/worker - Manages sandbox lifecycle via gVisor/runsc, sets up per-sandbox network interception via our custom sentrystack plugin to be routed through the interception path. Linux-only (//go:build linux, CGO).

  • cmd/clrk - the operator/developer CLI: install, upgrade, dev, apply, get, logs, traces, status, run-task, context management, and a local-cluster dev loop.

Egress interception. Outbound traffic is captured transparently and sent through an EgressGateway - an Envoy-based data plane with TLS termination (MITM) and a custom filter. This is where telemetry is recorded, credentials are injected, and routing/governance policies (EgressL4Route, MCPRoute, AIProviderRoute, egress/credential/fallback-routing/logging/rate-limit policies) are applied.

Telemetry storage and export. Intercepted I/O becomes Invocation records backed by ClickHouse (via the ch-go driver) and can be consumed using /logs and /traces subresources as well as re-exported over OpenTelemetry sink.

TaskAgent vs DaemonAgentTaskAgent is for triggered, run-to-completion work (HTTP request or cron) multiplexed across shared worker pods. DaemonAgent is for long-lived agent processes with a restart policy.

APIs

CRDPurpose
TaskAgentShort-lived agent execution (request → sandbox → response)
DaemonAgentLong-lived agent process with restart policy
WorkerPoolFleet of worker pods (Deployment + Service)
EgressGatewayTransparent egress proxy with TLS termination modes
EgressL4RouteL4 egress routing rules
MCPRouteMCP protocol routing
AIProviderRouteAI-provider-specific egress routing
InvocationAttributed record of an intercepted agent call (ClickHouse-backed)

Repository layout

PathContents
api/clrk/v1alpha1/CRD types (Apache-2.0)
client/Generated Kubernetes clientset, listers, informers (Apache-2.0)
internal/controller/controller-runtime reconcilers
internal/worker/, internal/sandbox/sandbox lifecycle (Linux-only)
internal/eg*, internal/extproc/, internal/egress/Envoy egress data plane + interception
internal/clickhouse/, internal/chwriter/, internal/otel*telemetry storage and export
internal/install/, cmd/clrk/installer and CLI
codegen/code-generator config (update.sh, header boilerplate)

FAQ

Does my agent need to use a specific framework or SDK?

No. CLRK intercepts at the network and process boundary, so any agent that makes HTTP/S calls works. The provided examples use the OpenAI and Gemini SDKs, plain shell tools, and MCP clients.

Where do API keys live?

Not in the agent. Credentials are injected by the egress MITM at request time via a credential-injection policy - never in pod env, mounts, or args. A compromised sandbox has no secrets to leak. The secret material iself is safe and sound in a Kubernetes Secret.

How is the sandbox isolated?

Sandboxes run via gVisor (runsc) for a stronger syscall boundary, each in its own network namespace with all egress forced through the interception path.

Can I run it locally or do I need a Kubernetes cluster?

All batteries included! clrk dev brings up a local cluster and dev loop. This can also be used to run CLRK without a Kubernetes cluster nearby. clrk install / clrk upgrade manage a Kubernetes-based deployment.

Why are api/ and client/ licensed differently from the rest?

So you can build against the API and use the generated client without AGPL copyleft obligations. See License.

Where is CONTRIBUTING.md?

Currently, external contributions are not accepted. If you encounter a bug or have a feature request, please open an issue on the GitHub repository.

Was this tested? I can't find any tests!

We have tests, we swear! Currently they are coupled with our private build/test infrastructure and are not publicly available. We try to maintain minimum 70% unit test coverage and have integration tests for the public API.

Was this vibe-coded?

We rely on AI-assist but every output line is carefully reviewed and tested before being committed.

License

CLRK is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0); see LICENSE.

Exception: the api/ and client/ directories are licensed under the Apache License 2.0; see api/LICENSE and client/LICENSE. These cover the public API types (api/clrk/v1alpha1) and the generated Kubernetes client/SDK, so they can be imported and used without AGPL copyleft obligations.

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CLRK

CLRK (we pronounce it as "clerk") is a Kubernetes-native runtime for LLM agents. It runs each agent in a gVisor sandbox and transparently intercepts all egress - LLM APIs, MCP, tool calls - without modifying agent code. That interception point gives you observability, policy enforcement, and routing-based cost control over agents you don't otherwise get to see inside.

CLRK egress control point

How it works

CLRK runs untrusted, framework-agnostic agent workloads in gVisor sandboxes. You describe an agent declaratively - a container image + a trigger + an egress policy - and CLRK schedules it onto a pool of sandbox workers. It brings its own scheduler, so agent startup isn't gated on pod-creation latency. Every byte in or out of the sandbox passes through a transparent proxy CLRK controls, so the platform sees and governs all LLM API calls, MCP traffic, and outbound tool calls without the agent code being aware of it. Yes, that includes TLS-encrypted connections.

The agent inside can be anything that makes HTTP(S) calls - a Python script using the OpenAI or Anthropic SDK, a Node MCP client, a shell one-liner. There is no required agent library; CLRK intercepts at the network and process boundary. See _examples/ for runnable agents (openai-bot, gemini-bot, cron-bot, jq-bot, MITM variants, and more).

Motivation

Running agents in production raises problems that general-purpose container orchestration does not solve on its own. CLRK is built to address them directly:

  • Observability. All I/O in and out of a sandbox is intercepted and logged, so LLM, MCP, and remote tool-call telemetry is auto-instrumented rather than bolted on per-framework.
  • Governance. Prevent sandbox escape and apply organization-wide policy (where an agent may connect, what credentials it may use) at the egress boundary.
  • Attribution. Tie agent loops back to the customer request or trigger that started them, captured as first-class Invocation records.
  • Zero-Trust Access. Give agents audited, authorized access to internal services instead of all-or-nothing network access.
  • Scalability. One model for both serverless bursts and long-lived "on-prem" Kubernetes fleets.
  • Reliability. Simple, robust retries, load-shedding, all outside of the Kubernetes control plane.

A deliberate design choice that follows from governance: credentials never live in the agent. API keys for AI providers, MCP servers, and internal services are injected by the egress MITM at request time, never via pod env, mounts, or args - so a compromised sandbox cannot exfiltrate them.

Architecture

CLRK ships two long-running binaries plus a CLI:

  • cmd/controller-manager - the control plane. Runs the controller-runtime reconcilers for the CRDs below and embeds an aggregated API server for the clrk.apoxy.dev group. Deployed as a Deployment on Kubernetes but can be run standalone. It also hosts UI dashboard.

  • cmd/worker - Manages sandbox lifecycle via gVisor/runsc, sets up per-sandbox network interception via our custom sentrystack plugin to be routed through the interception path. Linux-only (//go:build linux, CGO).

  • cmd/clrk - the operator/developer CLI: install, upgrade, dev, apply, get, logs, traces, status, run-task, context management, and a local-cluster dev loop.

Egress interception. Outbound traffic is captured transparently and sent through an EgressGateway - an Envoy-based data plane with TLS termination (MITM) and a custom filter. This is where telemetry is recorded, credentials are injected, and routing/governance policies (EgressL4Route, MCPRoute, AIProviderRoute, egress/credential/fallback-routing/logging/rate-limit policies) are applied.

Telemetry storage and export. Intercepted I/O becomes Invocation records backed by ClickHouse (via the ch-go driver) and can be consumed using /logs and /traces subresources as well as re-exported over OpenTelemetry sink.

TaskAgent vs DaemonAgentTaskAgent is for triggered, run-to-completion work (HTTP request or cron) multiplexed across shared worker pods. DaemonAgent is for long-lived agent processes with a restart policy.

APIs

CRDPurpose
TaskAgentShort-lived agent execution (request → sandbox → response)
DaemonAgentLong-lived agent process with restart policy
WorkerPoolFleet of worker pods (Deployment + Service)
EgressGatewayTransparent egress proxy with TLS termination modes
EgressL4RouteL4 egress routing rules
MCPRouteMCP protocol routing
AIProviderRouteAI-provider-specific egress routing
InvocationAttributed record of an intercepted agent call (ClickHouse-backed)

Repository layout

PathContents
api/clrk/v1alpha1/CRD types (Apache-2.0)
client/Generated Kubernetes clientset, listers, informers (Apache-2.0)
internal/controller/controller-runtime reconcilers
internal/worker/, internal/sandbox/sandbox lifecycle (Linux-only)
internal/eg*, internal/extproc/, internal/egress/Envoy egress data plane + interception
internal/clickhouse/, internal/chwriter/, internal/otel*telemetry storage and export
internal/install/, cmd/clrk/installer and CLI
codegen/code-generator config (update.sh, header boilerplate)

FAQ

Does my agent need to use a specific framework or SDK?

No. CLRK intercepts at the network and process boundary, so any agent that makes HTTP/S calls works. The provided examples use the OpenAI and Gemini SDKs, plain shell tools, and MCP clients.

Where do API keys live?

Not in the agent. Credentials are injected by the egress MITM at request time via a credential-injection policy - never in pod env, mounts, or args. A compromised sandbox has no secrets to leak. The secret material iself is safe and sound in a Kubernetes Secret.

How is the sandbox isolated?

Sandboxes run via gVisor (runsc) for a stronger syscall boundary, each in its own network namespace with all egress forced through the interception path.

Can I run it locally or do I need a Kubernetes cluster?

All batteries included! clrk dev brings up a local cluster and dev loop. This can also be used to run CLRK without a Kubernetes cluster nearby. clrk install / clrk upgrade manage a Kubernetes-based deployment.

Why are api/ and client/ licensed differently from the rest?

So you can build against the API and use the generated client without AGPL copyleft obligations. See License.

Where is CONTRIBUTING.md?

Currently, external contributions are not accepted. If you encounter a bug or have a feature request, please open an issue on the GitHub repository.

Was this tested? I can't find any tests!

We have tests, we swear! Currently they are coupled with our private build/test infrastructure and are not publicly available. We try to maintain minimum 70% unit test coverage and have integration tests for the public API.

Was this vibe-coded?

We rely on AI-assist but every output line is carefully reviewed and tested before being committed.

License

CLRK is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0); see LICENSE.

Exception: the api/ and client/ directories are licensed under the Apache License 2.0; see api/LICENSE and client/LICENSE. These cover the public API types (api/clrk/v1alpha1) and the generated Kubernetes client/SDK, so they can be imported and used without AGPL copyleft obligations.

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CLRK

CLRK (we pronounce it as "clerk") is a Kubernetes-native runtime for LLM agents. It runs each agent in a gVisor sandbox and transparently intercepts all egress - LLM APIs, MCP, tool calls - without modifying agent code. That interception point gives you observability, policy enforcement, and routing-based cost control over agents you don't otherwise get to see inside.

CLRK egress control point

How it works

CLRK runs untrusted, framework-agnostic agent workloads in gVisor sandboxes. You describe an agent declaratively - a container image + a trigger + an egress policy - and CLRK schedules it onto a pool of sandbox workers. It brings its own scheduler, so agent startup isn't gated on pod-creation latency. Every byte in or out of the sandbox passes through a transparent proxy CLRK controls, so the platform sees and governs all LLM API calls, MCP traffic, and outbound tool calls without the agent code being aware of it. Yes, that includes TLS-encrypted connections.

The agent inside can be anything that makes HTTP(S) calls - a Python script using the OpenAI or Anthropic SDK, a Node MCP client, a shell one-liner. There is no required agent library; CLRK intercepts at the network and process boundary. See _examples/ for runnable agents (openai-bot, gemini-bot, cron-bot, jq-bot, MITM variants, and more).

Motivation

Running agents in production raises problems that general-purpose container orchestration does not solve on its own. CLRK is built to address them directly:

  • Observability. All I/O in and out of a sandbox is intercepted and logged, so LLM, MCP, and remote tool-call telemetry is auto-instrumented rather than bolted on per-framework.
  • Governance. Prevent sandbox escape and apply organization-wide policy (where an agent may connect, what credentials it may use) at the egress boundary.
  • Attribution. Tie agent loops back to the customer request or trigger that started them, captured as first-class Invocation records.
  • Zero-Trust Access. Give agents audited, authorized access to internal services instead of all-or-nothing network access.
  • Scalability. One model for both serverless bursts and long-lived "on-prem" Kubernetes fleets.
  • Reliability. Simple, robust retries, load-shedding, all outside of the Kubernetes control plane.

A deliberate design choice that follows from governance: credentials never live in the agent. API keys for AI providers, MCP servers, and internal services are injected by the egress MITM at request time, never via pod env, mounts, or args - so a compromised sandbox cannot exfiltrate them.

Architecture

CLRK ships two long-running binaries plus a CLI:

  • cmd/controller-manager - the control plane. Runs the controller-runtime reconcilers for the CRDs below and embeds an aggregated API server for the clrk.apoxy.dev group. Deployed as a Deployment on Kubernetes but can be run standalone. It also hosts UI dashboard.

  • cmd/worker - Manages sandbox lifecycle via gVisor/runsc, sets up per-sandbox network interception via our custom sentrystack plugin to be routed through the interception path. Linux-only (//go:build linux, CGO).

  • cmd/clrk - the operator/developer CLI: install, upgrade, dev, apply, get, logs, traces, status, run-task, context management, and a local-cluster dev loop.

Egress interception. Outbound traffic is captured transparently and sent through an EgressGateway - an Envoy-based data plane with TLS termination (MITM) and a custom filter. This is where telemetry is recorded, credentials are injected, and routing/governance policies (EgressL4Route, MCPRoute, AIProviderRoute, egress/credential/fallback-routing/logging/rate-limit policies) are applied.

Telemetry storage and export. Intercepted I/O becomes Invocation records backed by ClickHouse (via the ch-go driver) and can be consumed using /logs and /traces subresources as well as re-exported over OpenTelemetry sink.

TaskAgent vs DaemonAgentTaskAgent is for triggered, run-to-completion work (HTTP request or cron) multiplexed across shared worker pods. DaemonAgent is for long-lived agent processes with a restart policy.

APIs

CRDPurpose
TaskAgentShort-lived agent execution (request → sandbox → response)
DaemonAgentLong-lived agent process with restart policy
WorkerPoolFleet of worker pods (Deployment + Service)
EgressGatewayTransparent egress proxy with TLS termination modes
EgressL4RouteL4 egress routing rules
MCPRouteMCP protocol routing
AIProviderRouteAI-provider-specific egress routing
InvocationAttributed record of an intercepted agent call (ClickHouse-backed)

Repository layout

PathContents
api/clrk/v1alpha1/CRD types (Apache-2.0)
client/Generated Kubernetes clientset, listers, informers (Apache-2.0)
internal/controller/controller-runtime reconcilers
internal/worker/, internal/sandbox/sandbox lifecycle (Linux-only)
internal/eg*, internal/extproc/, internal/egress/Envoy egress data plane + interception
internal/clickhouse/, internal/chwriter/, internal/otel*telemetry storage and export
internal/install/, cmd/clrk/installer and CLI
codegen/code-generator config (update.sh, header boilerplate)

FAQ

Does my agent need to use a specific framework or SDK?

No. CLRK intercepts at the network and process boundary, so any agent that makes HTTP/S calls works. The provided examples use the OpenAI and Gemini SDKs, plain shell tools, and MCP clients.

Where do API keys live?

Not in the agent. Credentials are injected by the egress MITM at request time via a credential-injection policy - never in pod env, mounts, or args. A compromised sandbox has no secrets to leak. The secret material iself is safe and sound in a Kubernetes Secret.

How is the sandbox isolated?

Sandboxes run via gVisor (runsc) for a stronger syscall boundary, each in its own network namespace with all egress forced through the interception path.

Can I run it locally or do I need a Kubernetes cluster?

All batteries included! clrk dev brings up a local cluster and dev loop. This can also be used to run CLRK without a Kubernetes cluster nearby. clrk install / clrk upgrade manage a Kubernetes-based deployment.

Why are api/ and client/ licensed differently from the rest?

So you can build against the API and use the generated client without AGPL copyleft obligations. See License.

Where is CONTRIBUTING.md?

Currently, external contributions are not accepted. If you encounter a bug or have a feature request, please open an issue on the GitHub repository.

Was this tested? I can't find any tests!

We have tests, we swear! Currently they are coupled with our private build/test infrastructure and are not publicly available. We try to maintain minimum 70% unit test coverage and have integration tests for the public API.

Was this vibe-coded?

We rely on AI-assist but every output line is carefully reviewed and tested before being committed.

License

CLRK is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0); see LICENSE.

Exception: the api/ and client/ directories are licensed under the Apache License 2.0; see api/LICENSE and client/LICENSE. These cover the public API types (api/clrk/v1alpha1) and the generated Kubernetes client/SDK, so they can be imported and used without AGPL copyleft obligations.

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

CLRK

CLRK (we pronounce it as "clerk") is a Kubernetes-native runtime for LLM agents. It runs each agent in a gVisor sandbox and transparently intercepts all egress - LLM APIs, MCP, tool calls - without modifying agent code. That interception point gives you observability, policy enforcement, and routing-based cost control over agents you don't otherwise get to see inside.

CLRK egress control point

How it works

CLRK runs untrusted, framework-agnostic agent workloads in gVisor sandboxes. You describe an agent declaratively - a container image + a trigger + an egress policy - and CLRK schedules it onto a pool of sandbox workers. It brings its own scheduler, so agent startup isn't gated on pod-creation latency. Every byte in or out of the sandbox passes through a transparent proxy CLRK controls, so the platform sees and governs all LLM API calls, MCP traffic, and outbound tool calls without the agent code being aware of it. Yes, that includes TLS-encrypted connections.

The agent inside can be anything that makes HTTP(S) calls - a Python script using the OpenAI or Anthropic SDK, a Node MCP client, a shell one-liner. There is no required agent library; CLRK intercepts at the network and process boundary. See _examples/ for runnable agents (openai-bot, gemini-bot, cron-bot, jq-bot, MITM variants, and more).

Motivation

Running agents in production raises problems that general-purpose container orchestration does not solve on its own. CLRK is built to address them directly:

  • Observability. All I/O in and out of a sandbox is intercepted and logged, so LLM, MCP, and remote tool-call telemetry is auto-instrumented rather than bolted on per-framework.
  • Governance. Prevent sandbox escape and apply organization-wide policy (where an agent may connect, what credentials it may use) at the egress boundary.
  • Attribution. Tie agent loops back to the customer request or trigger that started them, captured as first-class Invocation records.
  • Zero-Trust Access. Give agents audited, authorized access to internal services instead of all-or-nothing network access.
  • Scalability. One model for both serverless bursts and long-lived "on-prem" Kubernetes fleets.
  • Reliability. Simple, robust retries, load-shedding, all outside of the Kubernetes control plane.

A deliberate design choice that follows from governance: credentials never live in the agent. API keys for AI providers, MCP servers, and internal services are injected by the egress MITM at request time, never via pod env, mounts, or args - so a compromised sandbox cannot exfiltrate them.

Architecture

CLRK ships two long-running binaries plus a CLI:

  • cmd/controller-manager - the control plane. Runs the controller-runtime reconcilers for the CRDs below and embeds an aggregated API server for the clrk.apoxy.dev group. Deployed as a Deployment on Kubernetes but can be run standalone. It also hosts UI dashboard.

  • cmd/worker - Manages sandbox lifecycle via gVisor/runsc, sets up per-sandbox network interception via our custom sentrystack plugin to be routed through the interception path. Linux-only (//go:build linux, CGO).

  • cmd/clrk - the operator/developer CLI: install, upgrade, dev, apply, get, logs, traces, status, run-task, context management, and a local-cluster dev loop.

Egress interception. Outbound traffic is captured transparently and sent through an EgressGateway - an Envoy-based data plane with TLS termination (MITM) and a custom filter. This is where telemetry is recorded, credentials are injected, and routing/governance policies (EgressL4Route, MCPRoute, AIProviderRoute, egress/credential/fallback-routing/logging/rate-limit policies) are applied.

Telemetry storage and export. Intercepted I/O becomes Invocation records backed by ClickHouse (via the ch-go driver) and can be consumed using /logs and /traces subresources as well as re-exported over OpenTelemetry sink.

TaskAgent vs DaemonAgentTaskAgent is for triggered, run-to-completion work (HTTP request or cron) multiplexed across shared worker pods. DaemonAgent is for long-lived agent processes with a restart policy.

APIs

CRDPurpose
TaskAgentShort-lived agent execution (request → sandbox → response)
DaemonAgentLong-lived agent process with restart policy
WorkerPoolFleet of worker pods (Deployment + Service)
EgressGatewayTransparent egress proxy with TLS termination modes
EgressL4RouteL4 egress routing rules
MCPRouteMCP protocol routing
AIProviderRouteAI-provider-specific egress routing
InvocationAttributed record of an intercepted agent call (ClickHouse-backed)

Repository layout

PathContents
api/clrk/v1alpha1/CRD types (Apache-2.0)
client/Generated Kubernetes clientset, listers, informers (Apache-2.0)
internal/controller/controller-runtime reconcilers
internal/worker/, internal/sandbox/sandbox lifecycle (Linux-only)
internal/eg*, internal/extproc/, internal/egress/Envoy egress data plane + interception
internal/clickhouse/, internal/chwriter/, internal/otel*telemetry storage and export
internal/install/, cmd/clrk/installer and CLI
codegen/code-generator config (update.sh, header boilerplate)

FAQ

Does my agent need to use a specific framework or SDK?

No. CLRK intercepts at the network and process boundary, so any agent that makes HTTP/S calls works. The provided examples use the OpenAI and Gemini SDKs, plain shell tools, and MCP clients.

Where do API keys live?

Not in the agent. Credentials are injected by the egress MITM at request time via a credential-injection policy - never in pod env, mounts, or args. A compromised sandbox has no secrets to leak. The secret material iself is safe and sound in a Kubernetes Secret.

How is the sandbox isolated?

Sandboxes run via gVisor (runsc) for a stronger syscall boundary, each in its own network namespace with all egress forced through the interception path.

Can I run it locally or do I need a Kubernetes cluster?

All batteries included! clrk dev brings up a local cluster and dev loop. This can also be used to run CLRK without a Kubernetes cluster nearby. clrk install / clrk upgrade manage a Kubernetes-based deployment.

Why are api/ and client/ licensed differently from the rest?

So you can build against the API and use the generated client without AGPL copyleft obligations. See License.

Where is CONTRIBUTING.md?

Currently, external contributions are not accepted. If you encounter a bug or have a feature request, please open an issue on the GitHub repository.

Was this tested? I can't find any tests!

We have tests, we swear! Currently they are coupled with our private build/test infrastructure and are not publicly available. We try to maintain minimum 70% unit test coverage and have integration tests for the public API.

Was this vibe-coded?

We rely on AI-assist but every output line is carefully reviewed and tested before being committed.

License

CLRK is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0); see LICENSE.

Exception: the api/ and client/ directories are licensed under the Apache License 2.0; see api/LICENSE and client/LICENSE. These cover the public API types (api/clrk/v1alpha1) and the generated Kubernetes client/SDK, so they can be imported and used without AGPL copyleft obligations.

Releases

Packages

Contributors

Languages