- Python 55.1%
- CSS 18.8%
- HTML 14%
- JavaScript 11%
- Just 0.9%
- Other 0.2%
| .forgejo/workflows | ||
| app | ||
| screenshots | ||
| scripts | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| CLAUDE.md | ||
| COMMERCIAL_LICENSE.md | ||
| compose.yml | ||
| CONFIGURATION.md | ||
| Dockerfile | ||
| justfile | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| pyproject.toml | ||
| pyrightconfig.json | ||
| README.md | ||
| uv.lock | ||

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.
| Dark | Light |
|---|---|
![]() |
![]() |
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 (create, delete, reset passwords)
- 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)
Create a compose.yml:
services:
piruetas:
image: forgejo.patilla.es/patillacode/piruetas:latest
ports:
- "8000:8000"
volumes:
- ./data:/data
environment:
SECRET_KEY: change-me-to-a-random-string
ADMIN_USERNAME: admin
ADMIN_PASSWORD: changeme
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
Running behind a reverse proxy (nginx, Caddy, Traefik)? Set
TRUST_PROXY: "true"in your environment so rate limiting uses the real client IP.
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.
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.

