A prototype IDE for AI-assisted development built with Next.js and the Claude Agent SDK. Fury IDE provides a web-based interface for interacting with Claude, managing chat sessions, building visual workflows, and organizing project notes.
- SDK-backed sessions - Sessions run on the Claude Agent SDK (
@anthropic-ai/claude-agent-sdk): one persistent, warm streaming query per session, with mid-session model switching, native rewind, and background-task activity. A legacy Claude CLI path remains behind thesdkSessionsEnabledsetting (on by default) - Unified session list - Browse all sessions from
~/.claude/history.jsonlwith live session indicators - Streaming responses - Real-time streamed output over SSE with tool use activity indicators
- Markdown rendering - Assistant responses rendered with syntax highlighting (via
react-markdown,remark-gfm,rehype-highlight) - Rich text input - TipTap-based editor with code block support (Enter to send, Shift+Enter for newline)
- Stop/Kill controls - Abort an in-flight turn or kill a stuck session's warm process
- AskUserQuestion support - Interactive dialog when Claude requests user input via the AskUserQuestion tool
- Prompt suggestions - Detects stale/idle sessions with incomplete responses and suggests follow-up prompts (configurable)
- Long conversation warnings - Visual indicator when sessions exceed 50 messages
- Compaction detection - Hides context compaction messages from the transcript with visual indicator
- Drawflow-based visual canvas - Drag-and-drop node editor for building workflows
- Node types - Rectangle, Diamond, and Circle nodes with configurable inputs/outputs
- Per-node chat - Double-click any node to open a chat session scoped to that node
- Workflow persistence - Create, rename, delete, and auto-save workflows to disk
- Import/Export - Workflows stored as JSON in
.claude-workflows/
- Stream - Live stream of tool use events, text output, and errors during Claude responses
- File Tree - Explore the active session's project directory (filters out
node_modules,.next,.git, etc.) - Notes - Per-project rich text notes with auto-save (stored in
~/.claude-session-notes/) - MCP Servers - Manage Model Context Protocol servers with a guided wizard
- Allow external connections - Toggle to permit or block access from non-localhost IPs
- Prompt suggestions - Toggle to enable/disable follow-up prompt suggestions for stale sessions
- Light/Dark theme - Toggle via toolbar button, persisted in localStorage
- Directory picker - Browse filesystem to select project directories for new sessions
- Resizable panels - All panels are drag-resizable via
react-resizable-panels - UI state persistence - Active tab and workflow selection restored across page reloads
Fury supports voice dictation for prompts and text-to-speech playback of Claude's responses. Both are off by default.
Microphone button in the chat editor uses the browser's Web Speech API. Spoken punctuation ("period", "comma", "question mark", "new paragraph", etc.) is converted inline. Say "send" to submit (5-second delay allows corrections). Recording auto-stops after 30 seconds of silence.
- Browsers: Chrome or Edge (Firefox does not implement Web Speech)
- Locale: hardcoded to
en-US - Privacy note: Chrome/Edge route audio through their cloud speech service — no local STT server is involved
Toggle in Settings. The pipeline cleans markdown out of the response, optionally summarizes it, then synthesizes audio with Kokoro-82M.
Synthesizer (ttsProvider in settings):
| Mode | Setup |
|---|---|
local |
None — bundled kokoro-js runs Kokoro-82M in the Node process |
remote |
Set ttsRemoteHost / ttsRemotePort to a server exposing POST /kokoro/tts (body { text }, returns WAV) |
Voice is af_heart (American female). Kokoro-82M v1.0 supports English only —
no Russian or other non-bundled languages.
Summarizer (summarizerProvider in settings): Optional but recommended for
long responses.
| Mode | Setup |
|---|---|
none |
None — long responses are truncated at the first sentence after 300 chars |
haiku |
Set anthropicApiKey — uses claude-haiku-4-5 |
ollama |
Set ollamaHost / ollamaPort — picks the largest loaded model, POSTs to /api/chat |
The summarizer is context-aware: turns that wrote to files get a deterministic template ("I updated X. See details below.") and skip the LLM entirely; longer responses go through a two-pass tighten + list-stripping pipeline.
Source: lib/tts.ts, app/api/tts/route.ts, components/RichTextEditor.tsx
(dictation).
- Framework: Next.js 16 (App Router, Turbopack)
- Language: TypeScript
- Styling: Tailwind CSS 4, shadcn/ui components (Radix UI primitives)
- Editor: TipTap (rich text input + notes)
- Canvas: Drawflow
- AI: Claude Agent SDK (
@anthropic-ai/claude-agent-sdk) — one persistent streamingquery()per session viaSdkSessionManager; the legacy Claude CLI child-process path (SessionManager) remains as a fallback - Code Search: codemogger (local semantic + keyword search via MCP)
- Fonts: Geist Sans / Geist Mono
| Data | Location |
|---|---|
| Session transcripts | ~/.claude/projects/<slug>/<sessionId>.jsonl (written by the Claude Code subprocess) |
| Chat history | ~/.claude/history.jsonl (Claude Code global, also appended by Fury) |
| Transcript archive | ~/.claude/fury.db (SQLite, Fury managed) |
| Workflows | .claude-workflows/*.json (project-local) |
| UI state | .claude-ui-state/state.json (project-local) |
| App settings | .claude-ui-state/settings.json (project-local) |
| Saved prompts | .claude-prompts/*.json (project-local) |
| Session notes | ~/.claude-session-notes/*.md (user home) |
| MCP servers | ~/.claude.json (user scope) or .mcp.json (project scope), created and managed by Claude CLI via claude mcp add/remove |
| Code search index | ~/.codemogger/index.db (codemogger, user home) |
| Theme | localStorage (browser) |
Claude Code auto-deletes session JSONL files after 30 days (controlled by cleanupPeriodDays in ~/.claude/settings.json). Fury maintains an independent SQLite archive at ~/.claude/fury.db so transcripts survive cleanup.
How it works:
The database is populated automatically through four triggers:
- Startup scan — On first connection, scans all
~/.claude/projects/*/JSONL files and archives any that are new or changed. - History watcher — When
history.jsonlchanges (any session, including external CLI), archives the recently-active sessions. - Transcript watcher — When a watched session's JSONL changes during a live session, archives it immediately.
- Archive-on-read — When
/api/transcriptloads a JSONL, persists it as a fire-and-forget side effect.
A SHA-256 hash per session ensures duplicate archival is a no-op. When a JSONL file is missing (deleted by cleanup), the transcript API falls back to SQLite transparently. The history list merges archived sessions so cleaned-up sessions remain visible.
Schema (core tables):
sessions— session metadata: project path, display text, message count, content hash, status (active/archived), and a JSONmetadatablob (model, context tokens/window, token totals, compaction count)messages— parsed transcript messages (role, content, timestamp, turn index)raw_jsonl— original JSONL lines preserved for full-fidelity restorationusage_events— per-message token usage (input / output / cache read + write,is_sidechainfor subagents) that powers the Stats tab, retained even after a session is archived
Plus internal tables for the model catalog and pricing cache.
Technology: @libsql/client (Turso/libSQL) with WAL mode for concurrent read/write safety.
Manual population:
npx tsx scripts/populate-db.ts # Archive all existing JSONL files
npx tsx scripts/populate-db.ts --dry-run # Preview without writing
npx tsx scripts/populate-db.ts --verbose # Show per-file detailsFury runs sessions on the Claude Agent SDK (sdkSessionsEnabled, on by default). Each session is backed by one long-lived streaming query() and its warm CLI subprocess, tracked in memory by SdkSessionManager:
-
Creating a session — A frontend operation: a UUID is generated and held in React state. Nothing spawns and no server-side state is created until the first message; the session materialises on disk (and in the manager) when the first prompt is sent.
-
Sending a message — The first send opens a persistent
query()with a streaming-input generator and spawns the CLI subprocess; the prompt is pushed into that input stream and the response streams back over SSE. Subsequent messages reuse the same warm query and process — no cold start per turn. Per-turn tokens, context window, and partial output are tracked in memory and emitted live. -
Switching sessions — A frontend operation: the UI swaps which transcript is displayed. The other session's query keeps running in the background — its output is persisted to JSONL and its health/SSE events continue, so a background turn (or a subagent it dispatched) stays "live" with its dots still bouncing.
-
Conversation continuity — The live query holds context in-process; across a server restart the session re-opens with the SDK's
resume, replaying the archived transcript. Rewind uses the SDK's nativeresume+resumeSessionAt. -
Model, stop & stuck handling — The model can be switched mid-session (
setModel, replayed into the query). Stop/interrupt aborts the current turn while leaving the session resumable; a hang watchdog surfaces a stuck turn so it can be killed. Background tasks (subagents,run_in_backgroundBash, Monitor) drive their own turns via injected<task-notification>s. -
Parallel sessions — Multiple sessions run concurrent warm queries, each with its own subprocess and session UUID. The
activeSessionRefmechanism ensures only the currently-viewed session's SSE handler updates the display, preventing cross-session contamination. Deleting a session terminates its warm process.
Legacy CLI path — With
sdkSessionsEnabledoff, Fury falls back to the original stateless model: a short-livedclaude --print --session-id <uuid>(--resumefor follow-ups) is spawned per prompt viaSessionManager, with conversation continuity managed by the CLI re-reading the JSONL. The SSE stream shape is identical either way, so the frontend keeps calling/api/clauderegardless.
- Node.js 20+
- Claude Code CLI installed and authenticated (
claudecommand available in PATH) — used by both the Agent SDK and the legacy fallback path
cd Fury
npm install
npm run devOpen http://localhost:3879 in your browser.
| Command | Description |
|---|---|
npm run dev |
Start dev server with Turbopack on port 3879 |
npm run build |
Production build |
npm start |
Start production server on port 3879 |
npm run lint |
Run ESLint |
npm test |
Run the Vitest unit suite (fast, no server) |
npm run test:e2e |
Run the Playwright browser/E2E suite (needs the dev server) |
npx tsx scripts/populate-db.ts |
Populate transcript database from existing JSONL files |
Fury has two test layers — a fast Vitest unit suite (tests/unit/) and a
Playwright browser suite (everything else under tests/), including a
few live drives that run real Claude turns and spend tokens.
See tests/README.md for the full breakdown: how to run each layer, which
specs are token-spending live drives, the shared drive harness, and the directory-by-directory map.