Loading Now

When the Coding Agent Leaves the Codebase: Building a Multi-Runtime AI Agent Infra with Azure KARS

Let me share a common situation I often encounter at community gatherings.

After a meetup last year, I received an email. It wasn’t from a developer; the sender was actually a marketing manager at a manufacturing firm. He wrote: “I followed your tutorial to install Claude Code. I initially wanted it just to fix a static web page, but I discovered it could read multiple Excel files, create a script to process them, and generate a PowerPoint presentation. Now, my weekly dealer briefings are produced with it.”

Then, he asked a very straightforward question: “Can we implement this across my entire department?”

That question sets the stage for this article.

For the past couple of years, many have approached the development of agents differently: defining tool schemas, writing function calls, establishing an orchestrator, integrating RAG, and tweaking prompts. There’s nothing wrong with this approach, but it assumes one crucial thing: you must anticipate what the user will do, allowing you to encapsulate that capability in a tool.

Conversely, coding agents like Claude Code CLI, GitHub Copilot CLI, Codex CLI, and their counterparts took a different route. Their initial design aimed to “complete genuine software engineering tasks, on an authentic filesystem, using a real command line.” To achieve this, they needed to develop four vital capabilities:

Firstly, the filesystem is a key component. The agent operates from a defined working directory. It can read, write, list, and create files. For developers, this translates to “editing code,” whereas for a marketing manager, it means “I upload ten spreadsheets and receive a presentation back.” Thus, the same feature provides vastly different outputs depending on the context.

Secondly, the shell serves as the universal tool. Traditional agents require new tool definitions for each new capability. A coding agent, however, has just one primary tool: executing a command. This means that tools like pandas, LibreOffice, curl, ffmpeg, or Chromium can all be employed as agent capabilities as long as they can fit in a container. Extending the toolset switches from writing code to creating a Dockerfile.

Thirdly, it operates as a long-task machine. Coding doesn’t function on a simple request/response basis; it follows a plan → execute → read error → fix → re-execute cycle. In a business loop, this translates to: analyse the data → identify misaligned columns → clean the data → recalculate → chart it → compile the report. The self-correcting cycle that conversational agents struggle to implement is naturally the default operation for a coding agent.

Fourthly, it has established extension protocols. MCP connects it to external systems; Skills encapsulate your industry knowledge and delivery standards. For instance, a single SKILL.md can elaborate “this is the format of our monthly report, these are the definitions, and the disclaimer appears on page two” — all without needing to write any code.

Thus, the conclusion becomes apparent: the coding agent runtime wasn’t adapted into a business agent runtime. It remains the most versatile agent runtime available today. Code was just the initial focus because it has the clearest evaluation metric (does it run?). However, the underlying process — iteratively creating files, utilising multiple tools, within an isolated environment — is applicable to most knowledge work.

Returning to the email, the question posed, “Can we implement this throughout the department?” highlights some challenges that exist between a single laptop user and an entire department:

  • The marketing manager’s Claude Code was running on his personal Mac with his API key, conveniently bypassing the permission prompts (yes, truly).
  • Some colleagues preferred Copilot CLI since the company utilised GitHub Enterprise, while others favoured Codex CLI because they were connected to a self-hosted OpenAI-compatible gateway.
  • Security had one pressing concern: “This can execute arbitrary commands and access the network. What does it have permission to access?”

These three issues can be summarised: runtime diversity, credential management, and potential impact. Fortunately, Azure KARS is designed to tackle these challenges.

Azure/kars — the Agent Reference Stack for Kubernetes. This project is developed openly by the Azure Cloud Native team, who also built Azure Kubernetes Service and Azure Linux.

The most crucial point to note up front: this isn’t an officially supported Microsoft product. There’s no service-level agreement, support contract, or guarantee on product roadmap timelines. It serves as a reference implementation — an opportunity to learn from its architecture and build upon it.

In the KARS README, there’s a line that encapsulates the project’s core concept: granting an AI agent real tools means providing it with actual credentials and network access — but in a production environment, this entails a significant risk, as a single prompt-injected agent could potentially access your Azure subscription, GitHub organisation, and customer data.

KARS doesn’t suggest “limiting what the agent can do.” Instead, it advocates to manage agents with the same operational discipline as your other services.

A fundamental decision in KARS’s structure is: each agent operates in its own secure sandbox, with no independent network access.

The agent container runs as UID 1000, with no ability for outbound network access; it can only communicate with the inference router over localhost within the same pod. Any data exiting the pod does so via that Rust router. NetworkPolicy and the egress-guard iptables init container act as safety measures that limit risks if the router is ever bypassed. The outcome: compromising the agent does not put the cloud account, model, audit log, or peer mesh at risk.

This router is essential for the security framework. It operates as a separate container under a different UID (1001), holds the credentials the agent never accesses, and sits at the sole point for enforcing:

CapabilityDescription
Identity & token managementExchanges the sandbox Entra Agent ID (or cluster Workload Identity) for backend tokens using federated OIDC / IMDS, refreshing automatically. The agent process does not store long-lived keys.
Content safety inlineMonitors Foundry’s prompt_filter_results with every completion (jailbreak/indirect attack/harmful content) and enforces a configurable severity threshold.
Token limits & request restrictionsPer-tenant token caps and request rate limits, applied before the request exits the pod.
L7 egress allowlist + denylistEvery outbound connection must pass checks against the per-sandbox allowlist and the daily-updated OISD + URLhaus denylist; EgressApproval CRDs permit temporary exceptions.
MCP gatewayFacilitates calls to external MCP servers using OAuth and specific tool allowlists.
Tamper-proof audit logsEvery action gets logged in an append-only, SHA-256 hash-chained audit log (each entry’s hash includes the previous one) in a stable JSONL format.

A common argument worth addressing directly is: “We already have an API gateway — isn’t this redundant?” The answer is no; a north-south gateway manages traffic at the cluster boundary; in contrast, the KARS router enforces policy at the in-pod level, situated on localhost between the agent and everything else, ensuring the agent has no network paths that circumvent it. They function at different layers and are complementary, not interchangeable — a cluster-edge gateway can preface KARS, while the per-pod router still maintains per-sandbox identity, content safety, budget, and audit control that a shared edge cannot. This illustrates the core of the zero-trust model: the trust boundary lies within the pod, not the cluster perimeter.

This aspect is crucial to our discussion. You define the runtime type using KarsSandbox.spec.runtime.kind, and the router, governance, isolation, and audit chain remain consistent across all options.

The built-in runtimes include: OpenClaw (default, TypeScript/Node), Hermes (Nous Research, Python), OpenAI Agents SDK, Microsoft Agent Framework (Python; .NET support is pending), LangGraph, LangGraph.js, Anthropic Claude Agent SDK, Pydantic-AI — and also BYO: your own image, our terms.

As an advocate, I believe “identical router, governance, isolation, and audit chain” is one of the most overlooked phrases in the repository. It means the security assessment occurs once. Your security team doesn’t need to evaluate LangGraph, then assess the Claude Agent SDK, and then review your wrapper; they only review the pod structure, the CRDs, and the audit format. In the project’s own terms: security teams assess YAML, not Python. Approval gates, rate limits, tool allowlists, content safety thresholds, token limits, and trust topology are all declarative Kubernetes resources — simply commit them to a repository, reconcile with Argo/Flux, and audit using git log.

All three modes operate using the same KarsSandbox YAML. The only differences lie in where it runs and what isolates it.

  • Local kind (recommended) — multi-container pod: agent + router + initial egress guard. This is the real production configuration, with the same NetworkPolicy and egress guard as AKS. It’s the ideal development cycle to use because what you test locally is what you deploy.
  • Local Docker — single container where the agent and router are co-located. This provides the fastest prompt/tool cycle, but it’s not the final production shape.
  • AKS (production) — multi-container pod: agent (UID 1000) + router (UID 1001) + initial egress guard, with optional Kata + AMD SEV-SNP confidential containers (which require a specific Kata node pool).

All use the same CRDs. All follow the same router code path. All share the same audit format. All implement the same governance profiles. Transitioning from local to AKS is simply a one-line CLI command, not a complete overhaul to a different system.

Onboarding is notably straightforward for a Kubernetes project: run npm i -g @kars-runtime/cli, then execute kars dev –release –target local-k8s. On your first run, you’ll select a provider, and KARS will set up the controller, the encrypted mesh, and a sandboxed agent within a local kind cluster. The images are multi-arch (amd64 + arm64, and compatible on Apple Silicon) and are cosign-signed; using –release pulls them, so there’s no Rust, no cloning, and no building necessary.

Now, let’s circle back to the original email. My marketing colleague isn’t interested in OpenClaw or LangGraph; what he wants is the CLI he’s already comfortable using. This brings us to the BYO (Bring Your Own runtime) scenario.

BYO is particularly tricky — the essence of BYO is that the platform outlines the framework for isolation and governance, but how the agent operates ultimately falls back on you.

This misunderstanding happens frequently. The documentation is refreshingly clear about this: the CLIs continue to utilise their native protocols to access defined model services, and a BYO runtime integration doesn’t guarantee that every optional KARS capability is activated — things like Token Budget, Content Safety, precise /agt/evaluate assessments for every native tool call, or cross-agent AgentMesh orchestration. Simply meeting strict image-label or CR admission conditions does not fulfill the complete runtime plugin agreement.

To put it plainly: just because a pod is operational doesn’t mean it is being governed. Your container may perfectly meet the upstream BYO quickstart image and HTTP adapter requirements — org.kars.runtime.contract=v1, UID 1000, writable /sandbox and /tmp, port 8080, alongside ensuring SANDBOX_NAME and KARS_RUNTIME_CONTRACT_VERSION are validated — while still potentially allowing model calls to escape directly to the internet.

So, for a genuine BYO implementation, follow this ordered checklist:

  1. Deploy the upstream KARS, enable controller.byoStrict=true, and upload the runtime images to your own registry.
  2. Adhere to the matching CRD and controller guidelines when configuring agent settings and writable workspaces.
  3. Route Claude and Codex inference through the router’s /anthropic and /v1 endpoints when employing zero-credential routing.
  4. Incorporate /agt/evaluate for every CLI tool execution and funnel MCP through /mcp prior to asserting comprehensive tool regulation.
  5. Independently verify allowed egress and proxy compatibility specifically for Copilot CLI’s native token authentication and network traffic.

It’s crucial to highlight that Copilot CLI has different authentication methods compared to Claude and Codex — this distinction isn’t just about redirecting a base URL. Every CLI that possesses its own authorization chain necessitates its governed egress to be validated independently. You cannot rely on assumptions.

This might be the most forthright message in the BYO Agent Studio project: agents use restricted tool settings by default, and activating tools gives the CLI permission to execute commands, alter its workspace, and call configured MCP servers within its runtime. This represents a broad capability extension, rather than approval on a per-command basis. Conversely, denying access to tools also disables related MCP servers, but native restriction behaviour varies between CLIs, and it does not offer an additional operating-system isolation layer.

A significant number of teams fall into a dangerous illusion here: they believe that the CLI’s own permission prompts define the security boundary. That’s far from accurate. The true boundary is pod isolation and the router’s egress policy. The CLI-level toggles function merely as convenience configuration.

Additionally, it’s important to note that the configured name is entered into SKILL.md frontmatter, ensuring that all three CLIs identify the Skill consistently — but Skills provide guidance, not permissions for tool execution. If a Skill needs to read files or run workflows, you must enable the corresponding tools as well.

Credentials are utilized solely for local configuration and the active runtime; they do not enter the image building context or the process command line. However, the documentation makes it clear: this isn’t a secret vault. Local users, Docker administrators, and tool-enabled agents can access runtime credentials. Treat MCP environment variables and headers as sensitive information too.

A critical point that merits repeating: never expose the local control panel directly to the public internet. This is a single-user development workspace — there’s no support for multi-user logins, no application-level RBAC, no remote Docker TLS, and no production-level secret management.

Only connect trusted external MCP servers, as they come with their own permissions and potential consequences. On the implementation side: stdio MCP processes run within the agent runtime, not on the host; if additional executables are needed, extend containers/Dockerfile — downloading tools via ad hoc npx calls is not advisable in a read-only root filesystem.

At the heart of this rule sits a grand principle: in a BYO framework, capabilities should be declared by the image, not improvised at runtime. Images are auditable, signable, and reversible. On the other hand, something pulled in with npx during a conversation lacks those assurances.

Runtime images tie specific CLI versions — for example Claude Code 2.1.263, GitHub Copilot CLI 1.0.83, Codex CLI 0.152.0. Copilot’s restricted mode operates with a populated tool allowlist validated for that specific version; Codex relies on native feature settings and bundled model metadata. Always revalidate the adapters when a CLI version changes.

Coding-agent CLIs tend to update weekly. In a BYO setup, the CLI version represents an infrastructure dependency, not a casual client upgrade. It needs to be placed under change management to avoid situations where your tool allowlist stops matching up without warning.

The upstream quickstart README refers to k8s/karssandbox.yaml, while the current example file may still be called k8s/clawsandbox.yaml — ensure you use the actual contents of the repository rather than relying on potentially outdated paths. This seemingly minor detail underscores a larger principle: BYO signifies you’re working within a contract that is actively evolving.

Now, moving on to practical applications, let’s discuss KARS BYO Agent Studio.

It’s a workspace designed for three runtimes: Claude Code CLI, GitHub Copilot CLI, and Codex CLI. You can create agents, configure MCP servers and Skills, and manage streaming conversations all from a single UI. The project supports both local Docker development and Azure deployment using AKS/KARS.

This is precisely what my marketing acquaintance required: he doesn’t need to learn Kubernetes while still having his agent run in a secure sandbox.

  1. Select a runtime, then provide a name, model, endpoint, and credential.
  2. Configure agent instructions and optionally enable tools, MCP servers, and Skills.
  3. Save the agent, initiate its runtime, and start a session within the shared chat environment.
  4. Begin a session with @AgentName to specify which agent you’re using. Subsequent messages will continue using that agent until you mention a different @AgentName.

The three runtimes vary greatly in their requirements — which illustrates the concrete necessity of “validating BYO per runtime”:

RuntimeCredentialDefault modelEndpoint
Claude Code CLIAPI key for an Anthropic-compatible serviceclaude-sonnet-4-6https://api.anthropic.com
GitHub Copilot CLIGitHub token accepted by the CLI with Copilot accessgpt-6-astraManaged by Copilot CLI
Codex CLIAPI key for an OpenAI-compatible servicegpt-5.4https://api.openai.com/v1

Details critically influence the success of deployments. For Claude, input the service root, as the CLI calls the Messages API. For Codex, input a base URL that includes /v1, plus the provider must implement the Responses API, and not just /chat/completions. The credential for Copilot must be a GitHub OAuth token compatible with the CLI or a fine-grained PAT that allows Copilot Requests access — a general PAT is not acceptable, nor can arbitrary OpenAI keys serve as Copilot credentials. A frequently encountered issue during local debugging involves attempting to access a model service from a local runtime container using http://host.docker.internal:, rather than localhost.

It’s also worth noting that an agent draft may be saved even without credentials; however, chat remains inaccessible until valid credentials are provided — and once created, the runtime type can’t be changed; to switch runtimes, you need to establish a new agent.

This section starkly illustrates how non-coding jobs differ from coding tasks. Generating a complete presentation can take over ten minutes — much longer than an ordinary conversation turn.

The Website and KARS runtime send heartbeats every 15 seconds to maintain long file-generation streams. The Website doesn’t impose early deadlines on active tasks. The runtime permits an agent to operate for 60 minutes by default, and CHAT_TIMEOUT_MS allows configuration of limits ranging from one minute to 24 hours.

Crucially, in the event of a disconnection: if the link between the browser and the Website is interrupted, the agent continues working in the background. Upon reconnection, the UI polls the current session and restores the final response and deliverables once the task is complete. Only by explicitly selecting Stop generating can you cancel the runtime task. Close the laptop, pass through a tunnel — the work isn’t lost.

In a beautifully business-oriented engineering nuance, suppressed tool events are capped at a 64 MiB default allowance to prevent long-running PowerPoint jobs from failing when intermediate tool outputs exceed 4 MiB. User-facing assistant text remains limited to 4 MiB, while the structured output budget can be configured via CLI_STRUCTURED_OUTPUT_LIMIT_BYTES. Those who’ve generated Office documents programmatically will appreciate this — the intermediate output tends to be much larger than the final product.

The generated files are displayed beneath the assistant’s response, with type-aware previews: Word, Excel, and PowerPoint files are converted to PDF for preview purposes while maintaining the original file for download; PDFs are viewed through a native embedded viewer; HTML is rendered in a sandboxed iframe without script execution permissions; SVG/PNG/GIF/JPG/WebP are previewed as native images; Markdown appears as safely rendered GFM.

The security boundaries extend all the way to the deliverables: results from tools are intentionally excluded from browser output and session persistence. Deliverables are only accessible from the corresponding agent workspace after passing various safety checks, including path-traversal, symlink, extension, file count, and size verifications.

This is the essential aspect for non-coding business agents. Skill names are comprised of lowercase letters, numbers, and hyphens. Each Skill is uploaded as a ZIP file, with a maximum size of 5 MiB, containing SKILL.md at either the root or within the sole top-level directory of the ZIP. The archive may also comprise scripts, templates, and other resources.

The cross-runtime consistency stands out as a design triumph here. Uploaded Skills are safely extracted into persistent agent storage and synchronised with /sandbox/agents//skills// before each KARS conversation, ensuring Skills are not lost when a KARS pod restarts. From there, the runtime maps them to the native location of each CLI:

  • Claude Code: ~/.claude/skills/
  • GitHub Copilot CLI: /.github/skills/
  • Codex CLI: ~/.agents/skills/

One ZIP file supports all three runtimes. This means “how our company documents a monthly report” — your actual institutional asset — remains independent of any specific model vendor.

The project accommodates both Azure-managed and local Docker operations. In the Azure environment, the Website/control plane operates within Azure Container Apps, while agents function in a KARS Sandbox on AKS.

The control plane handles agent/provider/Skill configurations, maintaining session and message history, managing the browser stream along with background recovery, artifact metadata/preview/download proxying, and Managed Identity authentication to AKS. Persistent state — including configurations, credentials, ZIP Skills, sessions, and history — is stored on Azure Files.

The execution layer is the pod mentioned earlier: the BYO agent container (UID 1000) with a read-only root filesystem, alongside KARS governance/runtime, which includes the inference router, egress guard/proxy, network and tool policies. The installed components are undeniably business-oriented: the three CLIs, Chromium, curl, LibreOffice, and MCP clients. Importantly, even the browser does not receive exemptions — commands related to chrome, chromium, google-chrome, and google-chrome-stable all route through the KARS egress proxy, ensuring compliance with sandbox network governance.

The agent’s working directory is divided into three parts under /sandbox/agents//: workspace (for generated outputs), home (where native CLI configurations are stored), and skills (which includes synchronized ZIP Skills).

One final worthwhile trade-off to acknowledge: Sessions are portable transcripts, not corresponding native session IDs shared among the three CLIs — and oversized conversation context fails explicitly rather than being silently truncated. Silent truncation often leads to confusion in agent products; users aren’t aware of the reasons behind the agent suddenly “forgetting.” It’s much better to be explicit when there’s an issue.

Returning to the email, here’s how I’d respond today:

Yes, rolling it out to the department is indeed possible. However, what you’re creating isn’t merely “a bigger Claude Code” — it’s a comprehensive layer of agent infrastructure.

This layer consists of four levels that must be carefully considered:

Level 1 — Runtime: embrace diversity, avoid making rigid choices. Coding-agent CLIs have become the most versatile business agent runtime as they integrate the filesystem, the shell, the iterative loop, and the extension protocols into one resource. However, this space is constantly evolving. Your architecture should support coexistence among Claude Code, Copilot CLI, and Codex CLI, allowing users to choose based on their tasks, rather than the company committing to a single option. Keep in mind, the runtime type is fixed post-creation: this reminder indicates that the choice of runtime should not be a one-time decision for the whole company.

Level 2 — Governance: ensure boundaries are set where the agent lacks access. KARS’s solution places the trust boundary at the pod level, not across the cluster perimeter. The agent has no independent network access, credentials are stored in a container with a different UID, every egress is monitored at L7, and every decision is logged in a hash-chained audit. Any restrictions within the agent container are conveniences; only what you restrict outside it ensures security.

Level 3 — Knowledge: this serves as your competitive advantage. Models may change, and CLIs will be updated. However, “how we document a quarterly review, what definitions apply to dealer briefings” is your significant asset. Format it as a Skill, produce a single ZIP for all three runtimes — that’s the only way a business agent becomes genuinely transferable.

Level 4 — Experience: lengthy tasks and deliverables are crucial factors. Fifteen-second heartbeats, a 60-minute default execution time, continuity during disconnections, Office-to-PDF previews, a 64 MiB intermediate-output limit — none of these aspects are strictly “AI capabilities,” and without any of them, my friend’s deck would never come to fruition. Much of a business agent’s success or failure hinges on these engineering details.

As a final note for fellow advocates, KARS is a work in progress and not an officially supported product; CRDs are at v1alpha1, and this may change between minor releases, although the data path, security model, and audit chain remain stable. The README includes a commendable Known limitations section, beginning with the statement “We want you to discover these here, rather than in production.”

This honesty truly adds value to a reference implementation. You’re not purchasing a guarantee; instead, you’re accessing well-considered engineering insights on how to safely operate agents. For all of us engaged in advocacy, the crucial message is not simply “look at this powerful tool.” It’s this: we now understand where to delineate our boundaries.

Please check this repo – https://github.com/kinfey/kars-byo-demo

Share this content:


Discover more from Qureshi

Subscribe to get the latest posts sent to your email.

Discover more from Qureshi

Subscribe now to keep reading and get access to the full archive.

Continue reading