- GET/POST/DELETE /api/api-keys blueprint registered - GET /api/search?q=&content_type=&limit= semantic search endpoint - create_conversation gains conversation_type param (default "chat") - cleanup_old_conversations excludes mcp type from retention sweep - POST /api/chat/conversations accepts conversation_type body field Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fabled Assistant
A self-hosted second brain and project management application with integrated LLM capabilities. Write, organise, and act on your notes and tasks with the help of a local AI assistant — all running on your own hardware.
What It Does
Notes with inline formatting — Write in Markdown with a live-preview editor (Tiptap/ProseMirror). Headings, bold, italic, lists, code blocks, and task checklists render inline. A slash-command menu (/) inserts common blocks without leaving the keyboard.
Task tracking — Notes convert freely to tasks (and back). Tasks carry status (todo → in_progress → done), priority, due date, sub-tasks, milestone assignment, and work logs with time tracking.
Projects and milestones — Group related notes and tasks into projects. Milestones give projects a timeline and show completion progress. A kanban-style project view groups tasks by milestone.
Project Workspace — /workspace/:projectId opens a three-panel environment (tasks / chat / notes) locked to a project. The AI assistant creates and updates content directly in the workspace; new notes auto-load in the editor and the task list refreshes automatically.
Wikilinks and backlinks — Link notes with [[Title]] syntax. Click a wikilink to navigate to (or create) the referenced note. Each note shows what links to it. The editor suggests existing note titles as candidate links.
Tag organisation — Tags are first-class columns (stored as a PostgreSQL array, not extracted from body text). Tag autocomplete, tag-based filtering, and a force-directed graph view show how notes cluster.
Knowledge graph — /graph renders all notes, tasks, and tags as a D3 force-directed graph. Tag nodes cluster notes that share tags; project hub nodes (invisible) attract project members. Click any node to open a slide-in peek panel.
AI chat — Full conversation history with SSE streaming. The assistant automatically retrieves semantically relevant notes (RAG) and injects them as context. Attach specific notes by paperclip for focused discussions. Useful replies can be saved directly as notes.
AI writing assistant — Select a passage in the editor, give an instruction ("make this more concise", "add examples"), and stream a diff-style suggestion you can accept or reject.
Web research — The assistant can search the web (SearXNG), fetch pages, and synthesise findings. Research results are saved as notes. A lightweight search_web tool answers quick questions inline.
Collaboration and sharing — Share any project or note with other users or groups. Three permission levels: viewer, editor, admin. A "Shared with me" page lists all incoming shares. In-app notifications (with push) alert recipients when items are shared or when they are added to a group.
Groups — Admins can create platform-wide groups, assign users roles (member / owner), and share resources with the group in one action.
In-app notifications — A bell icon in the nav shows unread notification count with a 60-second polling interval. Clicking a notification navigates to the relevant resource and marks it read.
CalDAV calendar — Connect an external CalDAV server (Nextcloud, Radicale, etc.) and have the assistant create, list, search, update, and delete calendar events via natural language.
Push notifications — Web Push (VAPID) notifies you when AI generation completes, even in another tab. Configurable per-user from the Notifications settings tab.
PWA — Installable as a desktop or mobile app. Service worker caches the shell; push is handled by public/sw.js.
Data export and backup — Export your data as a Markdown ZIP (with YAML frontmatter) or a JSON array from the Data settings tab. Admins can export/restore full application backups (version 2 includes projects, milestones, task logs, AI drafts, note versions, push subscriptions) with proper ID remapping on restore.
OAuth / OIDC login — Supports PKCE-based OIDC in addition to local username/password auth. LOCAL_AUTH_ENABLED can disable local login entirely for SSO-only deployments.
Multi-user with isolation — All data is scoped to the owning user. Access to shared resources is resolved through services/access.py using the permission rank system. The first registered user becomes admin.
Daily Briefing — A scheduled, dialogue-based morning briefing accessible at /briefing. The assistant compiles your tasks, calendar events, projects, weather forecast (Open-Meteo), and RSS feed digest at 4am, then checks in at 8am, 12pm, and 4pm. You can reply interactively — the briefing is a real conversation, not a widget. The assistant learns your preferences over time via a profile note it maintains. Configure locations, work schedule, RSS feeds, and active slots from Settings → Briefing.
Dark and light themes — Defaults to dark (slate-indigo palette). One-click toggle in the header.
Keyboard shortcuts — g+h/n/t/p/c/g navigate sections; n new note; t new task; ? shows the shortcut panel. Full list available in-app.
Getting Started
Prerequisites
- Docker and Docker Compose
- A machine with enough RAM to run an LLM (8 GB+ recommended for smaller models like
llama3.2)
Quick Start
-
Clone the repository:
git clone https://github.com/your-username/fabledassistant.git cd fabledassistant -
Start the application:
docker compose up --build -
Open
http://localhost:5000in your browser. -
Register the first user account — this account becomes the admin.
-
Go to Settings → General to pull an LLM model (
llama3.2at 2 GB is a good starting point).
Day-to-Day Usage
- Create a note from the Notes page. Use Markdown — formatting renders live.
- Link notes by typing
[[for a wikilink autocomplete dropdown. - Tag your notes — add tags in the sidebar tag input; autocomplete suggests existing tags.
- Use the AI writing assistant — select text in the editor, write an instruction, stream a suggestion.
- Chat with the AI — the assistant finds relevant notes automatically. Attach specific notes for focused context.
- Convert notes ↔ tasks from the viewer toolbar.
- Open a project workspace from the project page — chat, tasks, and note editor in one view.
- Share a project or note — click Share in the project/note/task viewer toolbar, search for users or pick a group.
- Manage groups (admins) — Settings → Groups tab.
- Backup your data — Settings → Data tab for personal export; admin section for full application backup.
Configuration
Configuration is via environment variables. See docker-compose.yml for defaults.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
postgresql+asyncpg://... |
PostgreSQL connection string |
SECRET_KEY |
(required) | Session signing key |
OLLAMA_BASE_URL |
http://ollama:11434 |
Ollama API endpoint |
DEFAULT_MODEL |
llama3.1 |
LLM model to warm on startup |
EMBEDDING_MODEL |
nomic-embed-text |
Model used for semantic search / RAG |
SECURE_COOKIES |
false |
Set true behind TLS |
LOG_LEVEL |
INFO |
Logging verbosity |
OIDC_ISSUER |
— | OIDC issuer URL for SSO login |
OIDC_CLIENT_ID |
— | OIDC client ID |
OIDC_CLIENT_SECRET |
— | OIDC client secret |
LOCAL_AUTH_ENABLED |
true |
Set false to disable local login |
SEARXNG_URL |
— | SearXNG base URL for web search |
BASE_URL |
— | Public URL (used in email links and OIDC redirect) |
For production, docker-compose.prod.yml supports Docker secrets (SECRET_KEY_FILE, DATABASE_URL_FILE) and includes network isolation, health checks, and resource limits.
Production Deployment
Reverse Proxy (Required)
Fabled Assistant does not handle SSL/TLS. Run it behind a reverse proxy:
- Nginx, Traefik, or Caddy in front of the app container
- Terminate TLS at the proxy; forward to port 5000
- Do not expose port 5000 directly to the internet
- Rate-limit auth endpoints — recommended: ≤5 req/min per IP on
/api/auth/loginand/api/auth/register - Set CSP headers — recommended:
default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'
Security Checklist
- Strong
SECRET_KEY— generate withpython -c "import secrets; print(secrets.token_hex(32))"or use Docker secrets viaSECRET_KEY_FILE - Registration — auto-closes after the first user (admin). Re-enable from Settings → Users or send invite links.
- Session invalidation — changing or resetting a password bumps
session_version, evicting all other active sessions. - Keep Ollama on an internal network — both compose files keep it off the host network.
Technical Overview
Stack
| Layer | Technology |
|---|---|
| Frontend | Vue 3, TypeScript, Vite, Pinia, Vue Router |
| Editor | Tiptap (ProseMirror) with custom slash-command extension |
| Backend | Python 3.12, Quart (async ASGI) |
| Database | PostgreSQL 16, SQLAlchemy 2.0 async, Alembic |
| LLM | Ollama (local) — any OpenAI-compatible API |
| Search | SearXNG (optional, self-hosted) |
| Push | Web Push / VAPID (pywebpush 2.x) |
| Deployment | Docker Compose |
Architecture
The app runs as a single container serving the Vue SPA and REST API (/api/). The frontend is built by Vite during the Docker image build and served as static files by Quart.
LLM interactions stream via Server-Sent Events (SSE). Chat generation runs in background asyncio tasks with an in-memory event buffer supporting client reconnection without data loss. An abort mechanism lets users cancel in-flight generations.
Semantic search (RAG) uses nomic-embed-text via Ollama to generate embeddings stored in PostgreSQL. Notes above 0.60 cosine similarity are auto-injected into the system prompt; notes between 0.45–0.60 appear as sidebar suggestions.
Permission resolution is centralised in services/access.py. All resource access goes through get_project_permission / get_note_permission, which check ownership, direct shares, group membership shares, and note→project inheritance in order, returning the highest applicable permission.
Database
PostgreSQL with SQLAlchemy 2.0 async. Tasks are notes with non-null status (unified Note model). Tags are stored as a ARRAY[text] column. Migrations run automatically on startup via Alembic.
Project Structure
fabledassistant/
├── docker-compose.yml # Development stack
├── docker-compose.prod.yml # Production stack (Docker Swarm)
├── Dockerfile # Multi-stage build (Node → Python)
├── alembic/ # Database migrations
├── src/fabledassistant/
│ ├── app.py # Quart app factory + blueprint registration
│ ├── models/ # SQLAlchemy models
│ ├── routes/ # API blueprints
│ ├── services/ # Business logic (access, sharing, groups, …)
│ └── static/ # Built frontend (generated at build time)
└── frontend/
└── src/
├── views/ # Page-level components
├── components/ # Reusable UI components
├── composables/ # Vue composables (autosave, shortcuts, …)
├── stores/ # Pinia stores (auth, chat, notes, notifications, …)
└── api/ # Typed API client (client.ts)
Development
All development is done via Docker. No local dependency installation required.
# Start the dev stack (hot-reload not included — rebuild on changes)
docker compose up --build
# Reset the database
docker compose down -v && docker compose up --build
# Lint, format, typecheck, test (runs inside Docker via Makefile)
make check
CI runs on Forgejo Actions with a custom runner image (py3.12-node22) that has Python 3.12 and Node 22 pre-installed. Pushes to dev build a :dev image; merges to main build :latest.
License
This project is privately maintained.