Back to Articles

Building a Web Proxy for AI Coding Agents: Inside Claude Code WebUI

[ View on GitHub ]

Building a Web Proxy for AI Coding Agents: Inside Claude Code WebUI

Hook

What if the most powerful AI coding assistant required you to stay in a terminal, unable to check your phone or switch devices mid-conversation? Claude Code WebUI solves this by turning Anthropic’s CLI-only coding agent into a web-accessible service, but the architecture reveals fascinating challenges about bridging process boundaries and managing stateful AI interactions.

Context

When Anthropic released Claude CLI, they delivered an agentic coding assistant that can read files, write code, and execute commands—but exclusively through terminal sessions. For developers accustomed to modern web interfaces, this was a step backward: no conversation history across sessions, no mobile access, no easy way to share a coding session with a colleague looking over your shoulder. The problem wasn’t just UX preference; it was workflow fragmentation. If you started a coding session on your desktop and wanted to continue on your laptop, you’d lose all context. If you needed to approve file changes while away from your desk, you were stuck.

This is where claude-code-webui comes in. Built by sugyan, it’s not trying to reimplement Claude’s capabilities—instead, it’s a carefully designed proxy layer that spawns Claude CLI processes and translates between web protocols (WebSocket/SSE) and the CLI’s stdin/stdout streams. The project sits at an interesting intersection: it needs to be lightweight enough to add minimal overhead, yet sophisticated enough to manage process lifecycles, permission prompts, and streaming responses. With nearly 900 stars on GitHub, it’s clearly struck a nerve with developers who want the power of Claude Code without being chained to their terminals.

Technical Insight

User Message

Route to Session

Write to stdin

stdout Stream

Parse & Forward

SSE/WebSocket

Permission Request

Detected in stdout

Modal Dialog

Approve/Deny

Write Response

to stdin

Read/Write Files

Web UI

React Frontend

WebSocket/SSE

Connection Handler

Process Manager

Session Mapping

Claude CLI Process

stdin/stdout/stderr

File System

Project Directory

System architecture — auto-generated

The core architectural challenge of claude-code-webui is managing the lifecycle of a long-running, stateful CLI process from an HTTP/WebSocket server. Most web-to-CLI bridges are simple: spawn a process, wait for it to complete, return the output. But Claude CLI is interactive, requiring real-time streaming and mid-conversation permission approvals for file operations.

The backend uses Deno (with Node.js support) and implements a process manager that maintains a mapping between web sessions and spawned Claude CLI processes. When a user sends a message through the web UI, the server doesn’t just execute a one-off command—it writes to the stdin of a persistent process and reads from its stdout. Here’s a simplified version of how the streaming works:

// Spawning and managing the Claude CLI process
const process = new Deno.Command("claude", {
  args: ["--project", projectPath],
  stdin: "piped",
  stdout: "piped",
  stderr: "piped",
}).spawn();

// Writing user messages to Claude's stdin
const writer = process.stdin.getWriter();
await writer.write(new TextEncoder().encode(userMessage + "\n"));

// Streaming Claude's responses back to the web client
const reader = process.stdout.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  
  // Parse CLI output and forward to WebSocket/SSE
  const chunk = new TextDecoder().decode(value);
  await webSocket.send(JSON.stringify({
    type: "response",
    content: chunk
  }));
}

The interesting part is handling permission requests. Claude CLI will pause and ask for confirmation before executing potentially dangerous operations (like writing files or running shell commands). The WebUI detects these prompts by parsing stdout for specific patterns, then sends them to the frontend as modal dialogs. When the user approves or denies, the response is written back to stdin, and the process continues. This creates a synchronous request-response pattern within an otherwise asynchronous streaming flow.

The frontend is a React application that maintains conversation history in browser localStorage. Each message is stored with metadata about file operations, timing, and project context. This persistence layer is crucial because the underlying Claude CLI doesn’t maintain its own history—each spawn is a fresh start. The WebUI reconstructs context by replaying conversation history when switching projects or resuming sessions:

// Restoring conversation context on page reload
useEffect(() => {
  const savedHistory = localStorage.getItem(`conversation_${projectId}`);
  if (savedHistory) {
    const messages = JSON.parse(savedHistory);
    setConversationHistory(messages);
    
    // Optionally replay context to Claude CLI
    messages.forEach(msg => {
      if (msg.role === "user") {
        sendToClaudeCLI(msg.content, { silent: true });
      }
    });
  }
}, [projectId]);

The security model is worth examining. The WebUI doesn’t implement its own authentication—it relies on Claude CLI’s existing API key configuration. But it adds a layer of network security: the server binds to localhost by default, and users must explicitly configure it to accept external connections. For team environments, this means you’ll need to layer on additional auth (reverse proxy with OAuth, VPN, etc.) since the tool itself doesn’t handle multi-user authentication.

One clever architectural decision is the dual-mode transport support. The server can stream responses via either Server-Sent Events (SSE) or WebSockets. SSE is simpler and works through more corporate firewalls, while WebSocket enables bidirectional communication for more responsive permission dialogs. The frontend automatically falls back to SSE if WebSocket connection fails, ensuring broader compatibility without requiring server-side configuration changes.

Gotcha

The most significant limitation is the dependency chain: you need Claude CLI installed, properly authenticated with an Anthropic API key, and working correctly before claude-code-webui becomes useful. If Claude CLI has issues—authentication failures, API quota exhaustion, version incompatibilities—the WebUI inherits all of them while adding its own layer of complexity. Debugging becomes a multi-level exercise: Is the problem in the web server? The WebSocket connection? The CLI process spawn? The Claude API itself?

Security-wise, you’re running a web server that can execute arbitrary code through Claude. Even bound to localhost, this is a meaningful attack surface. If you expose it to your network (for mobile access) without additional authentication, anyone with network access can use your Claude API credits and execute code in your project directories. The tool doesn’t include rate limiting, API key scoping, or audit logging—features you’d want in a production multi-user environment. And because the WebUI maintains conversation history in browser localStorage, clearing your browser cache means losing all context. There’s no server-side persistence option, no backup mechanism, and no way to share conversation history between devices or team members.

Verdict

Use if: You need to access Claude’s coding capabilities from mobile devices or tablets, you’re onboarding non-technical team members who struggle with CLI workflows, or you frequently switch between projects and want persistent conversation history with visual context. It’s particularly valuable if you’re doing live coding demos where showing a browser UI is clearer than a terminal, or if you want to quickly review and approve Claude’s file changes from anywhere. Skip if: You’re comfortable in the terminal and value the security and simplicity of direct CLI usage, you don’t want to manage an additional server process and its dependencies, you need team features like shared conversation history or multi-user authentication, or you’re working in security-sensitive environments where running a local web server that executes code raises compliance concerns. Also skip if Claude CLI isn’t already part of your workflow—the added installation complexity isn’t worth it unless you’re committed to the underlying tool.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/ai-dev-tools/sugyan-claude-code-webui.svg)](https://starlog.is/api/badge-click/ai-dev-tools/sugyan-claude-code-webui)