A minimalist, self-hosted diary and journaling web app. https://piruet.app
  • Python 61.9%
  • CSS 15.5%
  • HTML 12.5%
  • JavaScript 9.3%
  • Just 0.6%
  • Other 0.2%
Find a file
PatillaCode 331b34e5fa
All checks were successful
Release / test (push) Successful in 39s
Release / e2e (push) Successful in 6m32s
Release / build (push) Successful in 1m56s
feat/sharing-wait-env-var (#33)
Co-authored-by: PatillaCode <patillacode@gmail.com>
Co-committed-by: PatillaCode <patillacode@gmail.com>
2026-05-25 21:29:31 +02:00
.forgejo/workflows feat/e2e-refactor (#28) 2026-05-06 21:56:48 +02:00
app feat/sharing-wait-env-var (#33) 2026-05-25 21:29:31 +02:00
scripts fix: prevent demo user from changing their own password (#22) 2026-05-02 15:23:40 +02:00
tests feat/sharing-wait-env-var (#33) 2026-05-25 21:29:31 +02:00
.dockerignore Code review and clean up (#18) 2026-05-01 10:24:47 +02:00
.env.example feat/sharing-wait-env-var (#33) 2026-05-25 21:29:31 +02:00
.gitignore feature/security-recovery-support (#16) 2026-04-28 16:23:03 +02:00
CLAUDE.md feat/arm64-multiarch-images (#25) 2026-05-03 14:25:13 +02:00
COMMERCIAL_LICENSE.md feature/ux-improvements (#6) 2026-04-21 16:55:26 +02:00
compose.yml Code review and clean up (#18) 2026-05-01 10:24:47 +02:00
CONFIGURATION.md feat/sharing-wait-env-var (#33) 2026-05-25 21:29:31 +02:00
Dockerfile feat/arm64-multiarch-images (#25) 2026-05-03 14:25:13 +02:00
justfile feat/e2e-refactor (#28) 2026-05-06 21:56:48 +02:00
LICENSE feature/ux-improvements (#6) 2026-04-21 16:55:26 +02:00
package-lock.json fix: commit package-lock.json so npm ci works in Docker CI builds 2026-04-23 10:27:04 +02:00
package.json feat: self-host fonts and Tiptap, add admin task scheduler (#10) 2026-04-22 17:49:19 +02:00
pyproject.toml feat/security-notifications (#30) 2026-05-25 18:09:46 +02:00
pyrightconfig.json Code review and clean up (#18) 2026-05-01 10:24:47 +02:00
README.md feat/sharing-wait-env-var (#33) 2026-05-25 21:29:31 +02:00
uv.lock feat/security-notifications (#30) 2026-05-25 18:09:46 +02:00

Piruetas

A minimalistic, self-hosted diary and journaling web app.

Piruetas gives each day its own page with a clean writing experience, multi-user support, and full control over your data.

Try it

A live demo is available at piruet.app. Log in with demo / piruetas, content resets every 30 minutes.

Editor Mobile menu Account
Journal editor Mobile navigation Account settings

More screenshots →

Features

  • Day-per-page diary with month calendar navigation
  • Rich text editing (bold, italic, links, inline images) via Tiptap
  • Auto-save with 2-second debounce and "Saved" toast
  • Drag-and-drop image uploads (JPEG, PNG, GIF, WebP, max 10 MB)
  • Public entry sharing via unique link (with revocation)
  • Multi-user with admin panel (user list, delete), optional self-service signup, and password recovery via recovery codes
  • Word count display per entry
  • Writing streak tracking
  • Security notifications via ntfy or Telegram (new user signup, admin login, rate limit blocks)
  • English and Spanish UI (locale switcher in header, cookie-persisted)
  • Configurable calendar week start (Monday or Sunday)
  • Light and dark theme (persisted in localStorage)
  • Mobile responsive with bottom toolbar above keyboard
  • Docker deployable with CI/CD via Forgejo

Quick start (Docker)

Images are published for amd64 (standard servers/desktops) and arm64 (Raspberry Pi 4/5, Apple Silicon).

Registry Image
GitHub (GHCR) ghcr.io/patillacode/piruetas:latest
Forgejo forgejo.patilla.es/patillacode/piruetas:latest

Create a compose.yml:

services:
  piruetas:
    image: ghcr.io/patillacode/piruetas:latest
    ports:
      - "8000:8000"
    volumes:
      - ./data:/data
    environment:
      # generate with: openssl rand -hex 32
      SECRET_KEY: change-me-to-a-random-string
      ADMIN_USERNAME: admin
      ADMIN_PASSWORD: changeme
      SECURE_COOKIES: "false"        # set to "true" if serving over HTTPS
      REGISTRATION_OPEN: "false"     # set to "true" to allow self-registration
      # TRUST_PROXY: "true"          # uncomment if behind a reverse proxy (nginx, Caddy, Traefik)
    restart: unless-stopped
docker compose up -d

Open http://localhost:8000 and log in with your admin credentials.

To update: docker compose pull && docker compose up -d

Local development

Requirements: Python 3.12+, uv, just.

git clone ssh://git@forgejo.patilla.es:2223/patillacode/piruetas.git
cd piruetas
cp .env.example .env
# Edit .env: set SECRET_KEY to any string, set SECURE_COOKIES=false
just install
just dev

Open http://localhost:8000.

Run just to see all available recipes.

JS bundle

The Tiptap editor library is bundled from npm into app/static/js/vendor/tiptap.bundle.js using esbuild. This file is committed to the repo so no Node tooling is needed to run the app — it's treated as a vendored asset, the same as self-hosted font files.

To rebuild after upgrading Tiptap (bump versions in package.json first):

just build-js

The Docker build always rebuilds the bundle from source in a Node build stage, so the committed bundle is only used for local development without Docker.

Running tests

Unit and integration tests (no browser required):

just test

E2E tests with Playwright (one-time browser install needed first):

just install-e2e   # downloads Chromium and Firefox — run once
just test-e2e      # headless
just test-e2e-headed  # with visible browser (useful for debugging)

Configuration

See CONFIGURATION.md for all available environment variables.

Support

Piruetas is free and open source. If you find it useful, a small donation keeps it alive.

ko-fi

License

Piruetas is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).

For use in proprietary or commercial products without complying with the AGPL-3.0, a commercial license is available. See COMMERCIAL_LICENSE.md or contact patillacode@gmail.com.