A self-hosted AI workstation for local models, cloud providers and agent teams.
Español · Quick start · Capabilities · Architecture · Setup guide
Faustus brings chat, coding agents, research, writing, image and video workflows, voice, and project knowledge into one workspace. It is a personal Odysseus fork, with a Python/FastAPI backend and a React/TypeScript interface.
Use local models through Ollama and compatible servers, or connect cloud APIs. Configure an orchestrator and its specialist agents inside a conversation. Keep work, sources, generated files and project context together, and see what is running rather than guessing whether a model has frozen.
The recurring idea is that the agent has to show its work: which context a turn was built from, which tool produced which evidence, which model answered and what it cost, which approval unlocked which action. Every feature below has a test that fails when that stops being true, and a section in FAUSTUS.md that explains why it exists.
Local-first means you choose where inference happens. Cloud APIs and authenticated official clients use their provider's billing or subscription quota; local inference uses your own hardware. Selecting a remote provider sends it the context needed for that request.
Install Docker and Docker Compose, then:
git clone https://github.com/Luissalet/Faustus.git
cd Faustus
cp .env.example .env
docker compose up -d --buildOn PowerShell, use Copy-Item .env.example .env instead of cp.
Open http://localhost:7000. The initial administrator password is printed in docker compose logs odysseus. Compose includes the search and vector-store services; it does not download a language model for you.
- Connect your model server in Settings or Cookbook. For Ollama running on the Docker host, configure its reachable address using the setup guide.
- Create a project and attach the files, documents or sources it should know.
- Start a conversation. Choose Chat for conversation or Agent for tools and actions.
- Use Activity to follow running conversations, workflows, renders and approvals.
- Add image/video engines, voice services or external agent clients when you need them.
Native installation, Windows/macOS instructions, GPU setup, HTTPS and environment configuration: setup guide. Preserve your data/ directory and back it up before upgrades.
Launchers live in this repository and resolve paths relative to the checkout:
| Launcher | Action |
|---|---|
Start-Faustus-Desktop.bat |
Open a native Electron window with theme-aware minimize, maximize/restore, full-screen and close controls. |
Start-Faustus.bat |
Start Faustus and open the web interface in your browser. |
Stop-Faustus.bat |
Stop the server managed by these launchers. |
Restart-Faustus.bat |
Restart that server and open the web interface. |
Python and Node.js are required for first-time setup. The launchers prepare missing dependencies, rebuild stale Studio assets and install the pinned desktop runtime when needed. Start-Faustus.ps1 -NoBrowser starts web mode without opening a tab; -Port 7001 selects another port.
Closing the desktop window stops the backend only if that window started it. An already-running web server is reused and remains running when the window closes. Process ownership is verified; unrelated Python processes and external model servers are not stopped. Desktop authentication is separate from your browser, so sign in once in the window.
Scheduled work requires a running Faustus server and an awake computer. Use web mode to leave the backend running after closing browser tabs; closing an owning desktop window stops scheduling too. In Agent chat, request a recurrence in English or Spanish, specify a time and time zone, and manage the saved task under Automations. Recurring tasks support IANA time zones and daylight-saving changes; existing tasks without a zone retain their UTC behavior.
Studio installs as a standalone app (a PWA) straight from the browser — no app store, no build step. On Chromium browsers (desktop or Android), Settings → This device offers an "Install Faustus" button once the browser has offered to; on iOS/iPadOS Safari, which never offers natively, the same screen shows the manual step (Share → Add to Home Screen). Once installed it opens full-screen with its own icon, keeps the shell working offline, and can receive real OS notifications — turn finished, an approval waiting, a reminder due — even with the app closed, via the standard Web Push protocol (VAPID + aes128gcm, implemented directly on cryptography, no third-party messaging service). Reaching it away from your own network still needs the server exposed over HTTPS (a VPN or tunnel to it), which "This device" mentions but does not set up. Below 767 px wide the navigation becomes a five-tab bottom bar (Home, Studio, Calendar, Notes, Settings). Mobile API · mobile layout notes.
- Point-to-edit: select a point in a captured browser frame and describe the change. An annotated screenshot and capture provenance are added to the draft, not sent automatically. The agent must inspect the current page and project; screenshot coordinates are not invented source-code mappings.
- Project visual references: save named
@referencesas project context links, distinguish subject, style and composition, and explicitly attach them from the picker. Removing a reference link does not delete its gallery image. - Learn a style: derive editable style rules from TXT/Markdown examples using the selected model, compare baseline and styled answers, then save and select a preset. Comparison makes two model calls using the selected connection.
- Local video: transcribe with an already-installed Whisper model, edit or manually translate timed segments, export SRT/VTT, and render narration using installed Windows English or Spanish voices. No cloud API or automatic model downloads. Inputs are bounded to 64 MB, 3 minutes and 1080p; FFmpeg/FFprobe are required. This is practical local narration, not voice cloning or lip-sync. Original audio is replaced in the narrated export.
- Meeting notes: record or upload an audio file and get back Markdown notes — summary, decisions, action items (owner/due date when stated), open questions and the full timestamped transcript — from a background job that chunks long recordings, transcribes each chunk with the configured STT engine, and runs one local-model pass to write the notes. If that model pass is unavailable, the transcript is still saved with a warning instead of being lost. Listed under Library → Meetings.
- Switch between local and API models; connect OpenAI, Claude, Gemini and OpenRouter through guided API setup with connection testing. OpenRouter calls report their real cost, per-endpoint preferences (data collection, provider order, web search only when asked) are explicit, and a local-only privacy profile refuses outbound calls instead of downgrading silently.
- A switch in Settings → Default AI (mirrored in Settings → Local models) chooses whether the default chat model loads at startup and stays resident — flips live, no restart: on loads it now, off releases it right away (VRAM freed within seconds, never mid chat turn). Works for both local backends: kept resident in Ollama via
keep_alive, or a managed llama.cppllama-serverstarted and exempted from its own idle-unload timer while the switch is on. Every model listing (Default AI, Local models, the chat picker) shows who actually serves it — Ollama, llama.cpp, or a remote API — detected once and shared everywhere. - Constrained decoding on both local backends: when an internal pass asks for a JSON object, the schema goes on the wire as a grammar —
formaton native Ollama,response_formaton llama-server — so the model cannot emit a token that breaks it. Forcing plain JSON is not enough: it returns valid JSON carrying a value outside the allowed set. - When the engine that serves the default chat model is stopped, Settings → Local models says so above the engine list and offers a button that starts it, instead of letting the next chat fail with nothing to act on.
- A local model stays loaded between agent turns: the keep-alive refresh sent when a run ends (or pauses on an approval or a question) carries the runner's own context size, so Ollama never mistakes it for a reload and evicts the model. Long batch runs no longer pay a full model load on every turn.
- Reasoning mode per turn: Auto, Fast, Think, Deep. A chip in the composer (for models that can think) and
/think auto|fast|think|deep. Auto is a deterministic Spanish/English rule: small talk answers without thinking, short lookups and questions about dates or quantities think lightly (low effort, small budget: measured on the local 27B, no thinking got 6 of 24 objective checks right, thinking got all of them), code, maths (word problems included), planning and analysis think with a budget, and an explicit "in depth" gets the large budget and a longer watchdog. The budget reaches llama-server and OpenAI-compatible engines; what Auto chose shows on the chip after the turn (spec). - The model's own reasoning levels, next to the model picker. When the selected model's server template declares reasoning efforts (a local llama-server), the reasoning chip lists them (Low, Medium, Maximum) plus "Follow the mode" and "Off"; the level picked wins over the mode for that chat. An effort the template does not accept is fitted to the nearest one it does instead of failing the request.
- Images reach a model that cannot see them. When the chat model has no vision (a llama-server without a projector, a text-only API model), a vision model describes attachments and tool screenshots for it: the one configured in Settings → Default AI → Vision (endpoint + model), or else one found on your local servers, preferring a model already loaded or a small dedicated vision model over a big general one, called with a small context window so it does not take the chat model's VRAM. Older images in the history reach a text-only route as their saved description instead of an image the server would reject;
/api/modelslists which models see (models_vision) (API). - A plan step that eats the clock gets a nudge. A step left in progress with the plan unchanged is asked to close with what it has after
agent_todo_stall_nudgerounds oragent_todo_stall_minutesminutes, whichever comes first. The time limit is what matters on a slow local model. - A turn that gathers without fixing anything gets asked for a first version. Whatever the tools (reads, probes, image questions, alternating sources),
agent_no_progress_roundsrounds (15) in which nothing was written, no plan step closed and no question asked bring one note asking for a first version of the deliverable now, with gaps marked; twice that insists once. It never blocks a tool and stays out of plan mode (progress_watch.py). - Follow-up rounds can think less.
agent_followup_reasoning_budget(Settings → Agent, off by default) caps the reasoning of agent rounds that follow clean tool results. The first round keeps the full budget, and so does any round after a failed tool, a refusal or a harness note. - Six questions about one image, then write it down.
inspect_imagecounts the questions about each image since the last successful write; everyvision_write_everyof them (6 by default, 0 = never; Settings → Agent → Vision) the answer asks the model to write its current best answer first and then ask only about the gaps that could change it. Across the whole turn, every twice that many images looked at by any means (crops opened withread_fileincluded) with nothing written brings a harness note asking the same. - Prompt-cache reuse per round, in the log. llama-server rounds carry
cache_nnext toprompt_n, and the agent loop logs[engine] round N: prompt X tokens processed, Y from cache, prefill Z ms, so a slow prefill shows whether the cache was lost. - The prompt a local server has cached is not rewritten. Older tool images are dropped four at a time on large windows (
agent_keep_images_batch), and the reply-language reminder gets a new copy instead of being moved, so each round's request starts with the previous one byte for byte and llama-server only processes what is new. Across turns, a chat keeps its tool set (saved across restarts, up toagent_sticky_toolset_maxtools), and plugin tools that only semantic retrieval picked do not widen it on a follow-up. - Prompt-cache reuse per turn. Each turn's metrics carry
prompt_cache(tokens processed, reused, and rounds whose cache stopped short); Studio shows it under "Why did it take this long?", andscripts/daily_eval.pyreports the reuse share for the whole run. - MTP drafting on a local engine, measured. An engine with
mtpon starts llama-server with--spec-type draft-mtp. On a 27B with four parallel slots, 3 draft tokens took one request from about 10 to 18–21 tokens/s and still helped a little with two at once, so there is no need to drop to one slot. - The context count includes the model's own kept reasoning. Qwen3-family templates replay every assistant turn's reasoning since the last question. The token estimate and the per-turn context ledger count it now, on its own line. Token calibration relearns after an estimator change instead of carrying a skewed factor.
- Reasoning that goes round in circles is cut short: when the model's thinking restates the same long sentence for the third time, the round is retried with the sampler pushed out of the loop instead of burning the whole reasoning budget.
- A turn that gets stopped still answers. When the loop breaker ends a run for repeating itself without progress, everything needed for an answer is already in the conversation, so one tool-free pass writes it — on the route that was actually answering, so the cost lands where the work did. A stopped turn is never a blank reply.
- Asking a question is not treated as dodging work: with a workspace open, a request to explain something is answered in prose without being sent back for a tool call, and the standing reply-language reminder is placed so the last thing the model reads is the step it was just given.
- Paste screenshots directly with Ctrl+V, upload attachments and reference workspace files.
- Navigate long chats with the message rail: hover previews, click/drag to jump, or use arrows, Home/End and Page Up/Down. Browsing older messages pauses automatic stream following.
- Read generated Markdown beside the chat, edit it and save it with conflict detection. Unsaved drafts belong to their conversation and survive panel navigation. Three Studio layouts (conversation, document, review) share one document session, so a selection in the document becomes a context chip in the composer and a suggestion from the agent lands with its anchor, never on the first matching line.
- A model answer can include a chart: a fenced
```chartblock with small JSON (bar/line/pie/area, series, an optional unit) renders inline as an SVG with axes, legend, tooltips and a "Show data" table — no charting library, and anything malformed just falls back to a plain code block (spec). - Keep files, generated outputs, sources, project context, agent activity and browser captures in a resizable side panel.
- Move to another conversation while the server keeps the current turn running. See queue position, current activity, tool use and permission requests; reconnect to the existing work. An approval card whose permission died with a restart says so instead of offering dead buttons.
- Every turn shows the strategy the agent chose (direct edit, plan then execute, research, specialised review, explore alternatives) and why; a turn worth repeating can be saved as a recipe with its real inputs.
- See every model call a session made — a "Model calls" panel shows the exact request sent (secrets redacted), the assembled response, tool calls, timings and errors for each call, and any recorded call can be re-sent unchanged to a different model to compare answers side by side.
- Search and navigate with Ctrl+K: from the second character it also searches everything you own at once (chats, brain, notes, documents, images, skills and board issues), mixed by relevance, with a filter row by type; each hit opens its own screen (unified_search.py). Use English or Spanish, themes, density controls, adjustable text and reduced motion.
- Pick a behaviour mode — a named conversational stance (adversarial, socratic, terse, mentor, red team, outside observer, editor, or one you write yourself) that changes how Faustus argues, never what it is allowed to do; it sits after the task preset and strictly before the untrusted-content policy in every turn's prompt, agent mode and Incognito included (Behaviour modes API).
- Plug in your own local apps as plugins — every connector is now one manifest (
plugins/<id>/plugin.json), and an application can ship its ownfaustus-plugin.jsonso it is offered for connection on sight, with the form already filled in, without a patch to Faustus (Plugins). Faustus can list them, start one that is down from a launch profile you saved, and show it when you ask — it adopts an app that is already answering instead of restarting it, and nothing lets it stop one. Naming one of your apps in a request brings these tools along, and an app that comes up at a different address than its connection says is named as such instead of waited on. What you ask for in so many words ("start Jobhunter", "what do you remember about me?", "remember that I work from home on Mondays", "put a dentist appointment in my calendar on Tuesday at five", "write me an email for my landlord") runs without an approval card, and so does fetching a link the search itself returned when you asked to look something up; anything the model decides on its own after reading untrusted content still asks, and after web text is in the turn, writing a document, a memory or an event asks again. The same holds for work inside a project folder: running its tests, a command you wrote in backticks, looking at its files with the shell, a data analysis in Python that provably stays inside the folder, running the script you asked it to write and test when its code provably stays inside the folder, and writing the file you named; installing packages, capturing the screen or code that could reach outside the folder still asks. A/connectorsscreen over the existing MCP manager with real states that keep "the app is off" apart from "the adapter failed its handshake", user-configured launch profiles (structured argv, no shell, readiness, idempotent), and a per-chat / per-project / per-scheduled-task connector allowlist that the tool dispatcher enforces rather than merely hides (Connectors API, tool selection, candidature recipe). - Eleven more of your own apps as plugins — Cassandra's (observability for the whole local stack: which service is up, what went down and when, what else changed in that minute, what the logs said, what the GPUs were doing, opt-in restarts), Nightingale's (a data workbench: bring files, folders or URLs in, clean them with versioned steps you can undo and replay, check them with quality rules, chart and dashboard them, train quick models and forecasts), Echo's (your clipboard history, searchable, with secrets hidden before they are stored; the assistant can also put text on your clipboard), Hypatia's (spaced-repetition flashcards the assistant writes from what you read and quizzes you on in chat), Vulcan's (your 3D-printable models: dimensions, thumbnails, duplicates and marketplace listings the assistant writes), Ledger's (household money), Links (read-later with the extracted text), People's (who is who, last contact, birthdays), Argus's (private screen memory with local OCR), Borges's (your documents indexed with local embeddings + BM25, answers with file and page) and Scribe's Hoard (meeting recorder: microphone and system audio as two tracks, local transcription). Each ships its own
faustus-plugin.json, is recognised on its port and was driven end to end from a chat with a local 27B ("create two accounts and note 12,50 € of taxi", "save this link and tell me what it says", "what was I doing ten minutes ago?", "add this folder to my library and quote what it says about plugins"). Five library skills read across them:hoard-family-recap("what happened in the hoards": watched arrivals, rules and jobs, backups, incidents),hoard-what-happened("what broke at 4 am": a sourced timeline from the audit trail),hoard-daily-digest("how did my day go": screen, money, reading, people, meetings, study),hoard-meeting-prep("I have a meeting with X": who they are, the last conversation, what you saved, the exact library passage, when it last came up on screen) andhoard-study-cards("make me flashcards from my notes on X" and "quiz me"). Since Hoard Link 0.4 the family is one system: every app posts events to the Hoard Hub's bus (each tool call the assistant makes, each finished transcript or new watched release), the hub runs rules ("when a transcript finishes, draft flashcards") and scheduled jobs (nightly deduplicated backups of every app's data), any app can call another's tools through the hub without knowing its port or token, Cassandra keeps the whole audit trail and checks the repositories for leaked secrets, Links follows feeds, GitHub releases and page changes for you, and Borges indexes the links you saved as citable documents. Manifest keys that start withx-are extensions for those readers and are skipped here, not refused. A machine can start an app differently from how it ships, a developer build of Writer's Hoard whose library lives in the dev server's origin for example, through the hub'slaunch_overrides, and a manifest may list several executables (the installed copy first). - Vitruvius's Hoard: design criterion, not guesses — a twelfth plugin app that gives the assistant the design sense a code model lacks: a library ingested from 22 open design-skill repositories (rules, UI styles, palettes, font pairings, motion recipes; every hit cited by source and heading), a render → capture → critique loop on headless Chromium (screenshots at any width, 29 deterministic design-lint checks for contrast, generic fonts, the stock purple-to-blue gradient, hero-plus-three-cards, missing reduced-motion, lorem ipsum…, plus an optional local vision critique scored 0-10), an OKLCH design-system generator exported as CSS variables, a Tailwind theme and W3C tokens with a live playground, and a reference gallery that captures any web page with a scroll video, its fonts and palette. The loop the assistant follows is write →
render_preview→design_critique→ fix → render again →page_assay(does every control actually work), and it ships as thehoard-design-looplibrary skill. Library search is hybrid: BM25 plus local multilingual embeddings fused by rank, so a Spanish question finds English criteria. - See what is running because of Faustus and stop it — a
/processescontrol center: listening ports with the process behind them, the agent's shells and MCP servers, background jobs, launched profiles and watched apps (Cursor, ChatGPT, node…), each with its origin and a Stop that only a person can press (the agent token is refused, the pid's creation time is the proof, the OS and Faustus itself are never targets). The same screen starts with Apps: your own local projects as cards with their icon, live status, Start / Stop / Restart, a console tail, and Open in a desktop window of their own (a generic Electron shell with the app's icon and taskbar identity) — add, edit and remove them freely; apps without an MCP server become connectors through a generic REST-to-MCP adapter fed by their OpenAPI or a small manifest. - Review your mail and update your job hunt —
review_candidature_mailreads the last N days of mail (never marking anything read), finds the employer replies (rejections, interviews, offers), matches or creates the application in Jobhunter's Hoard, records the reply there (idempotent by message id) and puts each interview with a stated date on the calendar (one event per interview slot); ambiguous employers and undated interviews are reported for manual review, never guessed. One tool call, so a local 27B does it in one turn. - Ask for things that repeat, and see them on Home — "what's the weather in my town tomorrow, every day", "a daily news briefing on X", "tell me when this shop has it back in stock", "summarise my mail each morning": built-in watcher actions (weather from Open-Meteo, page watch that reports only on change, news brief with sources, mail digest) run on the scheduler without needing a model to browse, and any automation can be pinned as a card on the Home screen with its latest result, a Refresh button and its next run.
- Your WhatsApp, read and answered from here — pair your own account by QR (WhatsApp Web multi-device protocol, a local Node bridge on the loopback with a token), then ask "what did people write me today", "summarise what Ana said", or "tell Ana I'll be ten minutes late" — every send is approved by you; voice notes arrive transcribed; a daily WhatsApp digest can be a Home card; Tools → WhatsApp is a real chat client (profile pictures, groups, older messages, replies with quotes, reactions, forward, edit, delete, ticks, typing, search, attachments, recorded voice notes, dictation) with an "Ask Faustus" panel that summarises, drafts a reply in your voice or translates — text only, never sends by itself.
- Sync Google Calendar the way Google allows it — OAuth2 ("Connect with Google", the same client as Gmail) and the Calendar API v3, incremental
syncTokenpulls, recurrences and cancellations, etag-guarded write-back; iCloud, Nextcloud and any other CalDAV server keep the password form. The Google OAuth client is set up from Settings — the wizard hands you the exact redirect URIs, takes theclient_secret.jsonGoogle downloads, and checks it against Google, no.envedit or restart (Google Calendar, guide). - Drive Faustus from your own code —
sdk/tsis a zero-dependency TypeScript client (ESM + CJS, typed events generated from the versioned SSE catalogue indocs/api/sse_events.json): create a session, stream a turn, answer questions and in-turn approvals, cancel with the run's fencing token, and resume by cursor after a dropped connection without ever repeating a POST. API tokens get asessionsscope for exactly that surface (docs/api/sdk_surface.md); the A20 acceptance test installs the packed tarball into clean CJS and ESM projects and runs them against a real server with auth on. - Parity with the reference harness, measured, not claimed — a public parity matrix and 36 acceptance recipes from an independent audit live in
docs/spec/paridad/;scripts/acceptance_run.pyruns the ones that have real tests and writes one evidence row per case (commit, config hash, model, outcome, cost status). All 36 are green as of 16 September 2026 — tool discovery, code execution, artifact offload, sandboxing, MCP OAuth, the embeddable component, OIDC login, service identity, scheduling, skill sources, loop-breaking, learning with rollback, benchmarking, migration and distribution lifecycle — with the remaining honest gaps (SDK registry publication, a clean-machine install, session sharing, a git-backed sandbox for skills) named in the matrix rather than hidden (acceptance runner). - See how long everything actually took — every tool result starts with wall time (this call, the turn so far, the clock) so a slow command is visible to the model, not just to you; the same numbers ride the
tool_outputevent and the Studio's step card. - Reach — eyes on the internet across 9 channels (web, YouTube, GitHub, Reddit, X, Hacker News, RSS, arXiv, Wikipedia), each with an ordered, real fallback chain and no dependency on a third-party CLI.
- Code graph answers architecture and call-tracing questions — trace a path between two symbols, see what a diff's callers are, get a repo's route/hotspot map — without reading whole files. Impact queries (
code_graph_impact) walk incoming call edges from a symbol or from everything a diff touches, follow aliased imports, and hand back the affected test files with a readypytestcommand instead of a guess. - What is this repo made of, and which paths matter —
code_graph_communitiesclusters the code into named modules and coarser areas (deterministic Louvain over the call/import graph, tests attached to what they exercise, names taken from real paths), andcode_graph_flowswalks every entry point (HTTP routes, agent and MCP tools,main) through its call tree with a 0-1 criticality score, the tests that reach it and thepytestcommand to run them. Impact queries also list the flows a change touches. - Reuse, adapt or write — verified — before building something,
prior_artgives the model a decomposition checklist, then checks everyowner/nameit proposes live against the GitHub API (exists, renamed, archived, fork, last push, licence against yours) so no invented or dead repository reaches you; licence mismatches downgrade "reuse" to "adapt: study it, write your own". Reports are saved and searchable (Prior art API). - Architecture drift check —
code_graph_driftrecords a baseline (communities, coupling, flows) and later compares the current graph against it: new/removed modules, files that moved between them, a new dependency into a previously isolated module, a dependency cycle introduced, flows that changed shape or criticality, a removed public symbol still referenced — as a 0-100 score with the top findings explained. Wired into the agent harness (code_graph_drift_check, on by default, never blocking): a baseline is taken before the turn's first edit and compared after the last, with a short note on the turn's summary when drift crosses the threshold. - Fan-out races one prompt across N candidate models (local and paid mixed freely), each in its own isolated worktree, and scores the results automatically instead of asking you to eyeball N diffs.
- PDF operations transform an existing PDF — merge, split by arbitrary range, rotate, reorder, compress, watermark, rasterize, OCR — the one thing the rest of the PDF layer never covered.
- PDF structure navigation (
pdf_outline/pdf_find_section/pdf_read_section) builds a table-of-contents tree from a PDF's own bookmarks (or heading detection, or fixed chunks as a last resort) so a long PDF can be jumped to by section instead of read page by page, with page numbers that always come from the tree, never guessed by the model. - Documents read as documents —
read_fileon a PDF returns its text page by page (with the outline/section tools for long ones andinspect_imagefor scanned pages), on a Word, PowerPoint, Excel or EPUB file returns it as Markdown, decodes UTF-16 exports, and names any other binary instead of dumping it; an image comes back as the picture itself. - Look closely at an image, not a generic caption (
inspect_image) — crop a region, rotate, zoom, enhance (autocontrast/sharpen/grayscale/threshold), overlay a labelled grid, ask a SPECIFIC question, count people, figures or objects tile by tile and in one look (both numbers, and a note when they differ), or detect circles/rectangles/lines with no model at all; works on a local image, a PDF page, or a fetched URL, and compares two images with a shared crosshair point. A vision-capable model gets the processed image attached directly; a text-only main model gets the same question answered by the configured Vision model instead of the fixed "describe this image" captionread_filefalls back to. - Precise RAG locators for PDFs — every chunk indexed from a PDF carries a stable, deterministic
p12#b3(orp12-13#b3when it spans pages) locator pointing at its exact page and block, shown alongside citations in retrieved context so an answer can point at the exact spot it came from. Optionalrag_pii_redactionsetting (off by default) sanitises emails, phone numbers, IBANs, card numbers (Luhn-checked), Spanish DNI/NIE (control-letter checked) and IPv4 addresses out of chunk text before it's embedded/indexed, without touching the original uploaded file. - Agent personas — 16 built-in identities (backend, security, writing, product, ML…) that slot into an agent's own AGENT.md without replacing its tool permissions.
- MCP tools per agent — an AGENT.md
tools:/deny:list can name MCP tools with wildcards (mcp__github__*,mcp__*); an allowlist is exclusive for MCP tools too, a coordinator's allowlist reaches the workers it starts, and a refused MCP tool is neither offered nor executable. - Code Mode (
run_code) composes tool calls inside an isolated subprocess under the same policy gate as a direct call, with wall-time, call-count and output-size quotas. - Embed Faustus in your own page with
<faustus-chat>(studio/embed/), a Shadow-DOM Web Component with its own SDK client, no global router or CSS, and a token that never toucheslocalStorageor the DOM. - Sign in with your corporate identity provider — OIDC with Authorization Code + PKCE, one-shot state/nonce, and email-verified account mapping.
- Creator (flag
creator_enabled, off by default) — a media production domain, 27 of its 43 work packages implemented and mounted: document model with revisions, library and lineage over the existing artifact catalogue, model identity vs. deployment, capability and parameter contracts, pure preflight, an adapter port with a generic contract test-harness, non-destructive ops on an exact rational clock, timeline and clocks, a deterministic FFmpeg render graph, aligned ASR transcription, a subtitle editor with its own SRT/VTT/ASS exporters, voice casting with consent records, a layered image canvas, storyboard and production plan (validated DAG), a music studio, a model explorer, expressive ComfyUI recipes, goals with typed completion criteria, physical resource inventory, safe plugin lifecycle, and preset evaluation/discovery. No engine is bundled: every adapter reportsavailable=Falsehonestly until one is installed. - Answers checked before you read them — without a model: a weekday named for a full date is checked against the calendar, visible working and second thoughts ("…wait, let me recount…") are spotted, and a slot suggested as free is checked against the calendar the turn just listed; any of these asks for one clean rewrite, and a draft the model is asked to write again is taken off the screen instead of staying above the corrected answer (answer_checks.py).
- A harness for long implementations — what 24 real chats of a from-scratch project taught it (FAUSTUS.md §95): a turn with red tests, a failed UI smoke test or a contradicted changeset can never close as complete; the harness itself starts the project's web server and checks every page and asset (status and Content-Type, console errors with Playwright) instead of trusting the model to open a browser; missing dependencies are reported before the first command; a delegated worker that returns nothing is retried once and then reported, never silently accepted; the second whole-file rewrite of a large file is refused in favour of a targeted edit; tests excused as pre-existing become high-priority todos after three turns; and a big implementation plan attached to a message is parsed once into a per-task tracker (
plan_status/plan_task/plan_done…) so the model sees the current task and its acceptance criteria, not 172 KB of plan again — and "keep implementing the plan" that ends with zero tool calls is rejected, not accepted as an answer. - UI accessibility and performance audit — the headless smoke check that already catches console errors now also flags missing alt text, unnamed buttons/links, unlabelled inputs, missing
lang/title, duplicate ids, heading skips and WCAG AA contrast, plus navigation timing, LCP and JS/CSS byte counts. Findings surface as quality warnings and only block the turn whenagent_ui_smoke_a11y_blockingis turned on; performance findings never block.
What the model sees next is exactly what is wired to the conversation — a rule borrowed from ThoughtDAG and applied to ordinary linear chats. The human draws the graph; no agent creates wires on its own.
- Explore separately: select a passage in a reply and open a side thread that sees the conversation up to that turn plus the passage, then grows on its own. The original conversation does not change. The thread list indents side threads under their parent, and a thought map shows the tree.
- Bring it back: wire the side thread into its parent as an explicit reference block — latest exchange, or the whole thread — change its depth, withdraw it or remove it. A withdrawn wire keeps the thread.
- Materials: pin a document selection (or the live document) and free-form notes as context that stays until you withdraw it. The Context wires panel previews the next turn layer by layer with token counts, and says what it does not count.
- Replay under a button: every reply records which wires it was written against. When a side thread or document moves on, the affected replies say so and offer Regenerate with the current version; nothing regenerates by itself.
- Every answer keeps its earlier versions: regenerating or editing a question no longer loses the answer it had. The reply shows ‹ 1/3 › to flip between them in place, with when, which model and the question as it was asked; Use this version makes one current and keeps the one it replaces. The
answer_versionsMCP tool lists them for an orchestrator comparing a retry with a first attempt (chat_versions.py). - Condense by hand: pick a range of settled turns and fold them into one summary row using the same summarizer as automatic compaction, on your own model. Expand restores the originals byte for byte; the turn in progress is never eligible.
- Define an orchestrator and its minions from the chat, choosing models, roles and tool restrictions.
- Delegate to child conversations with file ownership, progress, cancellation and steering.
- Use Council for blind first rounds, critique and synthesis across multiple models, with a designated executor for actions.
- Use skills, MCP tools, filesystem tools, shell execution and browser capabilities under the configured permissions.
- Connect official Codex CLI and Claude Code workers through the existing runner/dispatch system. Both also have private text-model connections for the Faustus chat loop, with an explicit subscription/API choice. Codex chat uses an ephemeral, environment-less App Server thread; Faustus retains tool execution and approvals.
- Keep subscription and API routes explicit. Official-client authentication is checked before work; a subscription error does not silently fall back to paid API usage.
- Inspect tool evidence, syntax checks, project tests and review results. Shadow-git checkpoints support diffs and restoration without replacing the project's own repository.
- Reopen original change evidence from a turn's summary. Owner-scoped receipts survive restarts, distinguish saved evidence from verified success, and feed the project's State Mirror; incognito turns are excluded. Evidence history.
- Source control without leaving the workspace: repositories discovered from linked folders, identities from
~/.ssh/config, manual entries andghaccounts, create/clone/publish on GitHub, branches, merges and pushes from a panel with a draggable edge, and a per-repository policy the agent'sgit_*tools obey (the shell refusesgit commit/pushon their behalf). A git radar watches every repository — linked project folders plus any folders you choose — and shows which ones still have uncommitted or unpushed work, as a strip in Source control, a badge in the sidebar and a block on Home that only appears when something is waiting; ask the agent "what have I not pushed?" (git_radar) or schedule it to notify you only when that set changes. Git API. - Autonomous engineering, end to end. Hand the agent a GitHub issue (
github_issue: URL,owner/repo#Nor#Nagainstorigin) and it can finish with a pull request (git_open_pr, only on a pushed branch and only where the repository policy allows remote writes). A bug hunter (bug_hunt) writes edge-case tests for a file or symbol, runs them in isolation and separates real bugs from wrong expectations, keeping the tests that expose real bugs as regressions. A CI failure analyzer (ci_failures) reads the failed jobs' logs of the last GitHub Actions run, extracts the concrete pytest/jest/tsc/cargo/go failures and maps them to the files in the workspace, and a five-agent deployment team in the agent library (deploy-lead+ reviewer, dependency auditor, CI analyst, log monitor) correlates findings into one action list. A fix memory records what each solved task changed, which errors it saw and how it was verified, and recalls the closest past fixes before the next similar task. Handoff lanes make who-may-delegate-to-whom (and with which tools) an explicit, inspectable policy with a Mermaid graph (off/shadow/enforce), and a night shift runs a queue of tasks unattended under a time/task budget and leaves a morning report.code_historyadds churn, blame, co-change and a risk score per file or symbol. APIs: bug hunt, CI failures, fix memory, handoff lanes, night shift, code history. - Wide and long runs.
swarm_mapapplies one instruction to many items (40 companies, 30 files, 100 URLs) in parallel — one model call per item, or one small tool-using worker per item — as many at once as the model server actually has free (llama-server/slots, minus the slots other chats are using), retrying each item once, never aborting the run for one failure, with an optional reduce pass and a Markdown/CSV/JSONL results table; runs resume after a restart and show in Workers (recipe). In long runs the model can manage its own context:context_statusshows what fills the window with stable handles, andcontext_pin,context_dropandcontext_notekeep, move out (reacquirable withread_overflow) or summarise earlier tool results; they are only offered when the window fills or the run gets long, so a short turn pays nothing for them (API). Every turn now records input and total tokens, tokens per tool call and per round. - Wide review fan-outs, bounded workers.
delegate_agentstasks can name a tier (local/fast/mid/frontier, each mapped to a model in Settings › Agent › Sub-agents) instead of a model; an allowed-model list is enforced before a worker starts (a worker naming anything else is refused and the coordinator is told why);read_onlyreviewers read and report a few findings in a short reply with a 6-round leash while editors own disjoint files; each task can carry its own rounds and timeout; the width is the owner's (up to 128) and workers on a hosted API wait on that API's own lane instead of the GPU slot. In one round, file edits on paths nothing else touches run side by side with the other independent calls (keyed dispatch); anything that could see another call's effect keeps its order, and a write that the approval gate might stop is never run ahead of it. - Small apps run right in the chat. An
htmlorsvgblock in a reply has a Run button: a generated calculator, quiz, timer or diagram runs in place, in a sandboxed frame with its own content policy (no network, no access to Faustus, its cookies or storage). The document editor's HTML preview uses the same runner, so its scripts run too. - The agent reviews its own turns.
turn_reviewreads what the last turns of a chat saved (tools, failures with exit codes, rounds, writes, slowest calls, prompt-cache reuse) and names what went wrong: the same failure twice, a loop over one tool, many rounds without writing, a lost cache. The agent uses it before retrying; you can ask "why did the last answer take so long?" or type/why [N](turn_review.py). - Headless runs.
scripts/faustus_run.py -p "…" --jsonruns one agent turn against a running server and prints NDJSON: a start record, every event, and a summary with the answer, tools, rounds, usage (prompt cache included) and why it stopped;--approveapproves the run's cards, otherwise it stops cleanly on one (exit 2) and can be resumed with--resume-approval;--plan,--effort,--workspace,--session./stats(alias/cost) shows what the whole chat used, per model: tokens, prompt served from cache, steps, tool calls, time, cost (session_usage.py);/recap [days]does the same across every chat for a period, with local vs hosted, top tools and the busiest days (usage_recap.py); Home shows the last 30 days as a card (turns, local vs hosted, tokens, cache share, tool calls, the most used model and tools) with a link to the full recap. /review [base]: a staged review of the working folder. The cheap, certain stages run first: the diff against the base (untracked files included), static analysis kept to the added lines, and only the tests related to the changed files. The chat's model then reads the diff with those results as established facts and looks for what they cannot prove: logic, edge cases, removed behaviour. Findings come back tagged by source (static, tests, model) (staged_review.py,POST /api/review/worktree, admin only).- The harness brings out each model's strongest reasoning. Reasoning is asked in each provider's own words on both the streaming and the helper path: llama-server's thinking switch and budget, Ollama's
think, OpenAI'sreasoning_effort, Claude's adaptive thinking andoutput_config.effort(up tomax/xhigh), OpenRouter'sreasoning, stepping down when a model refuses a level. Every mode has its own level (Settings › Agent › Reasoning per mode): Deep Research and the teacher think at the maximum by default, council members high. Claude as the model caches the whole conversation (rolling breakpoints, not only the system prompt) and keeps thinking inside tool loops (its signed thinking blocks go back with each tool call). - Code Mode pauses for approval, then resumes. A script call that hits a per-call desktop approval gate opens a question, waits on the person without charging that wait to the script's own wall time, and on approval runs that exact call once through a sealed single-action approval before continuing.
- Typed choice decisions: internal code can ask a local model to pick among a few fixed options from a single constrained forward pass (option log-probabilities) instead of generating and parsing text; used as an opt-in extra judge layer for claim verification.
- Optional DevTools browser server (off by default): a second built-in browser MCP server for performance traces, network/console inspection and page audits, alongside the existing navigation and control server.
- Documentation of any GitHub repository as MCP, in one step: New MCP server offers two remote, keyless presets over Streamable HTTP: one repository's docs and code search (type
owner/repoor paste its GitHub address) and DeepWiki for every public repository, so the agent reads a dependency's own documentation instead of searching the web for it. The help says the questions go to that remote service. - Argument-level tool policy, beyond the per-tool on/off switch: an admin rule constrains one dotted argument of a tool (exact name or glob, e.g.
mcp__github__*) — a domain allowlist forweb_fetch, a path prefix for a write, a pattern or length cap on any field — and either denies the call outright or routes it into the same human-approval flow other gated actions use. Manage rules, and try a tool+arguments pair against them, from Settings → Tools. tool_arg_policy.py. - Shadow mode and confidence-tiered approvals (opt-in,
approval_autonomy, off by default): every gated action gets a locally-computed 0-1 confidence score from signals already on hand (read-only vs. workspace write, whether the request named the target, prior approvals of this exact tool by this user, reversibility).shadowmode changes nothing visible — every card still shows — but logs what the score would have decided against what the person actually clicked, so a tool family earns a track record.activemode auto-approves a family only once it has been promoted (≥20 confident decisions, ≥95% agreement, zero disagreements on anything destructive); nothing irreversible, destructive, outside the workspace, or that sends a message/payment is ever eligible, whatever the score. Per-family stats and manual promote/demote:GET /api/approval-autonomy/stats,POST /api/approval-autonomy/family(human-only — the model cannot promote its own tools), and a card in Settings → Agent. - Ask for tools in plain English or Spanish. Every built-in tool carries example phrasings and domain synonyms, tools you name or hint at are always offered, and a vague message with a workspace never gets
bashorwriteon the strength of an embedding. - Runs where your project runs. On Windows the agent's shell is Git Bash, a
powershelltool covers.bat/.cmdlaunchers,winget, services and registry, and thepythontool uses the project's own.venvrather than Faustus's. The Docker sandbox is an option, not a gate:agent_sandbox_modedefaults toauto, which runs the command on the host whenever the container cannot serve it — always on native Windows, where a Linux image has none of that toolchain — and says so on the result;strictkeeps the original rule of refusing rather than falling back. The turn's prompt states which machine it is on, built from the executor rather than by hand. - Alternatives: try several approaches to the same change in isolated worktrees or frozen copies, compare them against the base with contested files called out, and apply one with a three-way merge — a hand edit you made meanwhile survives. Document alternatives work the same way on document versions. Alternatives API.
- Semantic desktop control through the accessibility tree first and pixels only as an explicit, riskier fallback; taking the desktop back invalidates the agent's stale references. Desktop semantics.
- Structural code search and rewrite: AST patterns with metavariables (
$VAR,$$$ARGS), previewed as a diff and applied by Faustus itself inside the workspace confinement, not by the underlying CLI. - Change risk score before editing: a 0-100 score with its top reasons (callers, tests, churn, coupling, diff size) from the code graph and its co-change history, alongside the existing impact query.
- Lifecycle hooks, no bureaucracy: attach your own automation to
session_start,turn_start,pre_tool,post_tool,turn_endandpre_compact— run a command and feed its output to the model, inject a note, or warn on a pattern (tool glob, file glob, command or message regex). Hooks only add: they never deny a call or ask for approval. One-click presets (format after edit, TypeScript typecheck,git statusat session start, dev-server and--no-verifywarnings…) and a run log, from Settings → Tools. lifecycle_hooks.py. - Instincts: small learned behaviours (
when … → do …) mined in the background from real turns by the cheap utility model, each with a confidence that rises with confirmations, falls with contradictions and decays with time; scoped per project, promoted to global when seen across projects, injected when confident, and evolvable into a draft skill.manage_instinctstool,/api/instincts, Skills → Instincts. instincts.py. - Hybrid skill selection: the skills offered on a turn are ranked by a semantic lane (local embeddings), the lexical lane and the skill's own "Use when …" trigger, multiplied by an outcome prior learned from how you reacted the last time a skill was surfaced.
POST /api/skills/selector/explainshows the score breakdown. selector.py. - Bundled libraries: 47 installable skills (TDD, a docs-against-code release review, verification loop, context budget, security review, onboarding, API design, evals, web accessibility/UI design, an interactive "learn this repo" tutor that studies the code graph's modules and flows with you, systematic debugging, writing plans, a pre-task interview, spec-driven development, a code-review checklist, a code simplifier, performance work and "reuse before you write"; the third-party ones are adapted from MIT/Apache collections, listed in
skills/library/THIRD_PARTY_NOTICES.md…), 52 per-language rule files (commonplus Python, TypeScript, React, Go, Rust, Java, C#, Swift, Kotlin, PHP, web) that join the system prompt behind the project's own.faustus/rules/under a token budget and the same trust verdict as the instructions, and 19 agent definitions (language reviewers that cannot write, build-error resolver, TDD guide, architect…). Skills → Library, Project → Rules. skill_library.py · project_rules.py. - Skills written for other agents import as they are: a
SKILL.mdin the open skill format keeps its folded or literaldescription,allowed-tools,metadata,licenseandcompatibilitythrough a read and a save. skill_format.py. - Several instances, one Ollama: instances on different ports (and data folders) register a machine-wide lease (pid, port, default, pins, activity, VRAM reservations) so they stop fighting over the same weights — one residency leader per default model, sibling pins and reservations respected by admission and eviction, adoption of an already-resident sibling default instead of loading a second one, and
GET /api/local-models/instances/GET /api/healthto see who holds what from any port. model_lease.py. - An agent turn never ends in silence. With real progress (tool calls that advance the task), the round budget auto-extends up to a configurable ceiling, with a visible progress line instead of a blank card; with no progress, or a genuinely empty round, the turn ends with a concrete question to the user instead. For long, repetitive tasks, a standing strategy block in the prompt (agent mode only) guides the model to break the work into units, save a progress cursor, and resume from it.
These checks provide evidence about supported actions; they are not a proof that every model statement is true. Tool access, automatic verification and external runners are configurable rather than implicitly enabled by choosing a model.
Project identity is stored independently of the sidebar folder name. An agent can attach a generated document or another supported source to its current project's context by reference.
The context engine retrieves and budgets relevant material from project sources, history and memory. It tracks provenance, conflicts and compact context capsules instead of trying to place an entire disk in a model's prompt. Persistent storage extends what can be retrieved, not the model's native context window.
The MCP tools and integrations blocks in the prompt are scoped the same way: only the tools already selected for the turn get a one-line reminder (they already carry a full native schema), every other connected server collapses to a single "N more tools — call lookup_tools" line, and the whole block is capped by agent_mcp_prompt_budget_tokens (0 turns it off). Tool discovery (lookup_tools, tool-RAG) reads the full tool index regardless, so nothing becomes unreachable — this only trims what repeats in the prompt text. A full listing every turn is still available behind agent_mcp_prompt_full_listing.
When a request clearly belongs to a domain (calendar, notes, tasks, email, WhatsApp, contacts, documents, chats, desktop, media, integrations), that domain's everyday tools go out as full schemas on the first round even when vector retrieval missed them, so the model does not spend a round on lookup_tools first. The tool index embeds only the MCP tools whose description changed; a server connecting or disconnecting no longer re-embeds all of them. A reply that cites a tool result by its id ([L-000011] from the exact calculator, for instance) shows it as a footnote with what that result was.
Everyday-use battery. python scripts/daily_eval.py --base http://127.0.0.1:7000 --model <model> --endpoint-url <url> runs twenty end-to-end tasks against a live instance (dates, sums, the tool that had to run, no approval card, no harness text in the answer, a memory recalled in a new chat) with deterministic checks, and writes a dated JSON and Markdown report under logs/daily_eval/. --set key=value (repeatable) runs one A/B arm with a setting changed and restores it afterwards.
Sampler A/B for Spanish prose. python scripts/typos_ab.py --endpoint http://127.0.0.1:8081/v1 sends a fixed batch of Castilian prose prompts under several sampler presets (interleaved) and counts words a Spanish frequency list does not know, per 1,000 words (needs wordfreq).
Narrow-window check. python scripts/ui_narrow_check.py --width 420 opens every screen and every Settings section in a headless browser and lists what ends past the right edge (sideways scrollers excluded). It is read-only, and --css tries a fix before it is built.
lookup_tools only proposes names a connected server offers right now, whatever the embedding index still remembers. When a server answers that a tool does not exist (it changed its tools without announcing it), Faustus re-reads that server's list on the spot, so the index stops offering the old name, and the failed result tells the model which tools the server has now. A result whose body is a JSON object with an error counts as a failed call in the run, the harness and exports. A read action of one of the user's apps (evaluate, report, explain…) runs without an approval card when the request names the app and the act, and re-reading an artifact this run's own tool output was stored in never asks.
Skills relevant to the request are chosen by a hybrid selector (semantic, lexical and trigger lanes); the cutoff is the skill_selector_threshold setting (Settings → System, 0.22 by default), so a skill written in one language can still be picked for a request in another by adding tags and triggers in that language.
Use Skip memory recall in the composer to suppress automatic personal-memory retrieval for subsequent messages, including live context compilation. Existing chat history and project sources remain available. This does not disable memory tools or saving the chat; use Incognito for its separate privacy behavior.
In Agent mode, Agent context also lets you skip automatic skills and select a soft input-token budget before sending. These controls travel with the turn without changing global settings. The budget is an estimate, remains bounded by the selected model's context window, and is not a billing cap. Explicit tools and project instructions remain available when automatic skills are skipped.
A project also carries:
- a board of typed issues (
KEY-Nids, priorities, labels, links, comments) with a kanban and a table view, Markdown import/export, and commit messages that close issues with fixes/closes/cierra/arregla; the agent getsboard_*tools and a summary of open work in its prompt (Board API); - a versioned requirements spec: every requirement records who proposed it, who — a human, always — accepted or rejected it, an immutable revision history, and typed evidence linking it to code, tests and runs, with a coverage matrix and a budgeted "context for this task" the agent can ask for (Requirements API);
- a knowledge neighbourhood that joins requirements, decisions, symbols, tests and runs into one typed graph with
declared/located/verifiedrelations and an honeststaleflag, plus per-turn context receipts that say which files actually fed an answer (Knowledge API).
Attention answers "what needs me now?" across every conversation, run and workflow along four axes — lifecycle, cause of waiting, connection health and next action — so a pending approval, a GPU queue and a dropped connection are one list, not three tabs. Attention API.
Second brain: a markdown vault Faustus creates and owns for you — no third-party note app, no separate account — under its own data folder, plain files with [[wiki links]] any external markdown editor can also open. Memories, personal notes and typed entities (people, places, tools, projects) are mirrored into editable notes; editing a note's text corrects the underlying memory, and deleting one silences it (suppressed, not erased) rather than forgetting it — reversible from a trash folder. A deterministic parser reads temporal markers ("since March 2025", "until June", "no longer") so a fact carries a validity window, and a newer fact of the same kind (works at / lives in) closes the older one's window instead of both standing as true at once; a background pass (rule-based, plus an optional local-model pass that only keeps what the source text actually says) extracts entities and their relations, and can write short cited summaries when the utility model is idle. The /brain screen ("Cerebro") gives it an explorer, a reading and editing view, an entity panel with relations now vs. history, and a force-directed graph of the whole vault or the neighbourhood around one note — no third-party library. The agent gets a brain tool (search, read, write, append, entity, timeline, neighbours, daily note), a matching MCP server, and a Context Engine source that surfaces entity cards and matching notes the same way learned memory does. Brain API.
| System | Purpose | Implementation |
|---|---|---|
| Project Context Links | Bind chats and reusable sources to stable projects; add and resolve context by reference. | project_context |
| Context Engine | Retrieve, rank, budget and explain the context assembled for a turn. | context_engine |
| Side threads & context wires | Branch a conversation from a passage, wire references, documents and notes explicitly, replay stale answers on request, condense by hand. | side_threads.py, condense.py |
| Model Router | Choose a local or remote model per turn from calibration, measured speed and history; never escalates to a paid route without an explicit allowance; explains the fit of every candidate. | model_router.py, Router API |
| Provider policy & admission | Local-only and subscription-vs-API decisions made once and enforced on every outbound call; pooled admission for GPU, CPU-heavy and foreground work. | provider_policy.py, resource_admission.py |
| Agent Profiles & Completion Modes | Reusable specialist profiles and task-dependent completion policies, within existing permissions; a lint that catches cycles and unreachable roles. | agent_profiles, agent_profile_lint.py |
| Strategy & recipes | An observable per-turn strategy that escalates only on observed failure, and reusable recipes built from real runs. | strategy_policy.py, recipes.py |
| Requirements | A versioned, human-accepted spec with typed evidence and coverage. | requirements |
| Second brain | A self-owned markdown vault of notes and typed entities with time-windowed relations, two-way synced with the filesystem, plus a graph view. | brain, Brain API |
| Typed decisions | Closed questions answered from one prefill by reading the next-token probabilities of the allowed answers; advisory, budgeted, never loads a model. | typed_decision.py, API |
| Project Board | Typed issues, kanban, commit-closing links and agent tools. | project_board.py |
| Git panel | Repositories, identities, GitHub, branches and a per-repository policy the agent obeys. | git_panel.py |
| Teach Mode | Capture demonstrations as reusable procedures, with review and execution controls. | teach mode routes |
| Immune System | Record incidents, evidence and corrective rules for recurring failures. | immune_system |
| Branching Futures & Alternatives | Explore alternative approaches in isolated branches, worktrees or document versions before choosing one. | branching_futures, alternatives.py |
| Council | Organize multi-model discussion, critique, decisions and controlled execution. | council |
| Workflows | Durable graphs with structural simulation, preflight, cost estimates with separate counts for activations, model calls and external operations, plan comparison and a canvas. | workflows, workflow_cost_estimate.py |
| Attention | One list of what needs a person, across everything that is running. | attention.py |
| Desktop semantics | Accessibility-tree desktop control with explicit channel choice and evidence. | desktop_semantics |
| State Mirror | Keep timestamped observations with freshness and provenance; verify and restore materialized state from its committed journal. | Recovery |
| Universal Delta Engine | Compare intended and observed changes across supported domains. | delta_engine |
| Greedy Completion Engine | Discover and assess useful follow-up work according to the chosen mode, scope and budget. | completion_engine |
| Jarvis voice | Voice interaction in English and Spanish, spoken replies and a reactive sphere. | voice guide |
For implementation details, see FAUSTUS.md. Current verification work is tracked in PENDIENTES.md.
- Mark attached images as subject/character, style or composition references. The selected roles become visible guidance in the sent message; they do not guarantee pixel-level conditioning. Gallery images can start a new reference chat while retaining the link to their original conversation.
- Open an attached image's thumbnail in the full editor, including masks and inpainting, without losing the chat draft. Attach result to chat saves the layer/mask draft and returns a PNG copy without sending a message. Inpainting requires a configured compatible image service.
- Plan and run approved ComfyUI recipes for images, reference editing and short video. Inspect required models before queueing work.
- The chat's Media recipe picker exposes installed recipes and their inputs, checks engine requirements without queueing a job, and adds an editable request to the draft. Reference-edit recipes support variations with strength and seed controls; engine-side image names are distinguished from chat attachments.
- With multiple configured engines, select by availability, queue and capacity, retaining the reason for the choice.
- Preserve recipe, version, seed, model licence, engine job and input digest with generated artifacts.
- Collect submitted renders in the server even with no chat open. Interrupted downloads remain retryable; completed outputs appear in Activity.
- Inspect image, audio and video properties before deciding how to process them.
- Convert and resize PNG/JPEG/WebP images and extract WAV/MP3 audio with scoped media tools, progress and cancellation.
- Download outputs through owner-scoped artifact links. Identical bytes can be shared physically without merging ownership or provenance.
- Expand File provenance beside Activity downloads to inspect size, type, SHA-256, partial/complete status and originating run, project or conversation.
ComfyUI is a separate service; model weights, custom nodes and their licences are not bundled. Use media recipes and workers documentation to configure the engines.
- Searches the web on its own for anything time-sensitive — sports results, news, prices, software releases, who currently holds a role, weather, schedules — instead of claiming it has no live access or asking permission first; a lightweight bilingual (Spanish/English) detector adds the web tools to the turn and nudges the model to search before answering. Sources read during a turn show up as favicons in the collapsible activity rail and next to each citation, served same-origin through a cached, SSRF-guarded favicon proxy. Freshness battery.
- Explainable web ranking — every search result carries a score and the reasons behind it: a bounded boost when several engines agree on a result, and a demotion (never a drop) for results sharing no content term with the query, shop-like results on a short non-purchase query, or stale results on a time-sensitive one.
- Source type and extraction quality on every web result and fetched page — official, docs, academic, reference, forum, shop and more from a URL heuristic, plus flags for thin, boilerplate, paywalled or JavaScript-required pages that feed the ranking nudge above.
- Research with source tracking, citation checks and report export.
- Deep Research thinks at the strongest level each model has, with a Reasoning selector on the Research screen (Auto, Maximum … Off) and a per-mode default in Settings; page reading stays fast unless raised.
- A research report as a podcast. A finished Deep Research report becomes a two-voice dialogue in the report's language — script written from the report alone, long reports condensed first, spoken by two local Piper voices and joined into one MP3 or WAV — with a player and transcript in the Research screen, the Library and the visual report, or on request through the
research_podcasttool (API). - Perspective-guided research planning (opt-in): before searching, a short set of distinct perspectives on the topic (practitioner, sceptic, regulator...) each contribute a few questions, merged with the usual subquestions and capped to the normal query budget.
- Blind review of a finished research report (opt-in): a second model scores the report from the question, the stripped report and its cited sources only — never the writer's plan or identity — and records unsupported claims and the gap with the writer's own evidence grade.
- Doc-claims checker: extracts path, symbol, settings-key and API-route claims from Markdown docs, grounds them against the real workspace, and flags broken references and sections whose cited code drifted after the doc was written.
- Project concepts: a persistent, per-project graph of architecture concepts (feature/module/pattern/config/decision/component) the agent writes itself as it learns a codebase, queried semantically (
concepts_understand) so understanding survives across sessions — with typed relations, staleness detection against the real workspace, optional automatic context injection, and a force-directed graph view in Studio (Context → Concepts). - Retain labelled original-source excerpts when extraction fails, preserve the previous report if final generation is empty, and pass bounded evidence alongside summaries. Shared scheduled lookups recover from cancellation without stranding other tasks. Diogenes adaptations.
- Write and edit documents; export supported content to Markdown, text, HTML, PDF, DOCX or JSON.
- Search imported ChatGPT, Claude, LM Studio and Faustus history alongside local knowledge.
- Organize notes, tasks and calendars; connect email with IMAP/SMTP and calendars through CalDAV.
- Compare models, run expert reviews and inspect provenance and learned rules. Memory flags it when a new learned rule contradicts an older one — the older item is deprioritised and marked contradicted, and you resolve it (keep newer / keep older / keep both) from a Conflicts section on the Memory screen; nothing is ever silently dropped.
- Grounding lint: every active memory item with cited evidence is checked, deterministically, for specifics its evidence does not actually contain — numbers, dates, quoted strings and proper-noun-ish names are extracted and matched against the excerpt(s) the item cites. Flagged items and their unsupported details show in a Grounding section next to Conflicts on the Memory screen; items with no evidence at all are counted separately and never accused.
- Monitor local model memory, GPU placement, fit estimates, downloads and service health through Cookbook. An idle-runner report tells a leftover process apart from an engine you are actually using: a runner listening on a port one of your configured endpoints is served on is owned, whatever launched it, so it is never reported as abandoned and never offered for release.
- Launch local servers with a verified configuration: model architecture (dense/MoE, multi-token prediction) is read from metadata rather than the model name, each launch option is checked against a per-implementation capability manifest before the command is built, and a launch receipt shows what was requested, what was applied and what the server confirmed. Every reply carries measured phases (queue, load, prefill, generation, tools) with their source under "Why did it take this long?" — a phase the engine does not report is shown as absent, never as zero.
- Managed llama.cpp engines start themselves on the first chat call and unload when idle (
engine_autostart,engine_idle_ttl_minutes), so a stopped engine never has to be started by hand and an idle one stops holding the GPU. Engines that support it can turn on MTP speculative decoding (detected from the GGUF itself, never guessed from the file name), with a warning when the server's default parallel slots would cancel most of the speed gain. A model that ships its own vision projector (an Ollama store keeps it as a separate layer; a folder keeps anmmproj*.ggufbeside the weights) is started with it automatically, so the main model reads images, screenshots and PDF pages itself, on the GPU, instead of handing them to a slower separate vision model; Settings shows a Vision tag and a toggle to switch it off. - Benchmark a running configuration on your own machine from Cookbook → Optimize for my machine: explicit plan and budget before anything runs, one model at a time, deterministic quality checks (no LLM judge), and a comparator that only marks a profile as recommended when speed improves beyond the observed noise without losing quality.
Compose triggers, conditions, waits, human approvals, media steps and stored reports. Server-side continuation advances started workflows and wakes timed steps. Attempts have leases and conditional writes so late results do not overwrite a cancellation or a newer attempt.
Two more wait steps poll instead of sleeping to a fixed instant: wait_until re-checks the same condition language as condition on an interval until it is true, with a bounded timeout that either fails the node or completes it onto a declared timeout branch; wait_for_event watches an event source (a file_change scanner ships by default, and more can be wired in) and only completes after a settle window of quiet since the last matching event, with its own overall timeout and a capped list of collected events. Both persist their deadline and progress in the paused node's own state, so a process restart mid-wait resumes exactly where it left off, and a run stuck past its deadline after a crash is found and resolved by the same periodic continuation that already wakes a plain wait.
Generated reports can resolve text from the run's inputs or previous results and save it as an owned artifact. Workflow outputs inherit the verified project and conversation scope. Activity shows dependencies, reasons for waiting and links to output files.
Project workflows can run declared Python, JavaScript and Bash skill scripts in Docker, with a bounded source snapshot, permissions bound to the exact code and command, and collected output files. Script skill setup describes the contract and prerequisites. Process output is drained continuously and retained as bounded tails so verbose scripts cannot exhaust host memory.
Cancelling a running script workflow also stops its container. The worker checks the exact live attempt and lease, and cancellation during container setup prevents the script from starting. Partial external effects remain explicit and are not automatically retried.
Script credentials are encrypted per owner and bound explicitly by name and revision to approvals. Rotation invalidates pending execution; workflows never inherit unrelated provider keys. Human-only credential endpoints and configuration are described in the script skill guide.
A skill sleep pass (src/skills_runtime/sleep_optimize.py, run on demand from the skill's "Proposals" tab or via POST /api/skills/{id}/sleep-pass) mines recent sessions for turns where a skill was consulted (manage_skills activity recorded in that turn's tool_events), classifies the user's next reply with deterministic en/es phrase tables (negative: "no funciona", "still broken", undo/retry signals; positive: "perfecto", "works now", "gracias") plus any tool errors in that turn, and asks a local model for ONE proposed SKILL.md revision. Nothing is ever applied automatically: the proposal is validated (frontmatter/name preserved, size bounded, no removed Pitfalls/Verification section, a security-scan pass) and stored pending, and approving it goes through the same skill-governance promotion gate plus a version history that can be rolled back byte-for-byte.
Project objectives accept typed updates from agents without losing simultaneous changes. Human edits are protected against stale agent updates, including edits within the same second; damaged state files are preserved during recovery.
The email delivery step sends text with optional HTML, CC/BCC and bounded workflow-content attachments through an owned SMTP account. Approval binds every recipient and the exact content, including attachment hashes. Approvals are consumed once at execution, approved waits resume automatically, and an uncertain external effect is not retried automatically. SMTP acceptance is recorded separately from inbox delivery.
Workflow nodes that perform external actions still need the appropriate configured capability and authorization. Cancelling stops subsequent work; it cannot undo an external action that already occurred.
The Workflows screen draws a definition as a layered graph with three explicit modes — design, structural simulation, authorized real execution — the same definition throughout. Simulation walks the graph round by round without side effects, leaves undecided conditions undecided rather than guessed, and never bypasses an AND dependency because a second path happened to be clean. Definitions import from this module's canonical export or an aigraphstudio-shaped graph, export back, and deep-link to a run.
The design_canvas tool makes the model declare a design before it touches a
file: requirements, entities, the approach with the alternative it rejected and
why, the files it will change, operations, norms and safeguards. The result is
stored in the project concept graph as a decision whose refs are those files, so
when one of them disappears the staleness check finds the design that no longer
matches. It is written by the model the turn is already running on, not by
whatever the global default happens to be.
At the other end of the scale, a turn that is plainly small talk is answered without the model’s reasoning and without the toolset attached. Measured on a local 27B with a cold prompt cache: 7.5 s carrying the tools against 2.2 s without them. A conversation that has already called a tool keeps everything, whatever its last message says.
Memory refuses to file a snapshot of the workspace as a fact about you. A count of the files in a folder stops being true the moment you add one, and a stored fact that contradicts reality is worse than no fact at all.
Typed decisions. Where a keyword rule is not sure, Faustus can ask a closed question instead of guessing: the options are labelled with single letters, the already-loaded utility model reads the text once, and the probabilities it puts on each letter for its very next token are the answer, with a confidence and a "did it even want to answer this" mass, and no reasoning generated. Several questions about the same text share the prompt prefix, so the server's prompt cache pays for the text once. It never loads a model, it has a hard latency budget, and it is advisory only: the rule decides whenever it is confident and whenever the model is unavailable or unsure. Today it settles the unsure cases of "does this question need a web search?", gives a type to second-brain entities left as "other", and suggests (never resolves) memory contradictions the fixed conflict rules cannot see. An eval compares rule, decision and combined accuracy with calibration and cache timings. Typed decision API, eval.
Three offline-checkable walkthroughs — a document with real review, a supervised agent end to end, semantic desktop control — are described in docs/showcase.md, each citing the files that implement it and the test that covers it, plus a small sample project under examples/showcase/. The adaptation backlog behind these features, audited row by row against the real code rather than asserted, lives in docs/adaptations/ (baseline classification and per-feature decision records).
Jarvis provides a voice session with English/Spanish recognition, spoken replies, interruption controls and a reactive visual sphere. Configure the available transcription and speech services in the app; browser microphone permission is required. Installed voices and local speech engines determine available languages and playback.
Speech providers: browser (Web Speech API), system (installed Windows voices, offline), local (Kokoro TTS / faster-whisper STT), Piper (fully local, MIT-licensed neural TTS, including Spanish voices — install the engine and download a voice from Settings → Voice, no built-in model bundled; synthesis always runs in an isolated child process, never inside the server), command (run your own local TTS/STT executable via a placeholder template), or a configured API endpoint. See docs/ui/voice.md.
Voice input enters the same conversation and tool-permission flow as typed input. A voice session is not blanket authorization for filesystem, desktop or external actions.
Every transcript — voice input and meeting notes alike — passes through a deterministic cleanup pass (src/stt_cleanup.py) before it reaches the conversation or the notes: repeated segments collapse to one, known silence/hallucination phrases (English/Spanish) and bare music markers are dropped, and an in-segment word/phrase loop ("the the the the…") is collapsed, with timestamps kept coherent throughout.
Windows desktop app: a global "dictate anywhere" hotkey (off by default; Settings → Voice) transcribes into whatever app has focus — email, a terminal, another program — not just Studio's own composer. It captures the target window before recording, then delivers the text by simulated paste (clipboard is saved and restored afterward) or direct keystrokes, for apps that block paste (src/dictation_paste.py, routes/dictation_routes.py).
| Area | Code |
|---|---|
| HTTP application and persistence | app.py, routes, core |
| Studio interface and state | studio/src |
| Model transport and official-client bridge | llm_core.py, cli_model.py, runner_billing.py |
| Worker dispatch and process supervision | dispatch.py, external_worker.py |
| Durable workflows | workflows |
| Media engines and continuation | media_runs.py, media_scheduler.py, media_backends |
| Artifacts, identity and migration | artifact_store.py, artifact_identity.py, artifact_migration.py |
| Regression and interface checks | tests, studio/checks |
The artifact store separates content-addressed bytes from owned output occurrences. Additive migration preserves historical identifiers and metadata; removal markers prevent deleted occurrences from being recreated by migration.
Internal names such as odysseus, ODYSSEUS_*, existing API paths and storage keys are retained for compatibility. The product name is Faustus.
Use the project's configured Python environment and install the development dependencies described in tests/README.md.
python -m pytest
npm ci
npx tsc --noEmit
npm run build
python -m src.doctorThe suite includes owner isolation, persistence, concurrency, cancellation, migration, HTTP integration and headless interface checks. Hardware engines and account integrations also need tests in their configured environment; an HTTP fixture does not demonstrate model quality or a provider's account access.
Measured on 12 September 2026: 16,993 tests pass on Linux (-m "not slow", about ten minutes on two workers) and the same tree passes on Windows with Docker Desktop running the container-backed cases; 295 modules under src/, 116 route modules, 149 Studio screens, 21 API documents under docs/api/, and 76 dated sections in FAUSTUS.md recording what each change was for and how it was verified. Interface checks run the real TypeScript through esbuild under Node rather than re-implementing it in Python.
python scripts/acceptance_run.py runs the 36 parity acceptance cases (A01-A36) and writes one evidence row per case; python scripts/benchmark_matrix.py runs a case × system × model benchmark matrix that reports a cell as MISSING rather than shrinking the denominator, and an unpriceable cost as "unknown", never 0.
Current verification results and remaining checks are listed in PENDIENTES.md.
A process that ends without shutting down leaves a trace: every start writes data/logs/running.json (pid and start time) and removes it on a clean shutdown, so the next start logs a [lifecycle] warning when the previous process was killed or crashed, and native faults write their thread stacks to data/logs/crash.log.
Activity, agents and automations
Follow tasks and approvals in Activity.
Configure workers, runners and their verification settings.
Inspect and control recurring work.
Second brain
/brain ("Cerebro" in Tools) is a three-pane markdown vault: a file explorer on the left (folders, search, tags, trash), the current note in the centre (a reading view with clickable [[wiki links]] — an unresolved one creates the note on click — and an editing view with autosave and [[ autocomplete), and on the right its backlinks, outgoing links, tags and, for an entity note, its relations now vs. its history with an "as of" date picker. A toggle switches to a force-directed graph of the whole vault or the local neighbourhood around one note.
Context packet summaries include a memory-selection receipt: included entries, omissions and reasons, character usage and degradation. It describes the final Context Engine packet without querying memory again or adding a second selection pass. Items the live packet leaves out for budget stay recoverable: the packet lists them as [ctx:<id>] lines and the context_recall tool (also on the context MCP server) returns their full text with provenance. scripts/bench_context_engine.py compares the legacy context blocks with the compiled packet offline (tokens, sections, latency, recall). With the live engine switched on, both agent and plain chat turns receive the packet; the classic saved-memory and document blocks stay on standby and come back only when no packet is delivered, so nothing is shown twice, and recalling an item the current turn's packet offered does not raise an approval card.
Keep AUTH_ENABLED=true for any network-accessible deployment.
Keep LOCALHOST_BYPASS=false outside local development.
Keep authentication enabled. Do not expose unauthenticated model, ComfyUI or internal service ports publicly. Keep credentials and private data/ files out of Git.
Bitwarden sessions are encrypted at rest and expire after one hour, shared by settings and agent tools. Old plaintext sessions are discarded on access and require unlocking again. Protect data/.app_key: encryption does not protect against a compromised host.
Approve tools and project instructions deliberately. Per-agent restrictions, owned sources, approval gates, sandbox settings and process supervision are separate controls. When a required sandbox is unavailable, the configured sandbox path must not silently run the command on the host.
A third-party MCP server or imported skill gets a static security pre-scan (no network, no LLM) before it can be trusted: remote-script execution, obfuscated payloads, credential access, exfiltration, persistence, destructive commands, dynamic code, open network listeners, and prompt-injection markers in tool descriptions or skill text. A critical finding quarantines it — same gate a permission escalation already uses — and approving requires an explicit override, shown next to the finding count, never a silent block.
The tool descriptions an MCP server advertises are scanned the moment it connects (and on every reconnect), not only at install time, when there are none yet. A scheduled shell task (run_script, run_local, ssh_command) is judged by the destructive-command guard exactly as the same line typed into bash would be, on create and on edit. The agent's shells never receive Faustus's own secrets (the internal token, the decrypted embedding key), the tmux path included. A remote picture in a reply waits for a click instead of loading on sight, because a URL written by an injected model can carry data out; images from the app itself and hosts you already allowed in the tab load at once.
A repeatable prompt-injection probe battery (python -m src.security_probes) checks the END-TO-END defences rather than a single function: 12 data-driven probes cover every untrusted vector (fetched pages, documents, email bodies, tool results, MCP tool descriptions, workspace files) and payload style (direct override, forged system messages, hidden HTML comments, zero-width/Unicode-tag smuggling, markdown exfiltration URLs, role-play jailbreaks, "call this tool" instructions, settings-disabling instructions, delayed multi-turn triggers, and forged sandbox-marker breakouts). A deterministic mode runs in CI with no model — a scripted "always-compromised" model that tries the exact malicious call the instant it has seen the injected content — and a live mode drives the same probes through a real local model and the real agent loop; results and a markdown summary are saved under DATA_DIR/security_probes/ for regression tracking.
A trajectory gate (src/trajectory_gate.py, GET/POST /api/agent-runs/{run_id}/gate) checks a recorded agent run against declarative, CI-style assertions — max error rate, step/tool-call/token/duration ceilings, forbidden/required tools, ordering rules ("write_file needs a prior read_file", "tests must run after the last edit"), no repeated identical calls, a final answer required — so a regression in agent behaviour is caught mechanically instead of by eye. python -m src.trajectory_gate --run <id> --spec spec.json (or --recent 20 to aggregate a pass rate per check) runs in CI with a non-zero exit code on failure; a compact "Gate a run" panel in Activity shows the same checks for any run id.
Doubt review (src/doubt_review.py, off by default: agent_doubt_review) asks a fresh-context, tool-less reviewer — no conversation history, only the task, a HIGH-risk file's code_graph_risk summary and the proposed diff — to find reasons a non-trivial edit is wrong before it lands, biased toward refutation rather than approval. Advisory by default: the edit applies and the verdict is appended to the tool result as "Second look..."; agent_doubt_review_block can instead refuse the write on a "concerns" verdict, reversible per call with confirm_risky: true. Cheap: a per-turn cache keeps the risk score and the review to one call per file/diff, and agent_doubt_review_model targets a small local model instead of spending the turn's main model on every edit.
See the threat model, security policy and setup security notes.
Faustus builds on Odysseus. See ACKNOWLEDGMENTS.md for additional credits, CONTRIBUTING.md for contribution guidance and LICENSE for AGPL-3.0-or-later.







