For detailed app building guides, API references, template rules, and code examples, see CLAUDE-REFERENCE.md.
Enso is a deeply personal AI assistant that understands who you are, discovers what you care about, and mobilizes a full team of AI agents to help you make real progress on the goals that matter most.
Every installation is self-hosted, open-source, and fully owned by the user — you own the factory, not just the product.
Enso follows a three-phase arc that compounds over time:
1. Understand the user deeply — Enso scans the user's digital life across 12 data sources (Kindle library, YouTube subscriptions, browser history, email, projects, Steam games, movies/TV, photos, Twitter/X, QQ Music, system apps). Each scan ingests content into the Knowledge Cortex — an interlinked wiki of 2000+ pages that builds a semantic map of who the user is, what they know, and what they're drawn to. Cross-source synthesis connects a Kindle book on quantitative finance to an AlphaRank project to a YouTube channel on systematic investing. The system sees patterns the user might not.
2. Identify what matters — From the Cortex, Enso infers Focus Areas — concrete, outcome-oriented goals the user is working toward. Not category labels ("Quantitative Finance") but actionable goals ("Develop AlphaRank into a Market-Beating Quant Tool"). Each focus has clarity levels (emerging → developing → clear), a deeper personal WHY, adjacent pursuits, and evidence grounded in the user's actual data. Focus areas are first-class Cortex citizens — their wiki pages accumulate everything: evaluation briefings, conversation insights, sprint results, and cross-references.
3. Iterate: Evaluate → Discuss → Evolve — Each focus area has a three-step iterative workflow:
- Evaluate: An orchestration-powered deep study. Multiple AI agents (researcher, codebase analyst, synthesizer) work in parallel to gather web research, analyze project code and sprint history, cross-reference Cortex knowledge, and produce a comprehensive briefing. Progress is visible live in the Evolve tab.
- Discuss: A clean strategic dialogue with the AI (no tool calls, no app cards — just focused thinking). The AI arrives prepared with the evaluation briefing and all Cortex context, acting as a co-strategist to flesh out the problem space, define success criteria, and build a clear vision.
- Evolve: The full conversation context feeds into an
/Evolveorchestration — a multi-agent sprint where a team of AI agents (Project Leader, Architect, Engineer, QA, and domain specialists) execute on the agreed goals. Each agent is a Claude Code session with role-specific prompts, coordinated through a DAG execution engine. This cycle repeats — each sprint's results feed back into the Cortex, refining the focus and informing the next evaluation.
This arc repeats and compounds: each sprint produces results that feed back into the Cortex, which refines the focus areas, which inform the next strategic dialogue, which shapes the next sprint. The system gets smarter about the user with every cycle.
- Knowledge Cortex — The single brain. Every data source scan, research result, conversation memory, and user profile lives as interlinked wiki pages at
~/.enso/wiki/(Karpathy's LLM Wiki pattern). Cross-source synthesis finds semantic connections across all 12 sources. Daily discovery searches the web for top interests and emails a personalized intelligence briefing. - Conversation Context Registry — A general-purpose framework where features (focus areas, projects, data sources) register as context providers for specific conversations. Enables context-aware system prompts, proactive messages on state changes, and event-driven triggers from external systems. Focus areas are the first consumer.
- Adaptive answers — Responses flow through a deterministic tool-to-UI pipeline: interactive research boards, data visualizations, photo studios, knowledge graphs — not walls of text. No LLM call needed for rendering. Focus conversations use a clean dialogue mode — pure text, no tool calls.
- AI teams — Complex goals are auto-decomposed into DAGs and executed by parallel Claude Code-powered agents with approval gates and shared context. Five agent roles: researcher, architect, builder, coder, reviewer.
- Unified LLM layer — Single
llm()function for all LLM calls. Tier-based model selection (fast/utility/pro), auto API key resolution, built-in retry with backoff. - Self-evolving — The platform includes Claude Code directly (
/code), so it can build and modify itself from within. Every user-built app is dual-registered as both a UI experience and an agent-callable tool — the ecosystem compounds with use. - User owns the factory — Each installation is a complete codebase with build tools. During setup, Claude Code personalizes the source code based on who the user is. The resulting APK is a custom app, not a configured generic one.
Enso has two layers:
- React Frontend — Browser-based chat UI (Vite + React 19 + Tailwind CSS 4 + Zustand), including a conversation sidebar for multiple persisted threads per client
- Enso Server (Backend) — Standalone Express + WS server providing deterministic tool-to-template rendering + Claude Code integration. Entry:
server/standalone.ts(dev) orserver/guardian.ts(production).
- Normal chat (Q&A): Browser → WS → standalone agent (
standalone-agent.ts, Gemini) → text response →deliverEnsoReply→ text card - Normal chat (tool use): Agent calls a tool registered via
registerLocalTool()→ result captured →deliverEnsoReply→ text card + auto-enhance viaconsumeRecentToolCall()→ app card rendered alongside text (no extra LLM call) - Claude Code: Browser → WS →
server.ts→ spawnclaude.exe(NDJSON stream) → streaming terminal card + interactive questions
src/ # React frontend (Vite entry)
├── App.tsx # Root layout
├── cards/ # Card renderers (DynamicUICard, TerminalCard, ShellCard, etc.)
├── components/ # TabNavigation, TasksView, EvolveView, ProjectsView, SettingsView, CardTimeline, CardContainer, ChatInput, ConversationSidebar, MarkdownText, ConnectionPicker, ToastContainer, BackgroundTaskBar
├── store/chat.ts # Zustand state
├── lib/ # ws-client, sandbox (Sucrase JSX→JS), enso-ui (17 components), connection manager, notifications, useElapsedTime
└── types.ts
server/ # Enso server (the backend)
├── standalone.ts # Dev entry — boots Express + WS standalone
├── guardian.ts # Production entry — supervises standalone with watchdog
├── apps/ # Shipped apps (checked into git)
│ ├── <appId>/ # app.json + template.jsx + executors/*.js
│ ├── cortex/ # Cortex Explorer (wiki dashboard, reader, graph, discovery, cross-reference)
│ ├── kindle/ # Kindle Library (data source + browse/search)
│ ├── youtube_manager/ # YouTube Manager (data source + browse/search)
│ ├── browser/ # Browser Data (history + bookmarks, unified)
│ ├── email_scanner/ # Email Scanner (data source + browse)
│ ├── projects/ # Projects Scanner (data source + browse)
│ └── system_info/ # System Info (data source + browse)
└── src/
├── server.ts # Express + WS server
├── standalone-agent.ts # Gemini-powered agent loop (chat, tool use, hooks)
├── outbound.ts # Barrel re-export (delivery, enhance, card actions, context)
├── outbound/ # Outbound submodules (card-actions, card-context, delivery, helpers)
├── llm.ts # Unified LLM call layer (tier-based model, retry, timeout)
├── cortex-tools.ts # Cortex wiki engine (ingest, search, read, lint, cross-reference)
├── cortex-synthesis.ts # Cross-source synthesis engine (LLM-first intelligence)
├── cortex-direct-ingest.ts # Per-item Cortex page creation (zero-LLM)
├── cortex-enrichment.ts # Post-ingest LLM semantic tagging + cross-source references
├── card-to-cortex.ts # Auto-persist app cards as Cortex wiki pages
├── data-source-registry.ts # Centralized DATA_SOURCES descriptors
├── data-source-pipeline.ts # Post-scan auto-ingest to Cortex
├── onboarding.ts # First-run data source onboarding flow
├── ui-generator.ts # Gemini-based tool selection for enhance
├── tool-factory.ts # Validation, auto-heal, and refine utilities
├── task-router.ts # Smart 3-tier message classifier (simple/one-off/orchestrated)
├── orchestrator.ts # Multi-agent orchestration planner and lifecycle
├── orchestrator-engine.ts # DAG execution engine with parallel agents
├── build-via-claude.ts # Build App via Claude Code session
├── mission-planner.ts # Mission analysis + sequential app building
├── evolution.ts # Self-evolution sprint system with AI persona agents
├── project-manager.ts # Project CRUD, team agents, personas, sprint history
├── app-persistence.ts # Save/load dynamic apps from disk
├── claude-code.ts # Claude Code CLI integration
├── shell-pty.ts # Remote terminal PTY manager (node-pty)
├── *-tools.ts # System app implementations (filesystem, workspace, media, screen, travel, meal)
├── team-leader.ts # Team Leader agent — the living organization (gather → assess → execute → brief → deliver)
├── focus-agent.ts # Focus utilities — analyzeFocusAreas, generateProgressPulse, deliverSprintResults
├── reacts.ts # Async react system — email/WeChat/web feedback → queue → TL processes
├── wechat.ts # WeChat Official Account API (token mgmt, customer service msgs, mass send, followers)
├── wechat-tools.ts # WeChat tools (enso_wechat_send, enso_wechat_followers)
├── wechat-webhook.ts # WeChat webhook (server verification + message receiving + react capture)
├── app-catalog.ts # APP_CATALOG definitions (system + app entries)
├── tunnel-registry.ts # Cloudflare tunnel provisioning for <name>.enso.net
└── native-tools/ # App action bridge
├── registry.ts # App tool discovery + template registry
└── templates/ # Pre-built JSX templates per app
scripts/ # Setup and maintenance scripts
├── personalize-prompt.md # Claude Code prompt for deep UI personalization
├── personalize.cjs # Deterministic fallback personalization (6 persona templates)
├── install.sh / install.ps1 # Legacy install scripts (superseded by ./setup)
└── qr-terminal.js # QR code generator for mobile deep links
setup # One-command setup script (bash, macOS/Linux)
setup.ps1 # One-command setup script (Windows PowerShell)
shared/types.ts # Protocol types shared between frontend and server
The app uses a universal 6-tab navigation that renders as a left rail on desktop and a bottom bar on mobile. Both platforms share the same tab state (activeTab in Zustand) and content views.
| Tab | Purpose | Key Components |
|---|---|---|
| Chat | Conversations with Enso | ConversationSidebar + CardTimeline + ChatInput + PinnedSidebar |
| Cortex | Knowledge browser — wiki pages, graph, discovery | CortexView (dashboard, reader, graph, search) |
| Focus | AI-inferred goals with expert teams and typed focus areas | FocusView (list → detail with Work/Cortex/Experts/Evolve tabs) |
| Tasks | Team Leader command center + scheduled tasks | TasksView (TL dashboard at top + scheduled tasks below) |
| Evolve | Self-evolution hub — evolve everything | EvolveView (quick actions, app ecosystem, sprint/discovery history) |
| Me | Profile, connection, settings | SettingsView (connection, model picker, debug) |
- Desktop:
DesktopTabRail(~56px left rail with icons + labels) + tab content fills remaining space - Mobile:
MobileTabBar(bottom bar, hides when inside a chat conversation) - State:
activeTab(which tab is shown),chatViewOpen(whether a conversation is open on mobile) - No desktop header: All header functions (search, settings, apps menu, connection) are absorbed into their respective tabs
- Projects tab removed: Project-type focus areas cover all project capabilities (team agents, codebase analysis, evolution sprints).
ProjectsViewcode remains accessible via/projectscommand. - Key files:
src/components/TabNavigation.tsx,src/components/FocusView.tsx,src/components/TasksView.tsx,src/components/EvolveView.tsx,src/components/SettingsView.tsx,src/App.tsx
- Multi-conversation:
conversationIdonchat.send,chat.history, etc.; card journals live per thread under~/.enso/cards/<client>/(conversations.json+<conversationId>.jsonl). REST:/api/conversations(CRUD + list). Client:activeConversationIdin Zustand +ConversationSidebar. chat.sendwithrouting.toolId: "claude-code"bypasses the agent, spawns CLI directlyshell.*messages manage PTY sessions —toolMeta.toolId === "shell"routes to ShellCardcard.actioncarriescardId,cardAction,cardPayload— dispatched via four-path resolution
Full
ClientMessage/ServerMessagefield enumeration in CLAUDE-REFERENCE.md. Authoritative types inshared/types.ts.
- Stable card ID generated before dispatch — all blocks reference same card
- Each block's text collected into
AgentStep[]with sequence numbers - Card's
textset to last block (final answer); earlier blocks insteps - Frontend shows expandable "N agent steps" toggle when 2+ steps
- Auto-Enhance: When the agent calls a registered tool,
deliverEnsoReply()checksconsumeRecentToolCall()and automatically renders the app card alongside the text response. No LLM call needed — deterministic based on tool usage. Replaces the old backgroundselectToolForContent()LLM call +enhanceHintapproach. - Fast Enhance (manual fallback): User clicks App button → app selected from dropdown (or auto-detect) → deterministic tool execution → template rendering → app view with Original/App toggle
- Build App: User clicks "Build custom app..." → single-line instruction → Claude Code session in terminal card → writes app files → post-build auto-registration →
buildCompletenotification - Deep Research: User triggers "Deep Dive" on a research card →
handleDeepResearchBuild()spawns Claude Code session → researches topic + writes a single.deep-research-ui.jsxwith bespoke interactive UI tailored to the topic → compile-checked with Sucrase → delivered asgeneratedUIon the research card. No app registration needed — each deep research is a one-off custom experience. - Refine: User types instruction in app view → single LLM call regenerates template JSX only → in-place update (cheapest iteration path)
Available methods in executor function bodies: ctx.callTool(name, params), ctx.listDir(path), ctx.readFile(path), ctx.searchFiles(root, name), ctx.fetch(url, opts?), ctx.search(query, opts?), ctx.ask(prompt, opts?), ctx.store.get/set/delete(key). See CLAUDE-REFERENCE.md for full API details.
17 pre-styled components injected into the sandbox: Tabs, DataTable, Stat, Badge, Button, UICard, Progress, Accordion, Dialog, Select, Input, Switch, Slider, Separator, EmptyState, EnsoUI.Tooltip, EnsoUI.VideoPlayer. 13 accent colors available. See CLAUDE-REFERENCE.md for props and usage.
- Task Router (
task-router.ts): Auto-classifies user messages into 4 tiers via Gemini Flash:simple→ normal agent chat (questions, information requests)research→ direct researcher tool invocation (bypasses agent, progressive streaming)one-off→ single Claude Code session (file ops, bug fixes, single app builds)orchestrated→ multi-agent orchestration (complex goals, sustained projects)
- Orchestrator (
orchestrator.ts): Spawns a Claude Code planning session that decomposes the goal into a task DAG with agent roles. Sends plan to frontend for review/approval. - Execution Engine (
orchestrator-engine.ts): DAG-based executor with configurable parallelism (default: 2 concurrent agents). Each agent = a Claude Code session with role-specific prompt. Hub-and-spoke communication: completed task results stored in shared context and injected into dependent tasks. - 5 agent roles:
researcher(web research + analysis),architect(design + decision),builder(Enso app creation viahandleBuildAppViaClaude),coder(code changes),reviewer(quality validation) - Approval gates: Tasks with
requiresApproval: truepause execution for user review - Frontend:
OrchestrationCard.tsxrenders planning → review → executing → complete phases with live task graph, agent status, progress bar - Protocol:
orchestration.approve,orchestration.pause,orchestration.resume,orchestration.cancelclient messages;orchestrationProgressserver field - Key files:
task-router.ts,orchestrator.ts,orchestrator-engine.ts(backend),OrchestrationCard.tsx(frontend), card type"orchestration"
- Trigger:
/missioncommand or "Mission Planner" tile on WelcomeCard - User describes interests/goals → Claude Code analyzes and proposes 2–5 apps
- Plan written to
server/.mission-plan.json, parsed, sent asmissionPlanto client - User reviews proposals in MissionCard (approve/skip/edit each app)
- Approved apps built sequentially via
handleBuildAppViaClaude - Progress tracked via
missionProgressmessages (analyzing → proposing → building → complete) - Key files:
mission-planner.ts(backend),MissionCard.tsx(frontend), card type"mission"
Enso includes an AI venture capital team that discovers high-potential project opportunities. The /discover [focus] command launches a 5-phase investment process: independent deal sourcing (3 partners with different lenses — demand signals, technology timing, competitive gaps) → pitch session → investment committee challenge (market timing, Enso advantage, feasibility, cost of entry) → deliverables (interactive dashboard + investment memo). Each recommendation receives a verdict: STRONG BUY / BUY / HOLD / PASS. Approved projects → import via Projects card → auto-generated AI team → evolution sprints. See PROJECTS.md for full process.
- Key files:
discovery.ts(VC team + planning prompt),orchestrator.ts+orchestrator-engine.ts(execution) - Trigger:
/discovercommand or "Discover" tile on WelcomeCard - Protocol:
discovery.startclient message type - Cost: ~$8-12 per discovery sprint, ~30 min runtime
- Output: Interactive
.orchestration-ui.jsxdashboard +investment-memo.md
Enso can import and manage any existing software project — scan a codebase, auto-generate a domain-specific AI team + customer personas, then evolve the project through autonomous sprints. Each project gets its own AI team and persona-driven validation loop.
Full operational guide: See PROJECTS.md for the complete system — VC discovery (
/discover), import flow, team/persona generation, the 7-phase evolution sprint pipeline, sprint design rationale (PL triage gate, merged synthesis, fix-verify loop), monitoring procedures, and known limitations.
Quick reference:
- Triggers:
/evolve,/discover,/evolution-history,/sessions - Storage:
~/.enso/projects/<id>/(definition + sprints),~/.enso/orchestrations/<id>/(live workspace) - Sprint planner: Claude Opus with adaptive thinking; up to 6 parallel Claude Code sessions; ~55-65 min per sprint
- Safety rule: Implementation tasks are forbidden from restarting servers, pushing to git, or modifying versions
- Context propagation: Tasks emit
<!-- STRUCTURED_SUMMARY {JSON} -->blocks; the engine parses these to inject compact context into downstream tasks - Resume after restart:
handleOrchestrationResume()rebuilds interrupted sprints from persisted plan + completed task outputs
Session registry — REST API for managing live sessions/orchestrations:
-
GET /api/sessions,DELETE /api/sessions/:runId -
GET /api/orchestrations/active,POST /api/orchestrations/:id/pause,DELETE /api/orchestrations/:id -
GET /api/orchestrations/recoverable— interrupted orchestrations available for resume -
Frontend:
SessionDashboardCard.tsx(/sessionscommand) -
Key files:
evolution.ts,evolution-archive.ts,project-manager.ts,team-generator.ts,orchestrator.ts,orchestrator-engine.ts,orchestration-workspace.ts,session-registry.ts(backend);OrchestrationCard.tsx,EvolutionHistoryCard.tsx,SessionDashboardCard.tsx(frontend)
Full architecture: See CORTEX.md for the complete Cortex system — two-layer wiki architecture, ingest pipelines (direct + LLM), cross-source enrichment, 3-tier related-items algorithm, 13 data sources, Cortex Explorer app, Daily Discovery briefing, context injection, and REST endpoints.
Cortex is the ONLY brain — all knowledge, memory, profile, focus goals, sprint deliverables, and data source content live as interlinked wiki pages at ~/.enso/wiki/. Based on Karpathy's "LLM Wiki" pattern: the LLM incrementally builds and maintains an interlinked markdown corpus instead of re-deriving knowledge via RAG. buildEnsoContext() (in memory-bridge.ts) reads only from Cortex — there are no separate memory, profile, or RAG stores.
Two-layer rule:
entities/— external identity (ISBN, IMDB, Steam ID, YouTube channel ID). 14 types: book, game, movie, tv-series, documentary, album, photo, song, playlist, artist, channel, video, project, article, place, person, twitter-account.synthesis/— system-created (ideas, articles, apps, projects, reports, profile, memory). 5 types: idea, synthesis, app, and the protecteduser-profile.md+conversation-memory.md.focuses/— focus-area goals + per-focus expert pages.
Key agent tools (in cortex-tools.ts): enso_wiki_search, enso_wiki_read, enso_wiki_ingest, enso_wiki_list, enso_wiki_lint, enso_wiki_import_sources, enso_cross_reference.
Key endpoints: POST /api/cortex-enrich (backfill), GET /api/cortex-stats, GET /api/cortex-pulse, POST /api/cortex-direct-ingest, POST /api/cortex/action.
- Key files:
cortex-tools.ts(engine),cortex-synthesis.ts(LLM synthesis),cortex-direct-ingest.ts(per-item pages, zero LLM),cortex-enrichment.ts(semantic tags + cross-refs at scan time),card-to-cortex.ts(auto-persist),memory-bridge.ts(context injection),proactive-engine.ts(active intelligence),entity-model.ts(3-tier related items),server/apps/cortex/(Explorer app)
Full operational guide: See TEAM-LEADER.md for the complete Team Leader architecture — daily routine pipeline, autonomous focus evolution cycle, expert team management, background task tracking, auto-restart, and autonomy policy.
Enso runs as a living organization with a single Team Leader (TL) agent that coordinates everything. The TL wakes up on a configurable schedule, surveys the entire system, staffs expert teams, drives focus evolution cycles autonomously, and only surfaces items to the user when their brain is genuinely needed.
The TL's north star: "Make this user's life better, every single day." Whether that means delivering a focus pulse, fixing a platform bug, launching an evolution sprint, or restructuring an expert team — the TL handles it all.
Morning routine (configurable, default 9am daily):
- Gather signals — Action log errors, focus area state, Cortex health, scheduled task results, user reacts, platform metrics. Zero LLM cost.
- Assess & prioritize — Single LLM call sees ALL signals, produces 3-7 prioritized actions with reasoning. Each action has: priority (critical→low), type (user-task/platform-fix/platform-feature/maintenance), delegation target, effort estimate.
- Execute — Auto-executes low-effort actions (≤5min by default). Proposes high-effort actions for user approval. Delegates to: focus utilities, Cortex enrichment, orchestration sprints.
- Brief the user — One unified daily briefing delivered via email + WeChat + in-app. Replaces 8+ separate notification emails. Every notification includes react action buttons.
- Process reacts — User feedback from previous notifications is incorporated into the assessment.
Configuration (~/.enso/data/team-leader-config.json):
schedule.morningRoutine— cron for full routine (default:"0 9 * * *")schedule.checkIn— cron for urgent scans (default: every 6h)channels— email/wechat/inApp togglesautoExecuteMaxEffort— threshold for autonomous action ("5min"/"30min"/"none")autoEvolve— whether TL can launch evolution sprints without approval
REST API: GET/PATCH /api/team-leader/config, POST /api/team-leader/morning, POST /api/team-leader/checkin, GET /api/team-leader/briefing, GET /api/team-leader/state
Dashboard (/dashboard command): TeamLeaderCard.tsx renders three tabs — Briefing (sections with items), Actions (each with priority/reasoning/delegation + react button), Reacts (history with resolution status).
- Key files:
team-leader.ts(core agent),focus-agent.ts(focus utilities),reacts.ts(feedback loop),TeamLeaderCard.tsx(dashboard)
Every notification Enso sends includes react actions — clickable buttons that let the user respond asynchronously without opening the app. Reacts feed back to the Team Leader (or any expert agent) for processing.
Two modes:
- Reactive — User responds to a TL-sent notification (email button, WeChat reply, web form)
- Proactive — User sends instructions to any agent directly from the UI with auto-attached context. Six context types:
card,focus,entity,sprint,deliverable,direct
Channels:
- Email: Approve / Defer / Reply buttons. Approve/Defer hit
GET /api/reacts/quick?nid=<id>&action=approve. Reply opens/r/<id>web form. - WeChat: User replies to messages → webhook captures with notification context association.
- Web form:
/r/<notificationId>— standalone HTML page with text input, no auth required. - In-app:
POST /api/reactswith optionalcontext(direct) + optionalagentTarget(TL or specific expert).
Agent targeting: Reacts can target any agent via agentTarget:
{ agent: "tl" }— Team Leader (default){ agent: "expert", focusId, expertId }— specific focus area expertGET /api/agentslists all available agents (TL + focus experts) for the frontend dropdown
In-app touchpoints (5 places to send reacts with context):
- Tasks tab — Inline input in TL dashboard (always visible, primary command center)
- Card share menu — "Send to Agent" in every card's ⋯ menu
- Focus detail — "Instruct TL" button in status banner
- Sprint deliverables — "TL" button on each deliverable card
- Orchestration completion — "Send to Agent" in sprint completion header
Shared component: ReactToTL.tsx — reusable popup/inline with agent dropdown, context preview, textarea. Supports mode: "popup" | "inline".
Processing: TL reads pending reacts in gatherSignals(), incorporates into LLM assessment (user reacts appear as signals alongside errors and focus state), marks as processed after the routine. Proactive reacts get a "DIRECT USER INSTRUCTION" flag in the LLM prompt, biasing toward action.
Notification context tracking: registerNotification() stores context for each sent notification. getLastWechatNotification() associates WeChat replies with the most recent notification. Contexts auto-expire after 7 days.
- Key files:
reacts.ts(system),wechat-webhook.ts(WeChat capture),server.ts(API routes +/r/<id>page +/api/agents),ReactToTL.tsx(shared UI component)
Full architecture: See FOCUS.md for the complete Focus Areas system — three-phase lifecycle (Infer → Refine → Execute), decision-mode conversations, 5 focus types, expert team generation and management, sprint deliverable activation, Conversation Context Registry (event-driven proactive messages), sidebar grouping, and full REST API.
Focus Areas bridges Cortex (understanding the user) and Evolve (taking action). The system infers 4-7 outcome-oriented goals from Cortex data, each with a dedicated decision-mode conversation, a 2-4 expert advisor team, and an iterative Evaluate → Discuss → Evolve cycle. The Team Leader drives focuses autonomously; the user acts as CEO.
Focus types (5): project, creative, learning, lifestyle, general. Project-type focuses absorb what was previously a separate Projects tab.
Conversation Context Registry (conversation-context.ts): event-driven framework for context-aware conversations. Three capabilities — context injection into system prompts, proactive messages on state changes (60s loop), event triggers (sprint.completed, cortex.entity.created, research.completed, focus.refined). Current consumer: FocusContextProvider. Sidebar groups conversations by context type (FOCUS AREAS/violet, EXPERTS/amber, PROJECTS/emerald, CHATS/default).
Cortex-native storage: Goals at ~/.enso/wiki/focuses/<goal-slug>.md, experts at ~/.enso/wiki/focuses/<focusId>/expert-<slug>.md.
- Key files:
focus-areas.ts(engine),focus-agent.ts(TL utilities),focus-context-provider.ts(decision-mode + expert personas),team-generator.ts(expert generation),conversation-context.ts(registry),FocusView.tsx,ConversationSidebar.tsx
Standard research uses a two-phase streaming pipeline (Phase A: summary + findings in ~19s, Phase B: full analysis in ~30s) via the Gemini API. Deep research escalates to Claude Code for a fundamentally different output:
- Trigger: "Deep Dive" button on a research card, or task router auto-escalation when
depth === "deep" - Pipeline:
card.action(deep_dive)→setDeepResearchLauncher()in card-actions →handleDeepResearchBuild()in build-via-claude.ts → Claude Code session (visible in terminal card) - Claude Code does two phases: (1) 5-10 web searches + article reading for thorough research, (2) designs and writes a bespoke interactive JSX component tailored to the topic's nature
- Output: Single
.deep-research-ui.jsxfile with all research data embedded asvardeclarations — no app registration, no executors - Delivery: Template is compile-checked with Sucrase (auto-fix via session resume if errors), then delivered as
generatedUIon the original research card via_generatedUIfield in tool result _generatedUIinterception: Bothcard-actions.tsanddelivery.tscheck for_generatedUIin tool result data, extract it, and deliver asgeneratedUIon the card (bypassing template registry)- Topic-adaptive design: Historical topics get timeline explorers, comparison topics get side-by-side panels with radar charts, location topics get area guides with ratings — each UI is custom-designed
- Key files:
build-via-claude.ts(handleDeepResearchBuild,buildDeepResearchUIPrompt),researcher-tools.ts(deep research trigger),card-actions.ts(launcher setup +_generatedUIinterception),delivery.ts(_generatedUIin auto-enhance)
- Locale state: Stored in Zustand (
language: "en" | "zh"), persisted tolocalStorage("enso_language"), synced to backend viasettings.set_languageWS message - Translation files:
src/lib/i18n/en.jsonandzh.json— flat key-value dictionaries (~100 keys each) - Core module:
src/lib/i18n/index.ts—t(key)function,useT()React hook (usesuseSyncExternalStore),_setLocale()for store sync - Settings UI:
SettingsPanel.tsx— consolidated gear icon dropdown with Language toggle (EN | 中文) + Claude Code Model picker (replaces old ModelPicker) - Components translated: WelcomeCard, ChatInput, CardTimeline, BackgroundTaskBar, AppBuilderDialog, DynamicUICard
- Adding a new language: Create
src/lib/i18n/<code>.json, add toSUPPORTED_LOCALESandLOCALE_LABELSin index.ts, add validation inserver.tssettings handler
Fully documented in CORTEX.md — the 13 data sources are the input pipeline into Cortex.
Consent-gated scans of the user's desktop environment. All data stays local. Current sources: Files, Browser History, Bookmarks, Email, System, Kindle, WeRead, YouTube, Steam, Movies/TV, Photos, Twitter/X, QQ Music.
Adding a new source = one new app directory in server/apps/<source>/ + one entry in DATA_SOURCES in data-source-registry.ts.
- Key files:
data-source-registry.ts,data-source-pipeline.ts,user-context-builder.ts,onboarding.ts(backend);SettingsPanel.tsxDataSourcesSection (frontend)
Single entry point for all LLM calls across the platform, replacing scattered direct API calls.
- Module:
server/src/llm.ts— exportsllm(prompt, opts?)function - Tier-based model selection:
fast(Gemini Flash — classification, summaries),utility(default — ingest, synthesis),pro(Opus-class — planning, complex reasoning) - Auto API key resolution: reads from environment, no per-call key management
- Built-in retry: exponential backoff on transient failures, configurable timeout
- Used by: Cortex ingest pipeline, data source profile builder, task router, UI generator, team generator
- Trigger:
/codeopens project picker, then/code <prompt>sends prompts - Backend spawns
claude.exe --output-format stream-json, parses NDJSON, streams via WS - Session resumption via
--resume <sessionId>,AskUserQuestiontool renders as clickable buttons - Model picker: Header dropdown lets user choose model + thinking mode (Opus/Sonnet/Haiku × Thinking/Fast). Persisted to localStorage, synced to server via
settings.set_model. Only affects direct user Claude Code sessions; build/orchestrator sessions default to Opus. - Extended thinking: When thinking mode is "adaptive", Claude's reasoning is streamed as
[think:start]/[think:end]markers and rendered as collapsible purple sections in TerminalCard. Reduces perceived wait time by showing live reasoning.
- Trigger:
/shellor the "Terminal" tile on the WelcomeCard - Backend spawns a real PTY via
node-pty(PowerShell on Windows, bash/zsh on macOS) - Frontend renders with xterm.js (full ANSI color, cursor positioning, alternate screen buffer)
- Character-level I/O: keystrokes forwarded via
shell.input, output streamed asServerMessagedeltas withtoolMeta.toolId === "shell" - Performance: PTY output written directly to xterm.js via
shellWritersmap, bypassing React state - Key files:
shell-pty.ts(backend),ShellCard.tsx(frontend), card type"shell"
Long-running tasks (builds, orchestrations, deep research, Claude Code sessions) use a multi-layer progress and notification system:
- Progress bars with ETA:
CardLoadingOverlayshows elapsed time + determinate progress bar when duration is estimable (research ~35s, build ~2min). Indeterminate sliding bar for unpredictable operations.ActivityIndicatorin terminal cards also shows elapsed time. - Background task bar:
BackgroundTaskBarcomponent sits above ChatInput, showing compact pills for each active background task (terminal, orchestration, deep research, shell) with elapsed time + click-to-scroll. Typing indicator suppressed when only background tasks are running — the chat stays available. - Browser notifications (web): When tab is not focused — Notification API, tab title flash, favicon badge dot, completion chime (Web Audio API two-tone C5→E5).
- Mobile notifications (Capacitor native): Haptic vibration + chime + in-app toast. Handles "return from background" via
wasRecentlyBackgrounded()detection. - In-app toast banners:
ToastContainercomponent shows slide-down toast for all completions on both platforms. Auto-dismiss 5-8s, tap to dismiss. - Results inbox: Slide-up sheet (
ResultsInbox) accessible from header button with unseen badge count. Lists all completed long-running tasks with seen/unseen tracking (persisted to localStorage). One-tap scroll-to-card navigation. - Card context recovery: After server restart,
tryReconstructContext()in card-actions.ts recovers card contexts from the JSONL journal (loadCardHistory) — historical cards become interactive again without re-running the app. - Key files:
src/lib/notifications.ts,src/lib/useElapsedTime.ts,src/components/ToastContainer.tsx,src/components/BackgroundTaskBar.tsx,src/components/ResultsInbox.tsx,server/src/outbound/card-actions.ts
Four-path dispatch (first match wins):
- Refine —
action === "refine"→ regenerate template only (1 LLM call) - Mechanical — built-in data mutations (sorting, task boards)
- App tool — resolve
prefix + actionto registered tool → execute directly - Agent fallback — unmatched actions go through the standalone agent pipeline
Ecosystem Bridge: registerAppTool() in registry.ts dual-registers each dynamic app tool with both the internal generatedToolExecutors map AND the agent's tool registry via registerLocalTool() in server/standalone.ts. Every user-built app is immediately discoverable by the agent for future requests — closing the loop where apps become reusable ecosystem tools.
Dynamic apps are the primary workflow. They live as portable directories (app.json + template.jsx + executors/*.js) in two locations:
| Location | Path | Purpose |
|---|---|---|
| User apps | ~/.enso/apps/<family>/ |
Created by Build App pipeline |
| Shipped apps | server/apps/<family>/ |
Promoted via Apps menu |
Three creation methods: (1) Build from Enso UI (recommended), (2) Via Code button (Claude Code), (3) Manual file creation.
System apps (advanced) use a 5-file TypeScript pattern for deeply integrated platform capabilities. See CLAUDE-REFERENCE.md for complete guides on both approaches.
| Tier | What | Can Delete? | Examples |
|---|---|---|---|
| System | Core platform capabilities. Deeply integrated (Node.js APIs, native binaries, SDK sessions). Always available. | No | filesystem, media, screen, browser, claude_code, shell |
| Apps | Everything else. Built on top of system capabilities. Can be pre-installed (shipped) or user-created. |
Yes | researcher, clawhub, alpharank, photo_studio |
Apps render in two styles:
| Experience | Card Type | Rendering | Apps |
|---|---|---|---|
| card | dynamic-ui |
React JSX template in sandbox | filesystem, media, screen, browser, researcher, all user apps |
| terminal | terminal / shell |
Streaming text terminal (xterm.js) | claude_code, shell |
Every non-terminal entry in APP_CATALOG (server/src/app-catalog.ts) must have a UI template or it will appear callable in the client but render raw JSON. There are exactly two valid ways to provide a template:
- Shipped app —
server/apps/<appId>/app.json+template.jsxexists (preferred for anything with a rich UI) - Native template — a
ToolTemplateregistered viaregisterToolTemplate()innative-tools/templates/*.ts(for deeply integrated system tools like filesystem, researcher)
Never add an APP_CATALOG entry without immediately providing one of these. The server logs a startup warning for any orphan entries — check [enso] ⚠️ APP_CATALOG integrity in the console if something looks broken.
Also: server/apps/ is for shipped/promoted apps only (git-tracked). User-built apps go to ~/.enso/apps/ automatically. The build pipeline (build-via-claude.ts) writes there by default — do not change it to write to server/apps/.
- Every tool's result data MUST include
"tool": "enso_<family>_<suffix>"field - All parameter schemas MUST have
additionalProperties: false - Exactly one tool per family must have
isPrimary: true - Executors are function bodies (no imports/exports), use
varnotconst/let - Templates are JSX strings (no imports), all hooks at top level (never in conditionals)
- Template sandbox has: React hooks, Recharts, Lucide icons, EnsoUI — no DOM/fetch/globals
- Use
EnsoUI.Tooltip(notTooltipwhich is Recharts)
Frontend: React 19 + Zustand 5 + Tailwind CSS 4 + Recharts + Lucide + Sucrase + xterm.js + Vite 6. Backend: Standalone Express 4 + ws 8 + node-pty. Language: TypeScript 5.7 strict, ESM. LLM: Gemini (via API key). Unified LLM: llm() in server/src/llm.ts — auto-resolves API keys, tier-based model selection (fast/utility/pro), retry with backoff.
New users get a complete environment with a single command. See SETUP.md for full details.
./setup # macOS/Linux
.\setup.ps1 # WindowsThe setup script handles everything interactively:
- Install location — user chooses where the source lives (default
~/Enso) - Dependencies — Node.js check,
npm install - Chat AI model — choose from 6 LLM providers (Gemini, OpenAI, Anthropic, DeepSeek, Ollama, OpenRouter)
- Service API keys — Brave Search for web research
- Claude Code — install CLI + authenticate (API key, OAuth/subscription, or skip)
- Remote access — automatic
<name>.enso.nettunnel via Cloudflare (calls tunnel registry API on master instance) - App personalization — user answers 3 questions (name, role, app name), Claude Code redesigns the UI
- Build — frontend + APK (installs JDK 21 + Android SDK if needed)
- Server start — guardian-supervised with watchdog
Non-interactive mode via environment variables: ENSO_LLM_CHOICE=1 ENSO_USER_ROLE="developer" ./setup
During setup, the user's role drives deep source code customization via Claude Code:
- Claude Code reads the user's profile and directly modifies
App.tsx,WelcomeCard.tsx,en.json,manifest.json,capacitor.config.ts - Not theming or config — actual source code changes committed to the user's repo
- Each persona gets a fundamentally different welcome screen layout, domain-specific prompts, reordered tools
- Examples: "Atlas" (founder) gets a command center with tabbed deal flow panels; "Signal" (investor) gets a Bloomberg-terminal aesthetic with monospace headers; "Nexus" (researcher) gets a literature-focused deep dive layout
The deterministic fallback (scripts/personalize.cjs) runs if Claude Code isn't available, matching against 6 persona templates: tech-founder, developer, researcher, investor, creative, product-manager.
See PERSONALIZATION-SHOWCASE.md for examples of all 6 persona apps.
Key files: setup (bash entry point), scripts/personalize-prompt.md (Claude Code prompt), scripts/personalize.cjs (fallback)
During setup, the server's URL and access token are baked into the frontend build via Vite define:
__ENSO_DEFAULT_BACKEND__,__ENSO_DEFAULT_TOKEN__,__ENSO_DEFAULT_NAME__invite.config.tsApp.tsxchecks these on first native launch — if present, auto-creates a backend entry and connects immediately, bypassing the SetupWizard- The resulting APK connects to the server that built it with zero user configuration
A master Enso instance can provision Cloudflare tunnels for other installations, giving each a <name>.enso.net subdomain.
- File:
server/src/tunnel-registry.ts - Activation: Only mounts when
CLOUDFLARE_API_TOKENenv var is set - Endpoints:
GET /api/tunnel/check,POST /api/tunnel/register,DELETE /api/tunnel/:specifier,GET /api/tunnel/list - Required env vars (master only):
CLOUDFLARE_API_TOKEN,CLOUDFLARE_ACCOUNT_ID,CLOUDFLARE_ZONE_ID - Registry file:
~/.enso/tunnel-registry.json
All development on main branch directly — no worktrees or feature branches.
npm run dev # Frontend dev server (Vite :5173)
npm run dev:server # Standalone backend server (Express + WS :3001)
npm run build # Production buildThe backend server runs on port 3001. Vite proxies /ws, /media, /upload to localhost:3001.
Dev commands: /delete-apps — clear all dynamically created apps.
Enso supports connecting to remote backends over the internet. The frontend includes a Connection Picker for managing multiple servers.
src/lib/connection.ts— Backend config CRUD (localStorage), URL resolution with token auth, deep-link supportsrc/components/ConnectionPicker.tsx— Modal UI for adding/testing/switching backends- Server auth (
server.ts) — CORS middleware, token auth (Bearer header or?token=query param), WS token validation
| Config Key | Env Var | Purpose |
|---|---|---|
accessToken |
ENSO_ACCESS_TOKEN |
Shared secret for auth (auto-generated if unset) |
machineName |
ENSO_MACHINE_NAME |
Friendly name shown in Connection Picker |
- Same-origin (default): No active backend config → relative URLs via Vite proxy
- Remote: Active backend set → absolute URLs with token auth appended
- Deep-link:
?backend=https://...&token=xxxin URL auto-creates + connects
Backend returns relative /media/... URLs. DynamicUICard recursively resolves these to absolute URLs with tokens for remote backends via resolveMediaUrlsInData().
Recommended: Cloudflare Tunnel — each machine gets a fixed subdomain (e.g., app.yourdomain.com). See server/SETUP.md for full setup instructions.
Enso is installable as a Progressive Web App — public/manifest.json, public/sw.js (app shell caching), and PWA meta tags in index.html.
- Every new feature must be validated with a full end-to-end live test before considering it complete. Build the code, deploy it (or run dev server), then exercise the feature through the actual UI to confirm it works with full functionality verified. Do not rely solely on successful compilation — always test the real user flow.
- All source is TypeScript with strict mode, ESM imports throughout
- Path alias:
@shared→./shared - Frontend uses functional React components with hooks
- State flows: WebSocket → Zustand store → React components
- Generated components are self-contained (no imports, deps injected via scope)
- Dark theme UI (Tailwind classes)
- Server and client share types via
shared/types.ts - Server logs use
[enso:inbound/outbound/enhance/action/build]prefixes
Centralized NDJSON action log captures all backend operations, errors, fixes, and Claude Code session lifecycle.
- Files:
~/.enso/action.log(rotates at 1000 lines),~/.enso/fixes.json(bug fix records) - Module:
server/src/action-log.ts—logAction(),logError(category, message, error, extra?),logFix() - HTTP API:
GET /api/action-log?count=100&type=error(types:action,error,fix,build,system,claude-code) - Client errors: Frontend reports via WebSocket
client.error; utility atsrc/lib/error-reporter.ts(5s dedup) - Category convention:
module:subpath(e.g.,action:refine,build-via-claude,ui-gen)
Full entry-type table, frontend error sources, and usage examples in CLAUDE-REFERENCE.md.