Assclaw fd6671cf7e
Magent CI/CD / verify (push) Successful in 5m20s
Magent CI/CD / deploy-beta (push) Successful in 1m41s
feat: add backup recovery, setup wizard and user-view guards
2026-09-18 17:23:03 +12:00
2026-08-29 20:27:17 +12:00
2026-08-29 20:27:17 +12:00
2026-08-29 20:27:17 +12:00

Magent

Magent is a friendly, AI-assisted request tracker for Seerr + Arr services. It shows a clear timeline of where a request is stuck, explains what is happening in plain English, and offers safe actions to help fix issues.

How it works

  1. Requests are pulled from Seerr and stored locally.
  2. Magent joins that request to Sonarr/Radarr, Prowlarr, qBittorrent, and Jellyfin using TMDB/TVDB IDs and download hashes.
  3. A state engine normalizes noisy service statuses into a simple, user-friendly state.
  4. The UI renders a timeline and a central status box for each request.
  5. Optional AI triage summarizes the likely cause and safest next steps.

Core features

  • Request search by title/year or request ID.
  • Recent requests list with posters and status.
  • Timeline view across Seerr, Arr, Prowlarr, qBittorrent, Jellyfin.
  • Central status box with clear reason + next steps.
  • Safe action buttons (search, resume, re-add, etc.).
  • Admin settings for service URLs, API keys, profiles, and root folders.
  • Health status for each service in the pipeline.
  • Cache and sync controls (full sync, delta sync, scheduled syncs).
  • Local database for speed and audit history.
  • Users and access control (admin vs user, block access).
  • Local account password changes via "My profile".
  • Personal viewing stats from Jellystat: minutes, movies, episodes, streaks, and recent plays alongside requests. See Jellystat setup.
  • Admin review and confirmation of account IDs across Jellyfin, Seerr, Jellystat and Magent. See user identities.
  • Docker-first deployment for easy hosting.
  • Guided, resumable first-install setup with app connection tests.
  • Encrypted backups of configuration, database and optional artwork cache, with restart-only restore.

Quick start (Docker - primary)

Docker is the recommended way to run Magent. It includes the backend and frontend with sane defaults.

docker compose up --build

Then open:

Docker setup steps

  1. Copy .env.example to .env. Generate independent JWT_SECRET, SETTINGS_ENCRYPTION_KEY and SETUP_TOKEN values as described below. Do not use the example placeholders.
  2. Set CORS_ALLOW_ORIGIN and MAGENT_APPLICATION_URL to your browser-facing origin. For public deployments, use HTTPS and AUTH_COOKIE_SECURE=true.
  3. Run docker compose up --build.
  4. Open http://localhost:3000. A fresh database opens the setup wizard automatically. Use your SETUP_TOKEN to create a local administrator, then connect and test each app you use.
  5. Choose site, sign-in, request-sync and email preferences, review the connections, and finish setup. Remove SETUP_TOKEN from the deployment environment afterwards.

Apps may be skipped and configured later. Progress is saved in SQLite. Background imports and automation remain paused until setup is complete; BACKGROUND_TASKS_ENABLED=false still takes precedence. Existing installations are automatically treated as configured and are not forced through the wizard. Administrators can reopen it at Settings → Advanced tools → Setup wizard.

If you prefer to seed an administrator through deployment configuration, set a unique ADMIN_USERNAME and ADMIN_PASSWORD instead of SETUP_TOKEN. The wizard then asks you to sign in with that account. Environment credentials create only the first administrator; they do not add another account to a restored installation. Service URLs and API keys can still be supplied through the environment, and the wizard preloads these settings without exposing saved secrets.

See installation and recovery for migration, backup limits and restore instructions.

Docker environment variables (sample)

JELLYSEERR_URL="http://localhost:5055"
JELLYSEERR_API_KEY="..."
SONARR_URL="http://localhost:8989"
SONARR_API_KEY="..."
SONARR_QUALITY_PROFILE_ID="1"
SONARR_ROOT_FOLDER="/tv"
RADARR_URL="http://localhost:7878"
RADARR_API_KEY="..."
RADARR_QUALITY_PROFILE_ID="1"
RADARR_ROOT_FOLDER="/movies"
PROWLARR_URL="http://localhost:9696"
PROWLARR_API_KEY="..."
QBIT_URL="http://localhost:8080"
QBIT_USERNAME="..."
QBIT_PASSWORD="..."
SQLITE_PATH="data/magent.db"
JWT_SECRET="replace-with-at-least-32-random-characters"
SETTINGS_ENCRYPTION_KEY="replace-with-a-fernet-key"
JWT_EXP_MINUTES="120"
ADMIN_USERNAME="set-a-real-admin-username"
ADMIN_PASSWORD="set-a-long-unique-admin-password"

Screenshots

Add screenshots here once available:

  • docs/screenshots/home.png
  • docs/screenshots/request-timeline.png
  • docs/screenshots/settings.png
  • docs/screenshots/profile.png

Local development (secondary)

Use this only when you need to modify code locally.

Backend (FastAPI)

cd backend
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000

Environment variables (sample):

$env:JELLYSEERR_URL="http://localhost:5055"
$env:JELLYSEERR_API_KEY="..."
$env:SONARR_URL="http://localhost:8989"
$env:SONARR_API_KEY="..."
$env:SONARR_QUALITY_PROFILE_ID="1"
$env:SONARR_ROOT_FOLDER="/tv"
$env:RADARR_URL="http://localhost:7878"
$env:RADARR_API_KEY="..."
$env:RADARR_QUALITY_PROFILE_ID="1"
$env:RADARR_ROOT_FOLDER="/movies"
$env:PROWLARR_URL="http://localhost:9696"
$env:PROWLARR_API_KEY="..."
$env:QBIT_URL="http://localhost:8080"
$env:QBIT_USERNAME="..."
$env:QBIT_PASSWORD="..."
$env:SQLITE_PATH="data/magent.db"
$env:JWT_SECRET="replace-with-at-least-32-random-characters"
$env:SETTINGS_ENCRYPTION_KEY="replace-with-a-fernet-key"
$env:JWT_EXP_MINUTES="120"
$env:ADMIN_USERNAME="set-a-real-admin-username"
$env:ADMIN_PASSWORD="set-a-long-unique-admin-password"

Frontend (Next.js)

cd frontend
npm install
npm run dev

Open http://localhost:3000

Admin panel: http://localhost:3000/admin

Login uses the admin credentials above (or any other local user you create in SQLite).

Local quality checks

bash scripts/ci_backend_quality_gate.sh
cd frontend
npm ci
npm run lint
npm run format:check
npm run typecheck
npm test
npm run build

Public Hosting Notes

The frontend proxies /api/* to the backend container. Set:

  • NEXT_PUBLIC_API_BASE=/api (browser uses same-origin)
  • BACKEND_INTERNAL_URL=http://backend:8000 (container-to-container)

If you prefer the browser to call the backend directly, set NEXT_PUBLIC_API_BASE to your public backend URL and ensure CORS is configured.

Gitea CI/CD

This repo now includes a Gitea Actions workflow at .gitea/workflows/ci-cd.yml.

  • Push to beta: runs the complete quality gate and deploys the isolated beta environment to AMS-DEV01.
  • Push to main or prod: runs the same verification without automatically changing production.
  • Production releases are tagged from main and deployed to GRZ-DKR01 using the checklist in PRODUCTION.md.

The beta deploy step ships tracked repository files over SSH, preserves beta's own .env and data/, rebuilds with docker compose up -d --build, and smoke-tests:

  • http://127.0.0.1:8000/health
  • http://127.0.0.1:3000/login

Configure these Gitea Actions secrets before enabling the deploy job:

The existing PROD_* names are retained for compatibility, but this workflow uses them only for the isolated beta host deployment.

  • PROD_SSH_PRIVATE_KEY: private key for the deployment account.
  • PROD_SSH_HOST: target host, for example AMS-DEV01.
  • PROD_SSH_USER: target user, for example zak.
  • PROD_SSH_KNOWN_HOSTS: required pinned known_hosts entry. Deployments reject unknown or changed hosts.

Beta always deploys to the isolated /home/<deployment-user>/magent-beta directory; the production path secret is intentionally ignored.

Security and data handling

Generate independent signing and settings-encryption secrets before first startup:

python -c "import secrets; print(secrets.token_urlsafe(48))"
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
  • JWT_SECRET must contain at least 32 characters. Access sessions expire after 120 minutes by default and are revoked after logout, password, role, or blocked-state changes.
  • SETUP_TOKEN is a separate random value of at least 32 characters, generated using the first command above a second time. It only authorizes first-admin creation on an unfinished, fresh installation. Never put it in a URL or share it with ordinary users. After completion the public bootstrap endpoint remains disabled even if the token is retained.
  • SETTINGS_ENCRYPTION_KEY protects service API keys, SMTP credentials, webhooks, and private keys stored in SQLite. Keep it in .env, outside the database and its backups. If omitted, Magent derives a migration-compatible key from JWT_SECRET; a dedicated key is recommended.
  • Invite secrets are stored as one-way hashes. Existing invite links continue to work after migration, but the admin UI cannot reveal an old link. Copy a link when it is created, or generate a replacement link later; replacement immediately invalidates the prior link.
  • Magent encrypts sensitive settings, not the entire SQLite database. Request metadata, account records, logs, the data/ volume, and backups should live on encrypted host storage with access restricted to the deployment account.
  • REQUESTS_CLEANUP_DAYS controls routine request-history retention (90 days by default). Account deletion removes authentication and subscription records and anonymizes retained request and portal history.
  • Production and beta cookies require HTTPS and use SameSite=Strict. Keep the backend port bound to loopback and publish the frontend only through the intended reverse proxy.
  • View as user is a per-tab interface preview: it hides configuration, user-management pages, diagnostics and moderation tools, including direct admin-page URLs. Exit user view restores the administrator interface. It does not impersonate another account or change backend permissions; the displayed data still belongs to the signed-in account. Test real permission boundaries with a separate non-admin account.

History endpoints

  • GET /requests/{id}/history?limit=10 recent snapshots
  • GET /requests/{id}/actions?limit=10 recent action logs

Troubleshooting

Login fails

  • For a fresh installation, open /setup and use SETUP_TOKEN, or sign in with the environment-seeded administrator. Existing installations use the accounts already in the database; changing ADMIN_PASSWORD does not reset an existing account.
  • Confirm the backend is reachable: http://localhost:8000/health (or see container logs).

Services show as down

  • Check the URLs and API keys in Settings.
  • Verify containers can reach each service (network/DNS).

No recent requests

  • Confirm Seerr credentials in Settings.
  • Run a full sync from Settings -> Requests.

Docker images not updating

  • Run docker compose up --build again.
  • If needed, run docker compose down first, then rebuild.
S
Description
No description provided
Readme
3.2 MiB
Languages
Python 51.1%
TypeScript 29.4%
CSS 11.3%
JavaScript 7.3%
PowerShell 0.4%
Other 0.3%