Organize papers and knowledge, in one place. Self-hosted, multi-user, Logseq-inspired: read and annotate PDFs in your browser, keep the notes as a nested outliner, and link everything together.
Install · User guide · Website · Releases
Every picture below is clickable and opens the matching part of the user guide.
Your library lives on your server and opens from any browser: the office desktop, the iPad (with the Pencil), your phone. Reading position, open tabs and zoom follow your account from device to device.
- Offline copy — keep a full copy of a workspace on your laptop with the desktop app (one click on the workspace's clone chip) or on any second Gamma. Read and write it on the train; it syncs itself when the connection returns — edits merge block by block, and the rare conflict is shown on its block with both versions rather than lost.
- Install it — Safari → Add to Home Screen on the iPad, Install Gamma in Chrome or Edge, or the desktop app for Windows, macOS and Linux.
→ Guide: Offline copies · Install as an app
Open a paper by pasting any link — arXiv, DOI, or a publisher page; Gamma finds the PDF and falls back to a legal open-access copy when the DOI is paywalled — or drag the file in. Then:
- Highlight — select text or drag a box around a figure, pick a color, add a comment. Each highlight becomes a block in your notes. Highlights already saved in the file by Acrobat, Preview or SumatraPDF come in as blocks too.
- Draw — with a stylus or the mouse: circle a claim, sketch an arrow, highlight freely. Lasso strokes to move, resize, rotate or recolor them; erase whole strokes or part of one. Ink is a note block linked to its place on the page.
- Follow citations — references in the PDF are clickable; a global ← Back unwinds jumps across documents, and a cited arXiv/DOI paper is one click from your library.
→ Guide: Reading and highlighting · Draw with a pen · Links inside the PDF
Highlights and free notes are the same kind of block, so a paper's notes and a plain page are edited the same way:
- Outliner — Enter for a new block, Tab / Shift+Tab to nest, drag to reorder, one undo history for the whole page.
- Live preview, Obsidian-style — markdown,
$…$/$$…$$math, code fences, callouts and tables render in place while the block you're on stays raw. Math gets bracket-pair coloring,\commandautocomplete, and Tab hops between{}arguments. - Pictures and tables — paste a screenshot and drag its edge to size it; tables are edited cell by cell, never as raw markdown.
- Link and embed —
[[page]]mentions,![[block]]embeds that edit the source in place, backlinks, and a "/" menu for everything else.
→ Guide: Notes
- Chat with the open paper — ask about it, paste figures, dictate by voice, or attach the whole PDF so the model sees tables and plots. Answers cite pages; a click jumps the PDF to the passage. Use Anthropic or OpenAI models, or sign in with your ChatGPT subscription — no API key.
- Mention a paper — type
@to attach a library page; its text stays in context for follow-ups. - Put the agent to work — ask it to search your library, read papers, compare findings, rename pages or file them into folders. Expand each tool step to inspect what it did; it can never delete anything.
→ Guide: AI chat · The library agent
- Folders build themselves from the paths you use: drop a paper into
qc/neutral-atomand you get qc › neutral-atom; storage stays flat, so one paper can live in several folders. - Labels are flat tags for facets like an author or a keyword — one click to filter by.
- Metadata fills itself on open (arXiv → DOI → AI) and is editable; one click copies BibTeX or a slide-ready citation with real italics.
- Search everything —
Ctrl+Fsearches notes, highlights and the full text of every PDF at once; narrow with label and folder chips. Matching is forgiving: "3000" finds "3,000-qubit" across a line break.
→ Guide: Library and organization · Search · Metadata and citations
- Workspaces — keep separate personal libraries, or collaborate in a shared library created by a server administrator: owners manage members, editors change pages, viewers read.
- Share a page — send a link to an annotated paper; invite people with view or edit rights, or open it to anyone with the link.
- Edit together — changes and cursors appear live; edits to different blocks coexist, same-block edits merge.
→ Guide: Sharing a page · Workspaces
- Assistants — the Gamma plugin for Codex and Claude Code lets either assistant search and read your papers, notes and highlights, read-only, for a workspace you approve in the browser: "@Gamma, in the Rydberg arrays paper, how is the blockade radius measured?" Setup is one command copied from Settings → AI → Integrations; any other MCP client connects with the same URL.
- Gamma Connector — the browser extension (extension/) saves the paper you're reading in one click — PDF, metadata, folder, labels — from the arXiv / DOI / publisher tab, and clips links or selections into your notes. Its cookie button saves your publisher sign-in per journal, so the server can fetch that journal's PDFs on its own from then on.
- Import — Zotero libraries and Logseq exports with their annotations; Obsidian vaults, Notion exports and Markdown folders as notes. Export — annotated PDF, Markdown, an Obsidian vault, a Logseq graph, a Zotero library, or a Gamma zip another Gamma can merge.
→ Guide: Assistants: Codex and Claude Code · Gamma Connector · Import and export · Backups
Get the Windows app from the Microsoft Store, or download standalone installers from GitHub Releases.
- Desktop app (Windows installer, macOS dmg, Debian/Ubuntu deb) — a self-contained Gamma with local libraries on your disk, no Docker, Python or Node. It also opens any Gamma server you host (the NAS, a VPS) and keeps offline copies of its workspaces. Details: desktop/. Builds are not notarized: Windows SmartScreen → More info → Run anyway; macOS says Apple could not verify Gamma on first launch → System Settings → Privacy & Security → Open Anyway (once); Linux:
sudo apt install ./Gamma-<version>-linux-amd64.deb. Windows and Linux apps update themselves. - iPad, phone, any browser — open your server and install it from the browser; see Install as an app.
- Gamma Connector browser extension (
gamma-connector-<version>.zip, in its ownextension-v<version>release) — unzip, thenchrome://extensions→ Developer mode → Load unpacked. - Server — the Docker image below, built from
mainon every merge.
docker run -d --name gamma -p 9001:9001 -v gamma-data:/data ghcr.io/tim4431/gamma:latestOpen http://localhost:9001 and log in as admin — a fresh instance seeds the account itself and prints its password once to the log (docker logs gamma). No environment variables needed.
Copy the template (the real file is gitignored, so local tweaks never land in commits) and start:
cp docker-compose.yml.example docker-compose.yml
docker compose up -dOpen http://localhost:9001 and log in with the seeded admin password from docker logs gamma (printed once on first start). Accounts, notes and uploaded PDFs live under the container's /data volume and survive upgrades.
Backups: a workspace exports as one zip from Settings → Workspaces, snapshots live in Settings → Backups, and administrators snapshot the whole instance from Settings → Server (restore those with the server stopped: manage.py backups --restore) — see Backups and the backup internals. If you bind-mount /data to a host folder, set PUID/PGID to your user's ids (id -u / id -g) so the files belong to you instead of root.
Users are managed in the app: sign in with an admin account → Settings → Users (create/delete accounts, reset passwords, grant or revoke the admin privilege — admin is a flag, not a special name). The CLI equivalent still works:
docker exec gamma python manage.py create-user alice her-password
docker exec gamma python manage.py set-admin alice on
docker exec gamma python manage.py list-usersFor assistants (Codex, Claude Code) signing in to a remotely hosted Gamma, an administrator confirms the Public server URL once in Settings → Server; it applies immediately, without environment variables or a restart.
Run from source (development)
Requires Python 3.11+ and Node 18+.
Backend
cd backend
python -m venv venv && source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
python manage.py create-user admin yourpassword
python manage.py set-admin admin on # admin privilege → GUI user management
python manage.py setup # seeds the guest account
uvicorn app:app --host 127.0.0.1 --port 9001Frontend
cd frontend
npm install
npm run dev # :5173, proxies /api → :9001Frontend source is grouped by function (editor/, pdf/, settings/, and
others), with startup/session code in app/ and reused code in shared/.
See the frontend source map for file locations and
naming conventions.
Tests
For local changes, run tests for the affected modules and their direct consumers; see the test selection policy for targeted backend, frontend, and browser commands. The commands below run full suites, which also run in PR CI.
cd backend
pip install -r requirements-dev.txt
python -m pytest tests -qIn-process API tests against a throwaway data dir — auth, the block tree, metadata/BibTeX, PDF-annotation import, full-text search, sync, and export.
Frontend checks, from frontend/: npm test for module tests, npm run build
for the production bundle, and npm run e2e for the browser suite against an
isolated backend (requires backend dependencies and Playwright Chromium).
Production without Docker — build the frontend and let the backend serve it:
cd frontend && npm run build
cd ../backend
GAMMA_STATIC_DIR=../frontend/dist uvicorn app:app --host 127.0.0.1 --port 9001Put a TLS-terminating reverse proxy (Caddy, nginx) in front of 9001 for a domain. If you use HTTP/3, consider limiting Caddy to protocols h1 h2 — a Chrome QUIC bug can make large PDFs crawl.
Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
GAMMA_DATA_DIR |
No | data/ at the repo root (/data in Docker) |
Where users.db and the per-workspace data live |
GAMMA_STATIC_DIR |
No | unset (/app/static in Docker) |
Built frontend to serve as SPA; unset = API only |
GAMMA_PORT |
No | 9001 |
Listen port (Docker entrypoint only) |
GAMMA_ADMIN_USER / GAMMA_ADMIN_PASSWORD |
No | admin / random, printed to the log once |
Overrides the account a fresh instance seeds itself at startup (only while no real accounts exist; never touched afterwards). Admins manage users from the GUI (Settings → Users) |
GAMMA_AI_ANTHROPIC_BASE_URL |
No | https://api.anthropic.com |
Default Anthropic-protocol endpoint, e.g. https://api.deepseek.com/anthropic |
GAMMA_AI_OPENAI_BASE_URL |
No | https://api.openai.com |
Default OpenAI-compatible endpoint |
AI is configured in the app, not the environment: each user adds provider entries under Settings → AI → Connections (pick the API format — Anthropic Messages or OpenAI Chat Completions — then a key, plus optional label, base URL, and model list), or connects a ChatGPT Plus/Pro subscription with Sign in with ChatGPT — OAuth, no key at all. Keys are stored server-side per user and never sent back to the browser. The base-URL variables above only change the per-protocol defaults shown in that dialog.
Docker image
Published to GitHub Container Registry on every push to main (latest) and on version tags (v1.2.3 → 1.2.3, 1.2), for linux/amd64 and linux/arm64:
ghcr.io/tim4431/gamma
Multi-stage build: a Node stage compiles the frontend, the final Python image runs FastAPI serving both the API and the SPA on port 9001. See Dockerfile and .github/workflows/docker.yml.
Gamma is licensed under the GNU Affero General Public License v3.0 only
(AGPL-3.0-only). Third-party components and assets retain their respective licenses.



