# Claudedeck

> Self-hostable web UI and admin console for the Claude Code CLI — multi-user streaming chat with per-agent MCP servers, instructions, and model management.

- **Type:** MCP server
- **Install:** `agentstack add mcp-razlen-claudedeck`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [RaZLeN](https://agentstack.voostack.com/s/razlen)
- **Installs:** 0
- **Category:** [Cloud & Infrastructure](https://agentstack.voostack.com/c/cloud-infrastructure)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [RaZLeN](https://github.com/RaZLeN)
- **Source:** https://github.com/RaZLeN/claudedeck

## Install

```sh
agentstack add mcp-razlen-claudedeck
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# ClaudeDeck

**A self-hostable web UI and admin console for [Claude Code](https://claude.com/claude-code).**

ClaudeDeck turns the Claude Code CLI into a multi-user chat service you can run on your own
server. Your users open a browser, pick an agent, and chat — each message is a Claude Code
run on the backend, streamed back token by token. Administrators configure everything from a
web panel: which model to use, which MCP servers each agent can reach, the agent's system
instructions, and who's allowed in.

It started life as the reusable core of an internal "AI analyst" product and was extracted
into a general-purpose framework: **bring your own agent persona and MCP tools, and you have a
production-shaped chat app around Claude Code without writing the plumbing.**

---

## Screenshots

**Chat** — streaming markdown replies, a searchable session sidebar, and an agent-produced
artifact card (view / copy / download):

**Structured questions** — an agent can ask clickable single / multi / free-text questions
instead of plain prose; the answers come back as its next message:

**Admin console** — manage agents (per-agent model, enable/disable), MCP servers, instructions
and users, all from the browser:

## Why

The Claude Code CLI is great in a terminal, but turning it into a shared web service means
solving the same problems every time: streaming `claude -p` over a WebSocket, persisting
conversations, resuming sessions, letting non-technical users talk to it, and giving admins a
safe way to change the model / tools / prompt without redeploying. ClaudeDeck is that layer.

## Features

- **Streaming chat** over WebSocket — token-by-token, with conversation history persisted in
  PostgreSQL and `--resume` continuity across messages.
- **Multiple agents.** Each agent is a Claude Code *workspace* (its own `CLAUDE.md`, rule
  files, MCP servers and model). Users pick which agent to talk to; admins create and edit
  them from the panel.
- **Per-agent MCP management.** Add/remove/enable HTTP & SSE MCP servers from the admin UI and
  check their live connection status — no redeploy. (stdio/command servers are intentionally
  rejected via the UI to avoid turning the panel into remote code execution.)
- **Live instruction editing.** Edit an agent's `CLAUDE.md` and `.claude/rules/*.md` from the
  browser; changes apply to the next message.
- **Model selection.** A global default model plus per-agent overrides, all editable in the panel.
- **Structured output (optional).** Agents can emit two marker blocks that the UI renders
  specially: **questions** (clickable single/multi/text forms) and a final **artifact**
  (a markdown document shown as a view/copy/download card). See [Structured output](#structured-output).
- **Local user accounts** with an admin role, managed in the panel. Passwords are scrypt-hashed.
- **Admin console**: settings, agents, instructions, MCP servers, users, and Claude CLI status/version.
- **Dockerized**: `docker compose up` brings up the app, PostgreSQL, and the pinned Claude CLI.

## Architecture

```
Browser (chat / admin)
   │   HTTP + WebSocket
   ▼
Node.js + Express backend ──spawn──> claude -p (Claude Code CLI)
   │                                     │
   ├── PostgreSQL 16                     ├── agents//CLAUDE.md + .claude/rules/*.md
   │   users / sessions / messages       └── agents//.mcp.json  (MCP servers)
   │   settings / agents
   └── express-session (cookie)
```

- Each chat message spawns `claude -p  --output-format stream-json --include-partial-messages
  --resume  --model ` with the agent's workspace as the working directory. The
  backend parses the stream, filters out marker blocks, and forwards visible text to the browser.
- The CLI version is **pinned** in `backend/Dockerfile` because the stream-json output contract
  is version-sensitive.

```
claudedeck/
├── backend/            # Node.js + TypeScript (Express, ws, pg)
│   ├── src/
│   │   ├── index.ts            # server, session cookie, WS, bootstrap, graceful shutdown
│   │   ├── auth/               # local-auth (login), password (scrypt), access (requireAuth/Admin)
│   │   ├── claude/             # session-manager (spawn CLI), marker-parser, mcp-admin
│   │   ├── config/             # settings, agents, agents-logic (pure)
│   │   ├── db/migrate.ts       # idempotent SQL migration runner
│   │   ├── ws/                 # chat-handler, expiration cron
│   │   └── api/                # routes (sessions/agents), admin (settings/agents/mcp/users)
│   └── test/                   # node:test unit tests
├── frontend/           # static HTML/CSS/vanilla JS (chat, admin, login)
├── agents/
│   ├── _base/          # template copied when you create a new agent
│   └── default/        # the built-in "Assistant" agent
├── db/migrations/      # 001_init.sql (base schema)
├── docker-compose.yml
└── .env.example
```

## Quick start (Docker)

Requirements: Docker + Docker Compose, and a Claude subscription/API access for the CLI.

```bash
git clone https://github.com/RaZLeN/claudedeck.git
cd claudedeck
cp .env.example .env
# Edit .env: set SESSION_SECRET (random 32+ bytes) and ADMIN_PASSWORD.

# The container runs as uid 1000 and writes agent config into ./agents from the admin panel:
sudo chown -R 1000:1000 ./agents

docker compose up -d --build
```

Then authenticate the Claude CLI **once** (its auth is stored in a named volume and survives
rebuilds):

```bash
docker compose exec -it app claude login
```

Open `http://localhost:3000`, log in with the admin credentials from `.env`, and start chatting.
Check the **Claude CLI** tab in the admin panel to confirm the CLI is authenticated.

### First admin

On first start (empty users table) ClaudeDeck creates an admin from `ADMIN_USERNAME` /
`ADMIN_PASSWORD` (defaults `admin` / `admin`, with a warning). **Change the password** in the
admin panel or set `ADMIN_PASSWORD` before exposing the service.

## Configuration

Most things are configured in two places: environment variables (infra) and the admin panel
(runtime). Environment variables live in `.env` (see `.env.example` for the full list):

| Variable | Purpose | Default |
|---|---|---|
| `PORT` | HTTP/WS port | `3000` |
| `SESSION_SECRET` | Cookie signing secret (32+ bytes). Required in production. | `change-me` |
| `COOKIE_SECURE` | Set `true` when served over HTTPS | `false` |
| `APP_TITLE` | Branding shown in the UI (also editable in the panel) | `ClaudeDeck` |
| `ADMIN_USERNAME` / `ADMIN_PASSWORD` | First admin, created once | `admin` / `admin` |
| `CLAUDE_MODEL` | Default model when an agent has no override | `sonnet` |
| `CLAUDE_MAX_SESSIONS` | Max concurrent CLI processes | `5` |
| `CLAUDE_MAX_TURNS` | Max CLI turns per message | `100` |
| `CLAUDE_SESSION_EXPIRY_HOURS` | Idle hours before a session is marked expired | `24` |
| `POSTGRES_*` | Database connection | see `.env.example` |

### Admin panel options

Open `/admin` as an administrator:

- **Settings** — the default model (`opus` / `sonnet` / `haiku`, or an exact model id) and the
  app title.
- **Agents** — create, edit, enable/disable, and order the agents users can pick. Each agent has
  a key (immutable), a label, and an optional per-agent model override. Creating an agent copies
  the `agents/_base` template into `agents//`.
- **Instructions** — edit the selected agent's `CLAUDE.md` and `.claude/rules/*.md` files. Changes
  take effect on the next message (each message is a fresh CLI process reading these files).
- **MCP servers** — manage the selected agent's HTTP/SSE MCP servers and check their live status.
  Both `.mcp.json` (definitions) and `.claude/settings.json` (enablement + tool pre-approval) are
  written together so the servers actually work in non-interactive `claude -p`.
- **Users** — create/edit/delete local accounts, toggle admin and disabled flags, reset passwords.
  The last active administrator is protected from removal.
- **Claude CLI** — whether the CLI is authenticated, its version, and a read-only update check.

## Defining an agent

An agent is just a directory under `agents/`. The `default` agent is a good example:

```
agents/default/
├── CLAUDE.md                    # persona + instructions (the agent's system context)
├── .claude/
│   ├── rules/structured-output.md   # extra rule files referenced from CLAUDE.md
│   └── settings.json            # enabled MCP servers + tool allow-list (managed by the panel)
└── .mcp.json                    # MCP server definitions (managed by the panel)
```

To add an agent, either create it in the admin panel (recommended — it scaffolds from
`_base`) or copy `agents/_base` to `agents//`, edit `CLAUDE.md`, and add a row in the
admin **Agents** tab with the same key.

## Structured output

Agents can opt into two marker blocks (each marker on its own line). They're filtered out of the
visible chat text and rendered specially. Everything else streams as normal markdown.

**Questions** — present clickable choices:

```
>>
{ "questions": [
  { "id": "env", "text": "Which environment?", "type": "single", "options": ["dev","staging","prod"] },
  { "id": "notes", "text": "Anything else?", "type": "text" }
] }
>>
```

`type` is `single` (radio), `multi` (checkboxes) or `text`. The user's answers come back as the
agent's next message.

**Artifact** — a final document the user can keep:

```
>>
# Title
...markdown...
>>
```

Rendered as a card with view / copy / download, and saved with the session. These are documented
for the agent in `agents/default/.claude/rules/structured-output.md`; reuse or drop them per agent.

## Security notes

- **Authentication** is local username/password with scrypt-hashed passwords and a signed,
  HTTP-only session cookie. Put the app behind HTTPS (`COOKIE_SECURE=true`) in production.
- **MCP via the panel is restricted to http/sse** — `stdio`/`command` servers are rejected so the
  admin UI can't be used to run arbitrary commands on the host.
- **Workspace paths are sandboxed** under `agents/`; instruction/MCP file paths are whitelisted and
  traversal-guarded.
- The container runs as a **non-root** user (`node`, uid 1000).
- **No external calls from the UI** — the frontend has no build step and vendors its two
  rendering libraries (`marked`, `DOMPurify`) under `frontend/js/vendor/`, so nothing is
  loaded from a CDN. It works fully offline / air-gapped once the CLI is authenticated.
- This is a single shared Claude Code identity (the CLI login). All agents use it; per-agent
  isolation is at the workspace/MCP/instruction level, not separate Claude credentials.

## Upgrading the Claude CLI

The CLI version is pinned in `backend/Dockerfile` (`npm install -g @anthropic-ai/claude-code@`)
because the stream-json contract this app parses can change between versions. To upgrade: bump the
version in the Dockerfile, `docker compose build app && docker compose up -d app`, then sanity-check
streaming. The **Claude CLI** admin tab shows the current vs. latest version but never auto-updates.

## Development (without Docker)

```bash
cd backend
npm install
npm run build      # tsc → dist/
npm test           # node:test unit tests
npm run dev        # tsx watch (needs a reachable PostgreSQL + a logged-in claude CLI on PATH)
```

You'll need a PostgreSQL instance (point `POSTGRES_*` at it), the `claude` CLI on your `PATH`
and authenticated, and `CLAUDE_AGENTS_DIR` pointing at the repo's `agents/` directory. The
backend applies migrations and bootstraps the default agent + admin on startup.

## License

[MIT](./LICENSE).

> Not affiliated with Anthropic. "Claude" and "Claude Code" are trademarks of Anthropic.
> ClaudeDeck drives the Claude Code CLI; you bring your own Claude access.

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [RaZLeN](https://github.com/RaZLeN)
- **Source:** [RaZLeN/claudedeck](https://github.com/RaZLeN/claudedeck)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-razlen-claudedeck
- Seller: https://agentstack.voostack.com/s/razlen
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
