θ±θ
β Self-Hosted AI Assistant
Tofu is a fully self-hosted AI assistant you run with a single command. It connects to any OpenAI-compatible LLM and gives you a complete AI workspace β from simple Q&A to autonomous multi-step agents that can search the web, edit your codebase, read papers, control your browser, and collaborate as a team of specialist agents.
Everything runs on your machine. Your data never leaves your infrastructure. One command and you're live.
What makes Tofu different:
- One command, everything included β the installer sets up the runtime, dependencies, database, and browser engine for you. No Docker required (though it's supported), no manual database setup, no config files to hand-edit.
- Bring any model β OpenAI, Anthropic, Gemini, DeepSeek, Qwen, GLM, local models via Ollama/vLLM, or even your existing Claude Pro/Max / ChatGPT subscription logged in directly. Add several keys and Tofu rotates and load-balances across them automatically.
- A real agent, not just a chat box β it can run multi-step tasks on its own: search, read, write code, run commands, generate images, and check its own work with a Planner β Worker β Critic loop.
- Truly yours β self-hosted, MIT-licensed, no telemetry. Your conversations, keys, and files stay on your infrastructure.
- Everything is also an API β every feature in the UI is a documented HTTP endpoint, so you can script Tofu or plug it into other tools (see Headless API).
Looking to drive Tofu from an AI agent or coding assistant? This README is written for people. There's a separate set of machine-facing materials β see For AI Agents & Developers at the bottom.
Pick the row that matches your OS. Each one ends with a running server on http://localhost:15000.
| OS | What to do |
|---|---|
| Windows | Download Tofu-Setup-x.y.z-win64.exe from the latest release and double-click. |
| Linux / macOS | curl -fsSL https://raw.githubusercontent.com/rangehow/ToFu/main/install.sh | bash |
| Docker | git clone https://github.com/rangehow/ToFu.git && cd ToFu && docker compose up -d |
That's it. Each path handles conda/runtime, dependencies, the database, the browser engine, and starts the server β no flags, no follow-up steps.
Need to pre-set an API key, change the port, or recover from a failed install? See docs/INSTALL.md for all flags and troubleshooting recipes.
Click βοΈ Settings β π Providers and add your API keys. Tofu works with any OpenAI-compatible API:
| Provider | Setup |
|---|---|
| OpenAI, Anthropic, Amazon Bedrock, Google Gemini, DeepSeek, Qwen, MiniMax, GLM, Doubao, Mistral, Grok, Baidu Qianfan, OpenRouter | Click β‘ Add from template β one click |
| Ollama, vLLM, or any local model server | Add as custom provider with your local endpoint |
| Azure OpenAI | Template available with deployment-specific base URL |
Multiple keys per provider β add several API keys and Tofu automatically rotates between them when one hits rate limits. Across providers, the smart dispatcher routes requests based on real-time latency scoring and error-rate tracking.
Or set environment variables for headless/Docker setups:
export LLM_API_KEY=sk-xxx
export LLM_BASE_URL=https://api.openai.com/v1
export LLM_MODEL=gpt-4oEverything you can do in the UI is also exposed as a documented HTTP API, so you can drive Tofu from scripts, agents, or your own apps without rendering the web UI.
Mounts:
| Prefix | Surface |
|---|---|
/api/v1/* |
Tofu native β full feature parity with the UI (chat, conversations, tasks, agents, capabilities, keys, usage, billing, β¦) |
/v1/... |
OpenAI compat β chat/completions, models, embeddings (drop-in for the OpenAI SDK) |
/v1/messages |
Anthropic compat β Messages API (drop-in for the Anthropic SDK) |
/metrics |
Prometheus exposition (admin-scoped) |
Self-description: /api/openapi.json and /api/openapi.yaml (OpenAPI 3.1), Swagger UI at /api/docs, ReDoc at /api/redoc.
Manage keys in Settings β π API Keys: mint, scope (chat/admin/etc.), set per-key RPM and TPD limits, revoke, view a 30-day usage chart per key. Idempotency-Key is supported on POSTs (24-hour cache, salted by principal). Standard rate-limit headers (X-RateLimit-*, Retry-After) are returned on every response.
Client SDKs ship in clients/:
# Python β sync `Tofu` class + `tofu` CLI
cd clients/python && pip install -e ".[cli]"
export TOFU_API_KEY=tofu_admin_xxx TOFU_BASE_URL=http://localhost:15000
tofu chat "hello"
# TypeScript β Node 18+, browsers, Cloudflare Workers, Vercel Edge, Deno, Bun
cd clients/typescript && npm installOr use any OpenAI / Anthropic SDK directly by pointing it at your Tofu base URL with your tofu_admin_* key as the API key.
When auth_mode=multi-user, Tofu turns into a paid AI relay station β one self-hosted instance, many users, each with their own wallet, billed against your upstream LLM costs.
What lights up automatically when you flip the mode (no-op in open/private):
- Per-user wallets in micro-credits (1 credit = 1,000,000 Β΅ β US $0.001), backed by an append-only ledger as the source of truth β no floats, no rounding bugs.
- Atomic reserve / settle on every chat request β pre-flight 402 on insufficient funds, post-flight settlement of actual token usage; a background janitor sweeps stale reservations every 30 minutes.
- Customer pages β
/login,/signup, and/dashboard(Wallet, Keys, Usage, Docs, Account). Signup gating + welcome credit indata/config/relay.json. - Payments β Stripe webhooks and Alipay async-notify, idempotent on
(provider, provider_id). Configure credentials indata/config/payments.json. - Redeem codes β generate batches, hand them to users, redeem to wallet.
- Pricing table β per-model unit prices (input/output/cache) hot-reloaded from
data/config/pricing.json, with family-prefix fallback and an admin-tunable margin. - Admin console β a standalone
/admindashboard (Users, Pricing, Redeem Codes, Payments) reachable only with anadmin-scoped key under multi-user mode.
Everything is implemented in lib/billing/ and routes/api_v1/billing.py; switch back to open or private and the tables stay empty, the customer pages stop being served, and the gate behaves as in the previous section.
The core experience: pick a model from the dropdown, type a message, get a streaming response. But Tofu goes much further than a basic chat UI.
When you want to try different models on the same question β switch models mid-conversation. Each message remembers which model generated it, so you can compare outputs naturally. Branch any assistant message to explore alternative responses from different models or with different parameters, all in the same thread.
When you're working in Chinese but need English sources β enable auto-translation per conversation. Your Chinese questions are translated to English for the model, and the English response is translated back. The original is always preserved β click to toggle. For faster, cheaper translation, connect a dedicated machine translation provider instead of using the LLM.
When conversations get long and you lose context β Tofu's 3-layer compaction pipeline handles this automatically:
- Micro-compaction (zero cost): old tool results are replaced with summaries, keeping only the recent "hot tail"
- Structural truncation: thinking blocks, oversized arguments, and redundant screenshots are trimmed
- LLM summary (force-triggered): when context pressure is high, a cheap model evaluates each turn for relevance and compresses accordingly
When you want to organize your conversations β create folders in the sidebar to group related threads. Drag conversations between folders, or leave them unfiled.
When you'd rather read the reasoning in order β finished multi-tool replies render as an interleaved timeline: each tool call appears inline right next to the thinking and narration that led to it, so you follow the assistant's actions in the order they actually happened instead of three separate "all thinking / all tools / all answer" blocks. On by default; toggle it in Settings β General β "Per-tool inline timeline."
When a conversation runs long β a context health bar shows how much of the model's window you're using, and Tofu automatically compacts older turns so the thread keeps going without hitting the limit. You can open the compaction viewer to inspect exactly what was summarized, so nothing feels lost.
When typing is slower than talking β dictate straight into the message box.
How to use: Click the mic button next to the composer, allow microphone access, speak, then click again to stop. Your speech is transcribed and inserted at the cursor β it's never auto-sent, so you review and edit before sending. It's dictation, not a spoken conversation.
The mic only appears when your browser supports recording and a speech-to-text model is configured β otherwise it stays hidden. To enable it, add a provider whose model has the transcription (or audio_chat) capability in Settings β Providers:
| Provider | Models |
|---|---|
| OpenAI | gpt-4o-transcribe, gpt-4o-mini-transcribe, whisper-1 |
| Groq | whisper-large-v3-turbo, whisper-large-v3 (fast, low cost) |
| Omni chat models | Gemini / LongCat and similar, via audio_chat |
Optional env tuning: TOFU_AUDIO_MAX_BYTES (default 25 MB), TOFU_AUDIO_MAX_DURATION_S (default 600 s). There's no separate voice tab β availability is driven entirely by the configured model.
When the assistant needs current information β today's news, documentation updates, API references β it can search the web and read pages.
How it works: Enable the π toggle in the tool bar. The assistant searches across multiple engines in parallel (DuckDuckGo, Brave, Bing, SearXNG), deduplicates results, then fetches and extracts the most relevant pages. A content filter (LLM-powered, optional) strips navigation, ads, and boilerplate.
When you paste a URL β the assistant fetches it directly, handling HTML, PDFs, and plain text. For pages behind authentication, use the browser extension instead (see below).
Configuration β in Settings β π Search & Fetch:
- How many results to auto-fetch (default: 6)
- Per-page timeout and max characters
- Blocked domains the fetcher should never visit
- Whether to use the LLM content filter (disable for speed)
This is where Tofu becomes more than a chatbot. When you enable tools, the assistant can take multi-step actions autonomously β searching the web, running code, editing files, generating images β chaining these together to solve complex tasks.
Built-in tools:
| Tool | What it does |
|---|---|
web_search |
Search the web (multi-engine parallel) |
fetch_url |
Read any URL (HTML, PDF, plain text) |
run_command |
Execute shell commands |
generate_image |
Create or edit images (Gemini, GPT-image) |
ask_human |
Pause and ask you a question mid-task |
list_conversations / get_conversation |
Reference past conversations |
create_memory / update_memory / delete_memory |
Save knowledge for future sessions |
check_error_logs / resolve_error |
Inspect and resolve errors in project logs |
| Browser tools | Control your browser (via extension) |
| Desktop tools | Control your local machine (via agent) |
| Project tools | Browse, search, edit any codebase |
| Scheduler tools | Create recurring automated tasks |
| Swarm tools | Spawn parallel sub-agents |
When you need a quick answer with live data β "What's the current price of NVDA?" The assistant searches, fetches the relevant page, and answers.
When you need a multi-step workflow β "Research the top 5 React state management libraries, compare them, and write a recommendation document." The assistant plans the steps, executes searches, reads documentation, and synthesizes the result β all autonomously.
When the task is too complex for one pass β enable Endpoint mode (Planner β Worker β Critic). A planner rewrites your request into a structured brief with acceptance criteria, a worker executes it, and a critic reviews against the checklist. If the result doesn't pass, the critic sends feedback and the worker iterates β up to 10 rounds.
When something fails β the assistant retries with exponential backoff. If the primary model fails entirely, it automatically falls back to a configured backup model and retries.
Point Tofu at any codebase and it becomes a coding assistant that can read, search, edit, and run commands in your project.
Getting started: Click Project in the sidebar, enter the path to your codebase (e.g. /home/you/myproject). The assistant gains these tools:
| Tool | What it does |
|---|---|
list_dir |
Browse directory structure with file sizes and line counts |
read_files |
Read files (supports images, PDFs, Office docs, code β with line numbers) |
grep_search |
Search across files with ripgrep (regex, context lines, count mode) |
find_files |
Find files by glob pattern |
write_file |
Create or overwrite files |
apply_diff |
Surgical search-and-replace edits (batch mode for multiple edits) |
insert_content |
Add code before/after an anchor without replacing it |
run_command |
Execute shell commands in the project directory |
When you need to understand a new codebase β "Give me an overview of this project's architecture." The assistant explores the directory tree, reads key files, and maps out the structure.
When you need to fix a bug β "The login page shows a blank screen after submitting." The assistant greps for relevant code, reads the components, identifies the issue, and applies a fix with apply_diff.
When you want safe experimentation β every file modification is tracked per-conversation with full undo support. Click the undo button to roll back any changes the assistant made.
Multi-root projects β add multiple directories as roots (e.g. frontend + backend repos). The assistant resolves namespaced paths across all roots.
Smart token management β the content_ref mechanism lets the assistant write a previous tool result to a file without re-generating it. This saves significant tokens on large files.
When you have several conversations open on the same project, the Project Brain makes them act like one coordinated team instead of separate, forgetful chats. Each conversation can see what the others are doing, share the same goals and decisions, and avoid stepping on each other's work β and the project can even pick up pending work on its own, all while staying fully visible and controllable by you.
How you use it: it's automatic whenever a conversation is in project mode (attached to a project folder) β no toggle to flip. You watch and steer it through the slide-in Project Brain panel, opened from the project bar (live activity, charter, board, and status tabs), plus a one-line status headline in the collab-bar. The one thing that needs you: agents can only propose changes to the shared charter β you click Commit or Reject.
| Capability | What it gives you |
|---|---|
| Charter | A shared north-star doc + committed decisions every conversation follows. Changes are human-approved. |
| Board & epics | A kanban of claimable workstreams so conversations divide work and don't duplicate it. |
| Activity feed | A live pulse of what every conversation is doing right now. |
| Peer messaging | One conversation can send another an advisory nudge β rate-limited, never interrupts mid-work. |
| Path leases | A conversation reserves the files it's editing so siblings hold off, preventing edit collisions. |
| Status lane | Ask the project "where are we? are we drifting?" and get a synthesized answer, plus a watch-list of concerns the brain revisits over time. |
| Autonomous dispatch | Idle projects self-start ready, unblocked work with no hand-off. |
Some tasks are too big for a single agent. The swarm system lets a master orchestrator plan sub-tasks and delegate them to specialist agents running in parallel.
When to use it: "Refactor this microservice into 3 separate services, update the API docs, and write migration scripts." Instead of one agent doing everything sequentially, the master spawns parallel agents for each sub-task.
How it works:
- The master LLM plans sub-tasks and assigns roles (coder, researcher, writer, reviewerβ¦)
- A streaming DAG scheduler launches agents as soon as their dependencies complete β no waiting for entire waves
- Agents share data through an artifact store (key-value pairs visible to all agents)
- As agents complete, the master reviews results and can spawn follow-up agents
- Final results are synthesized into a coherent output
Agent roles β each agent gets role-specific system prompts, model tiers, and scoped tool access. A "researcher" agent gets search tools; a "coder" agent gets project tools; a "reviewer" gets read-only access.
Rate limiting β a shared semaphore prevents agents from overwhelming the LLM API with concurrent requests. Automatic exponential backoff on 429s.
When you translate frequently and want faster, cheaper results β connect a dedicated machine translation provider instead of using the LLM for translation.
How it works: By default, Tofu uses a cheap LLM model for auto-translation (which understands context but is slower). When you configure a machine translation provider, all translation requests are routed directly to the MT API β typically 3β5Γ faster and 10β100Γ cheaper than LLM-based translation, with no prompt overhead.
Setup: Go to Settings β π ηΏ»θ― (Translation), enable machine translation, and choose a provider:
| Provider | Description | How to get API Key |
|---|---|---|
| NiuTrans (ε°ηηΏ»θ―) | Chinese MT specialist, supports 300+ language pairs | niutrans.com/cloud/overview |
| Custom | Any compatible REST API | Enter your endpoint and credentials |
NiuTrans is the default provider with excellent ChineseβEnglish quality. Click "η³θ―· API Key" in the settings card to register.
Fallback behavior:
- No MT configured β uses the cheap LLM model (default, works out of the box)
- MT configured β uses the MT API; if it fails, automatically falls back to LLM translation
- Code block protection β fenced (
```...```) and inline (`...`) code blocks are extracted before translation and restored after, preventing MT from corrupting code
Already paying for Claude Pro/Max or a ChatGPT subscription? Log in with it and Tofu uses that subscription as a model provider β no separate API key, billed under your existing plan.
How it works: Go to Settings β Providers and click η»ε½ Claude / η»ε½ ChatGPT. Tofu runs a PKCE OAuth flow (lib/oauth/), stores the token, and lib/oauth/outbound.py bridges the logged-in subscription into a managed provider slot β resolved per-request into a live token plus the required client-identity headers. From then on the subscription behaves like any other provider in the dispatcher (slot rotation, fallback, latency scoring all apply).
- Claude requests go to the Anthropic Messages API with the Claude-Code identity headers.
- ChatGPT (Codex) requests are auto-converted to the Responses API format.
This is a normal in-dispatch provider, not a CLI subprocess. (An earlier CLI-subprocess "backend switching" mechanism β
lib/agent_backends/β was removed in 2026-06 in favour of this simpler subscription-as-provider path.)
When you need the assistant to read pages that require login β internal dashboards, JIRA tickets, authenticated admin panels β the browser extension bridges your real browser session to Tofu.
Setup:
- Go to
chrome://extensionsβ Enable Developer Mode - Load unpacked β select the
browser_extension/folder - Click the extension icon β enter your Tofu server URL
What it can do:
| Tool | Use case |
|---|---|
browser_list_tabs |
See all your open tabs |
browser_read_tab |
Extract text content (with optional CSS selector) |
browser_screenshot |
Capture a visual screenshot |
browser_navigate |
Open a URL |
browser_click |
Click elements by selector or text |
browser_type |
Type into input fields |
browser_execute_js |
Run custom JavaScript for data extraction |
browser_get_interactive_elements |
Discover clickable/typeable elements |
browser_get_app_state |
Access Vue/React internal state |
When the page uses Canvas/SVG rendering (charts, DAG diagrams) β DOM text extraction returns nothing. Use browser_screenshot for visual analysis, browser_get_app_state for data, or browser_execute_js for custom extraction.
Multiple browsers can connect simultaneously with independent command queues β useful if you have work and personal browser profiles.
When you need the assistant to interact with your local machine beyond the browser β take full-screen screenshots, read/write local files, automate GUI clicks, manage clipboard.
Setup:
pip install pyautogui pillow psutil
python lib/desktop_agent.py --server http://your-server:15000 --allow-write --allow-execThe agent connects to your Tofu server and exposes tools for file operations, clipboard, screenshots, GUI automation (pyautogui), and system info. All dangerous operations require explicit --allow-write / --allow-exec flags.
When you're reading research papers β arXiv PDFs, conference proceedings, internal whitepapers β Paper Reader turns Tofu into a dedicated research companion.
How to use: Click the π Paper button in the sidebar. The screen splits: PDF on the left, chat + notes on the right. Upload a PDF or paste an arXiv URL (arxiv.org/abs/XXXX.XXXXX) β Tofu fetches, parses, and indexes the full text so the assistant can answer questions grounded in the paper.
What it does:
- Grounded Q&A β ask "what's the ablation result in Table 3?" or "explain Section 4.2" β the assistant cites the specific passage it's drawing from
- Paper library β the left sidebar shows all papers you've read, grouped by date; switch between them without losing conversation context
- Side-by-side reading β scroll the PDF while chatting; the assistant sees the page you're on
- Notes tab β drop your own notes alongside the paper; they persist across sessions
β οΈ Beta: Paper Reader is actively being iterated on. Feedback welcome on GitHub Issues.
The default PDF pipeline (pymupdf4llm) does a good job on most papers, but
struggles with borderless tables and complex math formulas that are
common in ML / theoretical CS papers. For those, Tofu can route through
Docling (IBM) β a layout-aware
model that uses TableFormer for tables and an internal equation model for math,
producing much cleaner Markdown.
Trade-off: Docling pulls in PyTorch + ~2 GB of model weights, so it's opt-in:
pip install docling --extra-index-url https://download.pytorch.org/whl/cpuThen enable it by setting PDF_TEXT_MODE=structured in your .env, or
per-request via the form field textMode=structured on /api/pdf/parse.
If Docling isn't installed when structured is requested, the server falls
back to pymupdf4llm automatically β your uploads never break.
When you need visual content β illustrations, diagrams, logos, edited photos β the assistant can generate images mid-conversation.
How to use: Enable the πΌοΈ toggle in the tool bar and describe what you want. The assistant calls generate_image with a detailed prompt.
- Create from scratch β "Draw a minimalist logo of a mountain with a sunrise"
- Edit existing images β upload an image and say "change the background to a beach sunset"
- Save to project β specify
output_pathto save directly into your codebase - SVG conversion β add
svg: trueto auto-trace the generated PNG into a scalable vector
Multi-model dispatch cycles across Gemini and GPT image models, automatically retrying on rate limits.
When the assistant produces something you'd rather see than scroll past β a full HTML page, an SVG diagram, a React-style snippet, or a long document β it becomes an Artifact.
How it works: A clickable chip appears next to the message; open it and Tofu renders the content live in a side panel β HTML/SVG in a sandboxed iframe, Markdown safely sanitized. Every artifact is versioned, so you can flip between revisions, pin favorites, browse them all in the per-conversation library, and export to PDF. Great for building a small web page, a chart, or a formatted report and iterating on it in place.
When you want to connect external tool servers β GitHub, databases, custom APIs β MCP bridges them into Tofu's tool system.
How it works: MCP servers run as subprocesses and communicate via stdio/SSE (JSON-RPC 2.0). Tofu translates their tools into OpenAI function-calling format, so the LLM can discover and invoke them alongside native tools.
Setup: Go to Settings or configure in data/config/mcp_servers.json:
{
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "ghp_xxx" }
}
}The assistant can then call tools like mcp__github__create_issue, mcp__github__search_code, etc. β any MCP-compatible server works.
Click the βοΈ My Day button in the sidebar to open your personal work journal β an LLM-powered daily dashboard.
When you want to see what you accomplished today β the LLM reads all your conversations for the day and clusters them into 5β15 coherent work streams (e.g. "Fix image rendering bug", "Deploy staging environment"), marking each as done, in progress, or blocked.
When you need tomorrow's plan β the LLM synthesizes 3β8 actionable TODO items from unfinished work. Each comes with a detailed prompt and recommended tool configuration. Click βΆ to launch any TODO as a new conversation, pre-filled and ready to go.
Calendar view β month-at-a-glance with per-day conversation counts and cost heatmap. Click any date to view or generate its report.
To-do management β uncompleted TODOs carry forward to the next day. Add manual TODOs, toggle done/undone, or launch them as conversations. Cost tracking shows per-day and per-conversation spend in CNY.
Auto-backfill β a background scheduler generates yesterday's report on server boot if it's missing, and again daily at midnight.
When you need something to run automatically β daily data pulls, periodic health checks, recurring reports β create a proactive agent that runs on a schedule.
How to use: Enable the π Scheduler toggle and ask: "Run a health check on my API every 6 hours" or "Every morning at 9am, summarize overnight GitHub issues." The assistant creates a cron-like task.
Task types: Shell commands, Python scripts, or LLM prompts β all with full tool access.
Manage tasks: Click the SCHEDULER badge in the top status bar to see all active proactive agents and their recent run logs.
Tofu quietly watches how it's performing and proposes small improvements to itself β you stay in control of every change.
How it works: A nightly loop analyzes recent runs and drafts proposals (e.g. "block a spammy search domain," "adjust a default"). Click the OPTIMIZER badge in the top bar to review each one with its rationale, severity, and confidence β then approve, reject, revert, or hit Run now. Nothing is applied without your say-so (a small whitelist of safe tweaks can auto-apply, and everything is reversible). Turn it off entirely in Settings.
When your team communicates in Feishu and you want AI assistance directly in group chats β Tofu connects as a Feishu bot via WebSocket.
Setup:
- Create an app at open.feishu.cn, enable Bot capability
- Go to Settings β π¦ Feishu β enter App ID and App Secret
- The bot auto-connects on server restart
Features: Multi-turn conversations with full tool support (search, code, project), slash commands for model/mode switching, and conversation management β all within Feishu's native chat interface.
When the assistant discovers something useful β a bug pattern, a project convention, your preferred coding style β it can save that knowledge as a memory for future sessions.
How it works: Project-scoped memories are Markdown files stored in .tofu/skills/ inside your project; global memories (shared across all projects) live in the server-side store data/memories/global/. The assistant creates them proactively or when you ask. In future conversations, relevant memories are automatically loaded into context.
Tools: create_memory, update_memory, delete_memory, merge_memories β the assistant manages its own knowledge base across sessions.
When to use: "Remember that our API always returns snake_case" β the assistant saves this convention and applies it in all future code generation for this project.
When you want to give the assistant reusable, packaged know-how β a set of instructions and helper scripts for a specific task β install a Skill.
How it works: Skills follow the open Claude / OpenClaw / AgentSkills format (a SKILL.md plus optional reference files and scripts). Go to Settings β Skills to browse a Catalog of recommended packs (e.g. Anthropic's docx / xlsx / pdf / skill-creator skills) and install with one click, or drag-and-drop a local .zip. Installed skills appear under the Installed tab, where you can view or uninstall them. Bundled install.sh scripts are surfaced as hints β never auto-executed.
When you want to explore a different direction without losing the current thread β branch any assistant message.
How it works: Click the branch icon on any assistant message. A new branch opens inline, continuing from that point with its own independent history. Multiple branches can stream in parallel. Each branch can use a different model or parameters.
Use cases:
- Compare how different models answer the same question
- Try an alternative approach without losing the current one
- Let one branch research while another branch implements
Switch to the Tofu theme and a little animated chibi-tofu mascot moves into the project bar. It wanders through a decorative scene with a real walk cycle and moods β thinking while a task loads, celebrating on success β and leaves interactive footstep effects (grass tufts, pool ripples, sky wisps). Use the Scene button (Meadow / Pool / Sky / Off) and Pet button (Tofu / Oneko) in the bar to customize it. It respects your OS "reduce motion" setting. Purely decorative β turn it off any time.
All configuration is done through the βοΈ Settings panel (top-right gear icon). Changes save instantly β no restart needed.
| Tab | What you configure |
|---|---|
| βοΈ General | Theme (Dark/Light/Tofu), temperature, max tokens, thinking depth, system prompt, per-tool inline timeline |
| π Providers | API keys, endpoints, model lists (incl. transcription/audio models), multi-key rotation, auto-discovery |
| π¦ Display | Which models appear in dropdowns, default model, fallback model |
| π Search & Fetch | Result count, timeouts, character limits, blocked domains, content filter |
| π Translation | Machine translation provider (NiuTrans / Custom), API key, endpoint |
| π Network | HTTP/HTTPS proxy, bypass domains |
| π Subscription Login | Log in to Claude Pro/Max or ChatGPT and use it as a provider |
| π¦ Feishu | App credentials, default project, allowed users |
| π MCP | Model Context Protocol servers (App-Store catalog + custom) |
| π Skills | Browse, install, and manage reusable Skill packs |
| π§ Memory & Preferences | Stored memories and your durable preference profile |
| π API Keys | Mint/scope/revoke headless API keys, per-key limits, auth mode |
</> Advanced |
Price overrides, cache management, server info |
Multi-tenant relay admin (Users, Pricing, Redeem Codes, Payments) now lives in a standalone
/adminconsole rather than a Settings tab.
For headless/Docker setups, you can configure via environment variables instead of the Settings UI. Copy the template and edit:
cp .env.example .env
vim .env # fill in your valuesThe .env.example file documents all supported variables. Key ones:
| Variable | Description | Default |
|---|---|---|
LLM_API_KEYS |
Comma-separated API keys | (none) |
LLM_BASE_URL |
API endpoint | https://api.openai.com/v1 |
LLM_MODEL |
Default model | gpt-4o |
PORT |
Server port | 15000 |
BIND_HOST |
Bind address | 127.0.0.1 (loopback) |
TOFU_AUTH_MODE |
Force auth mode and lock the UI: open / private / multi-user |
(file-driven) |
TOFU_AUTO_KEY |
Set to 0 to skip first-boot admin-key bootstrap |
1 |
TUNNEL_TOKEN |
DEPRECATED back-compat shim β use the API-keys system instead | (disabled) |
TRADING_ENABLED |
Enable trading module (1/0) |
0 |
PDF_TEXT_MODE |
Default PDF text-extract strategy: rich (pymupdf4llm, default), structured (Docling; requires pip install docling), fast |
rich |
PDF_VLM_BATCH_PAGES |
Pages per VLM call when VLM parsing is used (1β16) | 4 |
PDF_VLM_MAX_WORKERS |
Cap on concurrent VLM calls (useful on shared keys to avoid 429 storms) | unlimited |
Priority: Settings UI >
.envfile > system environment > defaults. You can alsoexportvariables directly β.envis just a convenience.
βββ server.py Flask app entry, middleware, logging
βββ bootstrap.py Auto-dependency repair (LLM-guided)
βββ index.html Main chat UI (single-page app)
β
βββ lib/ Core libraries
β βββ agent_core/ Reusable agent base (run loop, dispatch, TaskRuntime, push, profiles)
β βββ llm/ LLM API client package (build_body / stream / cache / diagnostics)
β βββ llm_dispatch/ Multi-key multi-model smart dispatcher
β βββ database/ Dual backend β SQLite default, PostgreSQL auto-bootstrap
β βββ tasks_pkg/ Task orchestration & context compaction
β β βββ orchestrator.py Main LLM β tool loop
β β βββ executor.py Tool execution engine
β β βββ endpoint.py Planner β Worker β Critic loop
β β βββ compaction/ 3-layer context compaction (package)
β βββ tools/ Tool definitions & schemas
β βββ swarm/ Multi-agent orchestration
β βββ fetch/ Content fetching & extraction
β βββ search/ Multi-engine web search
β βββ browser/ Browser extension bridge
β βββ project_mod/ Project co-pilot (scan, edit, undo)
β βββ memory/ Memory accumulation system
β βββ mcp/ Model Context Protocol bridge
β βββ feishu/ Feishu bot integration
β βββ scheduler/ Task scheduling (cron, proactive agents)
β βββ image_gen.py Image generation (multi-model dispatch)
β βββ mt_provider.py Machine translation providers (NiuTrans, custom)
β βββ desktop_agent.py Desktop automation agent
β βββ ...
β
βββ lib/conversations/ Project Brain β charter, board, feed, peer messaging, path leases, status lane
βββ routes/ Quart Blueprints + routes/api_v1/ (headless API)
βββ lib/billing/ Multi-tenant relay billing (wallet, ledger, pricing, payments)
βββ lib/oauth/ OAuth flows (Claude, Codex, PKCE, token store)
βββ lib/optimizer/ Nightly self-tuning loop (analyzer β proposer β applier)
βββ clients/ Headless API SDKs (python/, typescript/)
βββ static/ CSS, JS, icons
βββ browser_extension/ Chrome extension (Manifest V3)
βββ tests/ Test suite (unit, API, E2E)
βββ data/ Runtime data (git-ignored)
Tofu runs on Quart (async Flask) via Hypercorn; existing sync route handlers run unchanged in a thread pool.
| Feature | Linux | macOS | Windows |
|---|---|---|---|
| Core chat & tools | β | β | β |
| SQLite (default, zero-config) | β | β | β |
| PostgreSQL auto-bootstrap (optional) | β | β | β |
| Project co-pilot | β | β | β |
| Shell commands | β | β | β
(cmd.exe) |
| Desktop agent | β | β | β |
| Browser extension | β | β | β |
Smoke test: python debug/test_cross_platform.py
# All tests
python tests/run_all.py
# Individual suites
python -m pytest tests/test_backend_unit.py
python -m pytest tests/test_api_integration.py
python -m pytest tests/test_visual_e2e.py
# Or via the Makefile (parallelized; tune with JOBS=N)
make test-unit # fast unit tier
make test-api # API integration tier
make test-frontend # jsdom frontend suites
make test-all # everythingTofu has a tri-state auth model, persisted at data/config/auth.json and switchable from Settings β π API Keys (top of the tab):
| Mode | Gate | Use case |
|---|---|---|
open (DEFAULT) |
Pass-through; synthetic local-admin context | Personal install, frontend-only, loopback-bound |
private |
Bearer / x-api-key / cookie / ?token= required; HTML hint page on / |
Single multi-device operator |
multi-user |
Same gate as private, plus per-user wallets + signup pages |
Paid relay station serving many users |
Default bind is 127.0.0.1 β the API is not reachable from the LAN unless you pass --host 0.0.0.0 or BIND_HOST=0.0.0.0. Combined with open-by-default mode, personal use just works locally without exposure.
First-boot bootstrap (private/multi-user only) β when the api_keys store is empty and TUNNEL_TOKEN is unset, Tofu mints one tofu_admin_<hex> key on startup, prints the plaintext + a one-shot ?token=<...> URL to stderr, and writes the plaintext to data/config/.first_run_token (chmod 0600). Disable with TOFU_AUTO_KEY=0.
Token transports (priority): Authorization: Bearer β x-api-key (Anthropic SDK) β tofu_session HttpOnly cookie β ?token= query string (consumed + stripped β cookie, private mode only).
TOFU_AUTH_MODE=<mode> environment variable locks the mode β the UI radios are disabled and a 409 error_kind=env_locked is returned on PUT /api/v1/auth/mode.
Other security notes:
- No secrets in source β all credentials loaded from environment variables or Settings UI.
- Tool execution β the assistant can run shell commands and edit files; dangerous patterns are blocked, but use with appropriate caution.
- Desktop agent β requires explicit
--allow-write/--allow-execflags. TUNNEL_TOKENis a deprecated back-compat shim and prints a warning at boot β migrate to the API-keys system.
This README is written for people. If you're driving Tofu from a coding assistant, building on top of it, or contributing code, the machine-facing materials live here:
| Document | What it covers |
|---|---|
CLAUDE.md |
Project intelligence & mandatory rules for AI-assisted code changes (logging discipline, code style, change-approval gates, the frontend/backend boundary). |
JOURNAL.md |
The project's evolution journal β what was tried, why it changed, current status. |
docs/ARCHITECTURE.md |
Full directory map + Mermaid architecture diagram (and docs/architecture.html for the visual version). |
docs/HEADLESS_API.md |
Complete headless-API reference (the /api/v1/*, OpenAI, and Anthropic surfaces). |
docs/CUSTOM_TOOLS.md Β· docs/TOOL_PLUGINS.md |
Adding your own tools and plugin blueprints. |
docs/PROJECT_BRAIN.md |
Deep dive on cross-conversation coordination. |
/api/openapi.json Β· /api/docs |
Live OpenAPI 3.1 spec + Swagger UI served by a running instance. |
See CONTRIBUTING.md for the full guide. Quick version:
- Fork β feature branch
python healthcheck.py && python tests/run_all.py- Submit a pull request
MIT


