bvandeusen 9383f10dab ci: build only on dev push and release tag, not on main merge
Merging to main now runs CI checks only. The release tag (v*) is the
sole trigger for a production :latest image, eliminating the redundant
double-build that previously occurred on every PR merge + tag pair.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 16:13:18 -04:00

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 (todoin_progressdone), 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.

Dark and light themes — Defaults to dark (slate-indigo palette). One-click toggle in the header.

Keyboard shortcutsg+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

  1. Clone the repository:

    git clone https://github.com/your-username/fabledassistant.git
    cd fabledassistant
    
  2. Start the application:

    docker compose up --build
    
  3. Open http://localhost:5000 in your browser.

  4. Register the first user account — this account becomes the admin.

  5. Go to Settings → General to pull an LLM model (llama3.2 at 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/login and /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 with python -c "import secrets; print(secrets.token_hex(32))" or use Docker secrets via SECRET_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.450.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.

S
Description
No description provided
Readme 14 MiB
v26.06.03 Latest
2026-06-03 12:51:04 -04:00
Languages
Python 53.7%
Vue 38.1%
TypeScript 5.8%
CSS 1.4%
Shell 0.8%