Skip to content

Repository files navigation

devlog

Local-first developer task / note / link tracker. Single SQLite file, FastAPI backend, vanilla-JS web UI, a native SwiftUI macOS app, and an MCP server so an LLM can drive everything.

  • Tasks · notes · links scoped to projects, with cross-refs (#42, [[Title]]), tags, full-text search, and a rich markdown editor.
  • Time tracking with single-doing invariant, editable sessions, end-of-workday auto-pause.
  • Drawings via a vendored drawio webapp — fully offline; tokens like ![[drawing:N]] render inline.
  • Markdown via markdown-it with footnotes, task lists, anchors, a custom MkDocs-style admonition rule, highlight.js, and Mermaid.
  • MCP server (devlog-mcp) exposing 18 tools so Claude can create projects/tasks/notes/links/sessions and search.

Quick start

Option A — Pull the prebuilt image from GHCR (fastest, no build, no clone)

GitHub Actions publishes a multi-arch image (linux/amd64 + linux/arm64) to ghcr.io/morapet/devlog on every push to main and on v*.*.* tags. drawio is baked in.

# one-shot run with a host volume for data
mkdir -p ~/devlog-data
docker run -d --name devlog \
    -p 8765:8765 \
    -v ~/devlog-data:/data \
    --restart unless-stopped \
    ghcr.io/morapet/devlog:latest
open http://localhost:8765

Update later:

docker pull ghcr.io/morapet/devlog:latest
docker rm -f devlog
# …then re-run the docker run command above

Or use docker compose with the published image (drop into a new dir as docker-compose.yml):

services:
  devlog:
    image: ghcr.io/morapet/devlog:latest
    container_name: devlog
    ports: ["8765:8765"]
    volumes: ["./data:/data"]
    restart: unless-stopped
docker compose up -d

Available tags:

Tag Source
latest most recent push to main
main most recent push to main
v1.2.3, 1.2, 1 semver from a v*.*.* git tag
sha-abc1234 a specific commit

Note: GHCR packages start as private. After the first publish, go to https://github.com/users/morapet/packages/container/devlog → Package settings → "Change visibility" → Public, so others can docker pull without auth.

Option B — Build the Docker image from source

git clone https://github.com/morapet/devlog.git
cd devlog
make docker-up        # builds the image (includes drawio) and starts the container
open http://localhost:8765

Data persists in ./data/ (a SQLite WAL file). Stop with make docker-down.

Option C — Local Python (with uv)

git clone https://github.com/morapet/devlog.git
cd devlog
make install          # uv sync
make drawio           # download + install the drawio webapp (~120 MB, one-time)
make dev              # uv run devlog
open http://127.0.0.1:8765

Data goes to ~/.local/share/devlog/devlog.db (or $XDG_DATA_HOME/devlog/ if set).

Option D — Install as a CLI tool

uv tool install git+https://github.com/morapet/devlog.git
devlog                # starts the backend
bash $(uv tool dir)/devlog/scripts/install-drawio.sh   # if you want drawings

Option E — Ubuntu / Debian, run on every login (systemd user service)

# From a repo checkout
make install-linux      # backend service + desktop app, all-in-one

# Or piecewise
bash clients/linux-server/install.sh   # backend via pipx/uv + systemd --user
bash clients/linux-app/install.sh      # GTK desktop app + autostart

# Or from anywhere, no checkout
curl -sLf https://raw.githubusercontent.com/morapet/devlog/main/clients/linux-server/install.sh \
    | bash -s -- --from-github --linger

The server script:

  • Installs the devlog package (via uv toolpipxpip --user, whichever exists; bootstraps pipx via apt if none).
  • Downloads the drawio webapp into the installed package (skip with --no-drawio).
  • Writes ~/.config/systemd/user/devlog.service and runs systemctl --user enable --now devlog.
  • With --linger, runs sudo loginctl enable-linger $USER so the backend keeps running after logout.

See clients/linux-server/README.md for status / upgrade / uninstall.

Use from your iPhone (or any phone)

The web UI is a mobile-friendly PWA — run the backend on any machine your phone can reach and it behaves like a native app. There is no iOS build to install; Safari is the client.

Same Wi-Fi (home / office LAN)

  1. Make the server reachable from the network:
    • Docker already binds 0.0.0.0 — nothing to do.
    • Local Python: DEVLOG_HOST=0.0.0.0 make dev (the default bind is 127.0.0.1, which the phone can't reach).
  2. Find the machine's LAN IP: ipconfig getifaddr en0 (macOS) or hostname -I (Linux).
  3. On the iPhone, open http://<that-ip>:8765 in Safari.
  4. Add to Home Screen: tap Share → Add to Home Screen. Devlog launches full-screen with its own icon, indistinguishable from a native app.

Away from home — Tailscale (recommended)

Install Tailscale on the server machine and the iPhone (App Store, free for personal use). The phone can then reach the server from anywhere:

http://<machine-name>:8765        # via MagicDNS

For HTTPS (nicer, and required for the offline service worker — plain http:// on a LAN IP is not a secure context):

tailscale serve --bg 8765
# → https://<machine-name>.<tailnet>.ts.net

No computer at all — run it on the iPhone

The backend is small enough to run on the phone itself inside iSH (free, App Store); Safari talks to it over localhost. See clients/ios/README.md — install is four commands, nothing is compiled on-device.

Hosting it on the internet (HTTPS + login)

Devlog ships built-in auth for remote access: your own machine (loopback) is trusted, but requests from other devices need a shared secret. The secret comes from DEVLOG_AUTH_TOKEN, or is auto-generated into <data_dir>/auth.token — print it with devlog --print-token. Set DEVLOG_AUTH=always to require the secret even on loopback, or DEVLOG_AUTH=off to disable auth entirely. The web UI prompts for the token on first remote access and keeps a 30-day session cookie; API clients send Authorization: Bearer <token>. With HTTPS in front, hosting publicly is reasonable. Two ready-made setups, both serving the PWA from anywhere with full offline-shell support:

  • deploy/cloudflare/Cloudflare Tunnel, free, zero open ports: runs on any always-on machine at home; optional Cloudflare Access (Google login / email PIN) at the edge on top of the built-in shared secret.
  • deploy/vps-caddy/VPS + Caddy: ~€4/mo box, automatic Let's Encrypt certificates, built-in shared secret for auth.
  • deploy/pythonanywhere/PythonAnywhere: free tier works (HTTPS at you.pythonanywhere.com), no server admin at all; deploys via a small WSGI bridge.
  • deploy/cloud-run/Google Cloud Run: free *.run.app HTTPS URL, scale-to-zero; SQLite persists via Litestream streaming to a GCS bucket (single instance only).

Never expose port 8765 directly with DEVLOG_AUTH=off — an open devlog is writable by anyone. Keep the shared secret (required for remote access by default) and TLS in front (the cookie and token travel in requests).

Desktop app (optional)

macOS — native SwiftUI

make mac
# or:
cd clients/mac-app && ./build.sh && open .build/Devlog.app

Requires Swift / CommandLineTools. A native window hosts the full web UI in a WKWebView (with native save/open panels and Cmd+F find), and can manage its own backend. make mac-dmg builds a drag-to-Applications installer; make mac-install copies it into /Applications.

Linux — GNOME / Ubuntu (GTK3 + WebKit2GTK)

make app-linux
# or:
bash clients/linux-app/install.sh

A GTK desktop window wrapping the same web UI. The installer apt-installs the PyGObject / WebKit2GTK dependencies, drops a launcher, and enables autostart. See clients/linux-app/README.md.

MCP server

Exposes the HTTP API as 18 MCP tools for use from Claude Desktop / Claude Code.

Add to your client config (e.g. ~/.claude.json or claude_desktop_config.json):

{
  "mcpServers": {
    "devlog": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/devlog", "devlog-mcp"]
    }
  }
}

Override the backend URL with DEVLOG_BASE_URL. See src/devlog/mcp_server.py for the full tool list.

Make targets

make help               # list every target
make install            # install python deps via uv
make drawio             # download drawio webapp
make dev                # run the backend
make mac                # build and launch the macOS app
make mcp                # run devlog-mcp (stdio)
make docker-build       # docker compose build
make docker-up          # docker compose up -d
make docker-down        # docker compose down
make docker-logs        # follow container logs
make clean              # remove build artifacts (keeps data + db)

Configuration

Env var Default Meaning
DEVLOG_HOST 127.0.0.1 Bind address (0.0.0.0 in Docker)
DEVLOG_PORT 8765 Bind port
DEVLOG_DATA_DIR $XDG_DATA_HOME/devlog or ~/.local/share/devlog Where the SQLite file lives
DEVLOG_BASE_URL http://127.0.0.1:8765 Used by devlog-mcp to reach the backend
DEVLOG_AUTH auto auto trusts loopback and requires the token remotely; always requires it everywhere; off disables auth
DEVLOG_AUTH_TOKEN (auto-generated to auth.token) Shared secret for remote access; print it with devlog --print-token. Read by devlog-mcp too

Project layout

.
├── src/devlog/           # FastAPI app + web assets
│   ├── api/              # routers: projects, items, sessions, attachments, search, stats, settings
│   ├── web/              # index.html, app.js, style.css, vendor/drawio/ (ignored)
│   ├── db.py             # schema + thread-local connections + migrations
│   ├── autostop.py       # background loop pausing 'doing' tasks at end of workday
│   ├── stats.py          # raw per-day session time math
│   └── mcp_server.py     # FastMCP wrapper exposing 18 tools
├── clients/mac-app/      # SwiftUI native app (Swift Package Manager)
├── scripts/              # helpers (install-drawio.sh)
├── Dockerfile            # python:3.13-slim base, uv, optional drawio install
├── docker-compose.yml    # `make docker-up`
├── Makefile              # convenience targets
└── pyproject.toml        # uv-managed; entry points: devlog, devlog-mcp

Stack

  • Backend: FastAPI · SQLite (WAL + FTS5) · httpx · selectolax
  • Web UI: vanilla JS · Tailwind via CDN · markdown-it + custom plugins · highlight.js · Mermaid · drawio (vendored)
  • macOS app: SwiftUI · WKWebView · async/await URLSession client
  • MCP: mcp Python SDK (FastMCP, stdio transport)

Documentation

Three layers, each at a different scope:

  • ARCHITECTURE.md — big picture: system diagram, process model, rendering pipeline, what each client does, what's new recently.
  • AGENTS.md — operating guide for LLMs: how to connect via MCP, common workflows mapped to tool calls, the drawio recipe with a Python helper.
  • SPECIFICATION.md — exhaustive contract suitable for full reimplementation. Domain model, every endpoint, every invariant.

License

MIT

About

Developer daily logging system tasks/ideas/links

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages