Files
libnovel/AGENTS.md
Admin 7aad42834f
All checks were successful
Release / Test backend (push) Successful in 48s
Release / Check ui (push) Successful in 54s
Release / Docker / caddy (push) Successful in 38s
Release / Docker / backend (push) Successful in 3m7s
Release / Docker / runner (push) Successful in 2m58s
Release / Upload source maps (push) Successful in 1m56s
Release / Docker / ui (push) Successful in 2m17s
Release / Gitea Release (push) Successful in 47s
fix: GlitchTip source map upload flow; add AGENTS.md
Add 'releases new' and 'releases finalize' steps around sourcemaps
upload in release.yaml — without an explicit 'releases new' call,
GlitchTip creates the release entry but associates 0 files.

Add root AGENTS.md (picked up by Claude, Cursor, Copilot, etc.) with
full project context: stack, repo layout, Gitea CI conventions,
GlitchTip DSN/upload flow, infra, and iOS notes.
2026-04-05 14:52:41 +05:00

5.0 KiB

LibNovel v2 — Agent Context

This file is the root-level knowledge base for LLM coding agents (OpenCode, Claude, Cursor, Copilot, etc.). Sub-directories have their own AGENTS.md with deeper context (e.g. ios/AGENTS.md).


Stack

Layer Technology
UI SvelteKit 2 + Svelte 5, TypeScript, TailwindCSS
Backend / Runner Go (single repo, two binaries: backend, runner)
iOS app SwiftUI, iOS 17+, Swift 5.9+
Database PocketBase (SQLite) + MinIO (object storage)
Search Meilisearch
Queue Asynq over Redis (local) / Valkey (prod)
Scraping Novelfire scraper in backend/novelfire/

Repository Layout

.
├── .gitea/workflows/     # CI/CD — Gitea Actions (NOT .github/)
├── .opencode/            # OpenCode agent config (memory, skills)
├── backend/              # Go backend + runner (single module)
├── caddy/                # Caddy reverse proxy Dockerfile
├── homelab/              # Homelab docker-compose + observability stack
├── ios/                  # SwiftUI iOS app (see ios/AGENTS.md)
├── scripts/              # Utility scripts
├── ui/                   # SvelteKit UI
├── docker-compose.yml    # Prod compose (all services)
├── AGENTS.md             # This file
└── opencode.json         # OpenCode config

CI/CD — Gitea Actions

  • Workflows live in .gitea/workflows/not .github/workflows/
  • Self-hosted Gitea instance; use gitea.ref_name / gitea.sha (not github.*)
  • Two workflows:
    • ci.yaml — runs on every push to main (test + type-check)
    • release.yaml — runs on v* tags (build Docker images, upload source maps, create Gitea release)
  • Secrets: DOCKER_USER, DOCKER_TOKEN, GITEA_TOKEN, GLITCHTIP_AUTH_TOKEN

Releasing a new version

git tag v2.5.X -m "Short title\n\nOptional longer body"
git push origin v2.5.X

CI will build all Docker images, upload source maps to GlitchTip, and create a Gitea release automatically.


GlitchTip Error Tracking

  • Instance: https://errors.libnovel.cc/
  • Org: libnovel
  • Projects: ui (id/1), backend (id/2), runner (id/3)
  • Tool: glitchtip-cli v0.1.0

Per-service DSNs (stored in Doppler)

Service Doppler key GlitchTip project
UI (SvelteKit) PUBLIC_GLITCHTIP_DSN ui (1)
Backend (Go) GLITCHTIP_DSN_BACKEND backend (2)
Runner (Go) GLITCHTIP_DSN_RUNNER runner (3)

Source map upload flow (release.yaml)

The correct order is critical — uploading before releases new results in 0 files shown in GlitchTip UI:

glitchtip-cli sourcemaps inject ./build          # inject debug IDs
glitchtip-cli releases new <version>             # MUST come before upload
glitchtip-cli sourcemaps upload ./build \
  --release <version>                            # associate files with release
glitchtip-cli releases finalize <version>        # mark release complete

Infrastructure

Environment Host Path Doppler config
Prod 165.22.70.138 /opt/libnovel/ prd
Homelab runner 192.168.0.109 /opt/libnovel-runner/ prd_homelab

Docker Compose — always use Doppler

# Prod
doppler run --project libnovel --config prd -- docker compose <cmd>

# Homelab full-stack (runs from .bak file on server)
doppler run --project libnovel --config prd_homelab -- docker compose -f homelab/docker-compose.yml.bak <cmd>

# Homelab runner only
doppler run --project libnovel --config prd_homelab -- docker compose -f homelab/runner/docker-compose.yml <cmd>
  • Prod runner has profiles: [runner]docker compose up -d will NOT accidentally start it
  • When deploying, always sync docker-compose.yml to the server before running up -d

Observability

Tool Purpose
GlitchTip Error tracking (UI + backend + runner)
Grafana Faro RUM / Web Vitals (collector at faro.libnovel.cc/collect)
OpenTelemetry Distributed tracing (OTLP → collector → Tempo)
Grafana Dashboards at /admin/grafana

Grafana dashboards: homelab/otel/grafana/provisioning/dashboards/


Go Backend

  • Primary files: orchestrator.go, server/handlers_*.go, novelfire/scraper.go, storage/hybrid.go, storage/pocketbase.go
  • Store interface: store.go — never touch MinIO/PocketBase clients directly outside storage/
  • Two binaries built from the same module: backend (HTTP API) and runner (Asynq worker)

SvelteKit UI

  • Source: ui/src/
  • i18n: Paraglide — translation files in ui/messages/*.json (5 locales)
  • Auth debug bypass: GET /api/auth/debug-login?token=<DEBUG_LOGIN_TOKEN>&username=<username>&next=<path>

iOS App

Full context in ios/AGENTS.md. Quick notes:

  • SwiftUI, iOS 17+, @Observable for new types
  • Download key separator: :: (not -)
  • Voice fallback: book override → global default → "af_bella"
  • Offline pattern: NetworkMonitor env object + OfflineBanner + ErrorAlertModifier