claude-code-viewer turns subscription mode into a command generator
A full-featured web-based Claude Code client that provides complete interactive functionality for managing Claude Code projects
At a glance
- What is it?
- A web client for Claude Code that analyses session logs, with a built-in terminal and remote access over Tailscale. Its most interesting decision is defensive: a Terms of Service change in April 2026 led the author to make chat sending, session resuming and permission approval opt-in, and to reduce subscription mode to copying a ready-made CLI command.
- Who is it for?
- claude-code-viewer suits someone who wants to read and monitor Claude Code sessions from a browser, including a phone, since the read path is independent of the Agent SDK and works regardless of how you authenticate. Choose API key mode if you have one, because subscription mode is deliberately hobbled into producing a command you paste elsewhere rather than sending a message.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 46 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A Terms of Service change split the features in two
The most consequential part of the documentation is a warning about Anthropic's Terms of Service. It states that as of April 2026 those terms prohibit using the Agent SDK to send chat messages with a subscription account, and that while Anthropic's announcements on X suggested personal use may be acceptable, the boundary between permitted and prohibited use remains ambiguous.
The response was to make four capabilities opt-in: chat sending, session resuming, permission approval, and AskUserQuestion. Everything read-oriented stays unrestricted. Real-time conversation log viewing, session history browsing, Git operations and the rest are implemented independently of the Agent SDK and work regardless of your authentication mode. You can start a session from the CLI or from the built-in terminal and watch it live with no restrictions at all.
So the tool has two personalities behind one interface. Read-only analysis is unconditional, and anything that writes to a conversation requires an explicit opt-in on top of a supported authentication mode.
The project's stated core philosophy is zero data loss, effective organisation and a remote-friendly design, and the introduction is explicit that the focus is comprehensive session log analysis: conversation data is preserved and organised through strict schema validation and a progressive disclosure UI that reveals detail on demand rather than dumping everything at once.
Subscription mode becomes a command generator
Authentication is chosen on first launch or from the settings screen, and the two modes are not equivalent.
API key is the default and uses the Anthropic API directly, with all features including chat sending fully available. Subscription mode opts out of the Agent SDK chat features entirely, and the chat input changes shape rather than disappearing. You configure your session options in the form, click a Copy button, and get the equivalent claude CLI command with the corresponding arguments already set. You paste that into any terminal to start or resume the session. Once it is running, the viewer shows the conversation in real-time exactly as before.
That is a genuinely clever response to a licensing constraint. The application stops being a chat client and becomes an assistant for the real client, and the value proposition survives because the log viewing does not depend on how the conversation was started.
The built-in terminal closes the loop. It is a terminal emulator in a panel at the bottom of the screen, so the workflow is form, copy, paste into the panel, and launch, all without leaving the browser. You never touch a real shell.
The result is a tool where the subscription path gives you a session you watch, and the API key path gives you a session you drive.
The base path validator rejects more than it accepts
Serving the app below a URL prefix is a first-class feature, configured with --base-path or the CCV_BASE_PATH environment variable, and the reason it needs care is that the prefix touches everything.
Once a base path is set, the UI, the API, the SSE connection, the terminal WebSocket, the authentication cookies, the PWA manifest and the service worker all use that prefix. That is a long list of things to get right, and it explains the accompanying nginx configuration, where proxy_buffering is off and the upgrade headers are set so the terminal WebSocket survives the hop:
location /ccv/ {
proxy_pass http://127.0.0.1:3400;
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}The reverse proxy has to preserve the prefix when forwarding, which is the part people get wrong.
The validation rules are strict and worth reading before you pick a prefix. Nested URL-safe segments are accepted, so /tools/ccv works. Values containing traversal segments, backslashes, query strings, fragments, spaces or percent-encoding are rejected outright. That is a deny list rather than an allow list, and the reasoning is sensible given the prefix ends up in cookie paths, manifest URLs and a service worker scope.
Node 22.13 is a floor, not a suggestion
System requirements name three things: Node.js 22.13.0 or later, Claude Code v1.0.125 or later, and macOS and Linux, with Windows explicitly not supported. The Node floor is the interesting one because the development script relies on it. The backend dev command runs the TypeScript entry point directly under node with --watch and --env-file-if-exists, which is a flag from that generation of Node rather than something older, and it is also why there is no separate compile step for the backend in development.
The build path differs, using tsdown for the backend and Vite for the frontend, with the whole build driven by a shell script rather than a single package.json line. Type checking uses tsgo, and linting and formatting use oxlint and oxfmt rather than eslint and prettier, both invoked with --ignore-path .gitignore and --no-error-on-unmatched-pattern so generated and vendored files are skipped the same way git skips them.
The command surface is small and complete:
claude-code-viewer [options]
Options:
-p, --port <port> Port to listen on (default: 3000)
-h, --hostname <hostname> Hostname to listen on (default: localhost)
-v, --verbose Enable verbose debug logging
-P, --password <password> Password for authentication
-e, --executable <executable> Path to Claude Code executableThe remaining options cover the Claude directory path, an API-only mode with no web interface, and the base path. Configuration is available through either the flags or environment variables, with the flags taking precedence.
The compose file ships with your history mount disabled
The container is a three-stage build on node:22-slim that enables pnpm through corepack and adds git and openssh-client, which are there so the Claude Code executable and repository operations work. Dependencies install with --frozen-lockfile and --ignore-scripts against a cache-mounted pnpm store, then the build runs pnpm build followed by pnpm prune --prod. The runtime stage copies node_modules and dist, sets CCV_ENV, PORT, HOSTNAME and a PATH pointing at the local binaries, exposes 3400, and runs a shell entrypoint around node dist/main.js.
The compose file is where the problem is. It declares two volumes, claude_home and workspace, but only workspace is mounted. The claude_home line, which would map to /root/.claude, is present and commented out:
volumes:
# - claude_home:/root/.claude
- workspace:/root/workspaceSince the whole point of the tool is reading conversation history from a Claude directory, a container started from the file as shipped has no persistent /root/.claude, so nothing about your sessions survives replacing the container. The fix is one character, uncommenting that line, but it is the kind of thing that costs an afternoon.
The same file also passes CCV_PASSWORD from the host environment with no default, so an unset variable produces an empty value, while the image sets HOSTNAME to 0.0.0.0 so the server accepts remote connections. Taken together that is an unauthenticated service reachable from the network unless you set the variable, so treat the password as required in any deployment.
Two runtime dependencies, both pinned exactly
The published package has only two runtime dependencies and both are pinned to an exact version rather than a range. The first is @anthropic-ai/claude-code, and the second is @replit/ruspty, which is a native pseudo-terminal binding and the reason the built-in terminal exists at all.
Pinning the Claude Code package exactly is defensible given that the tool parses its session output, where a minor release could change a format. It also creates a version story worth checking: the system requirements ask for Claude Code v1.0.125 or later, while the manifest depends on 2.1.220. Those are different major lines, so the minimum stated for your own installation is not the version the application bundles.
The published tarball contains only dist, as the files field lists nothing else, so anything in the repository outside the build output does not ship. That includes the plugin and skill material, the docs, the mock Claude directory used by tests and the end-to-end scripts. Contributors get the lot; npm consumers get the compiled server and nothing more.
The repository is considerably larger than the package, and it is a pnpm workspace with a Nix flake, a git submodule, Lingui for translations, Drizzle for the database, lefthook for git hooks, oxlint and oxfmt for quality, and both unit and end-to-end test suites driven by vitest and shell scripts.
Remote access is a Tailscale recipe, not a feature
Running the viewer on an always-on machine and reaching it from a phone is presented as a recipe rather than a built-in capability. The three steps are to set up HTTPS on your Tailscale node following Tailscale's own certificates guide, start the viewer bound to every interface with a password, and then open the Tailscale HTTPS URL from the phone:
claude-code-viewer --hostname 0.0.0.0 --port 3400 --password your-secretThe design choice is to delegate transport security to Tailscale rather than build TLS into the application, which keeps the server simple and means the connection is only as private as your tailnet. There is no built-in HTTPS termination, so exposing this to the open internet is not what these instructions are for.
On mobile it is a PWA, so adding it to the home screen gives an app-like interface with an optimised layout and push notifications when sessions complete. Notifications depend on the service worker, which is one of the things the base path feature has to rewrite correctly, so the two features interact.
The documentation is careful to note that you can watch a session you started from the real CLI without any of this, which is the lowest-friction way in: start Claude Code normally and point the viewer at it.
Quiet since mid-August, and pinned below 1.0
The version history is compact and recent. v0.8.0 landed on 2026-08-11, v0.8.1 on 2026-08-18 at 05:10 UTC, and v0.8.2 the same morning at 06:59 UTC, with the last push to main on 2026-08-18 as well. As of the date this was written that commit is roughly six weeks old, and the project is at 0.8.2, so it is pre-1.0 and the interface you read about may move.
The manifest version matches the newest tag exactly, which is the sort of consistency worth noticing because it is not guaranteed. Releases are cut by a release script rather than by hand, and prepack runs a build followed by clean-pkg-json, so the published metadata is normalised before it ships.
The repository carries 1,292 stars, 163 forks and 8 open issues, is MIT licensed, and its homepage in the repository metadata points at the npm package page rather than a project site. A PRIVACY.md is present at the root, which is a reasonable thing to find in a tool that reads your entire conversation history, and CHANGELOG.md is there for the release notes the README does not summarise.
For anyone adopting this, the practical reading is that the read-oriented features are stable and independent of the legal ambiguity, while anything that writes to a conversation sits behind an opt-in precisely because the terms were unclear.
Editorial conclusion
claude-code-viewer suits someone who wants to read and monitor Claude Code sessions from a browser, including a phone, since the read path is independent of the Agent SDK and works regardless of how you authenticate. Choose API key mode if you have one, because subscription mode is deliberately hobbled into producing a command you paste elsewhere rather than sending a message. If you deploy the container, do two things first: set CCV_PASSWORD, since the image binds to all interfaces, and uncomment the claude_home volume mount in the compose file, because it ships disabled and your session history will not survive a container replacement.
Frequently asked questions
How do I start claude-code-viewer?
Run npx @kimuson/claude-code-viewer@latest --port 3400 with no install, or install it globally with npm install -g @kimuson/claude-code-viewer and run claude-code-viewer --port 3400. Then open http://localhost:3400.
Why is chat sending disabled when I use a Claude subscription?
The README states that as of April 2026 Anthropic's Terms of Service prohibit using the Agent SDK to send chat messages with a subscription account, and that the permitted boundary remains ambiguous. Chat sending, session resuming, permission approval and AskUserQuestion were therefore made opt-in.
Can I still watch a Claude Code session live with subscription authentication?
Yes. Real-time conversation log viewing, session history browsing and Git operations are implemented independently of the Agent SDK and stay available in either mode. You start the session from the CLI or the built-in terminal, and the viewer displays it as usual.
What are the system requirements for claude-code-viewer?
Node.js 22.13.0 or later, Claude Code v1.0.125 or later, and macOS or Linux. Windows is not supported.
Will claude-code-viewer keep my session history in Docker?
Not with the compose file as shipped. It declares a claude_home volume but the line mapping it to /root/.claude is commented out, so only the workspace volume is mounted. Uncomment that line to persist session data across container replacements.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/d-kimuson-claude-code-viewer)