The curator app (Python backend, tests, systemd units, config, scripts) now lives in this repo under scenarios/curator/backend, exported from the standalone checkout's tracked tree (.pi mirror, venv and caches excluded). 149 unit tests pass from the new location; _SHARED_LIB and eval GOLDEN_DIR resolve unchanged. History not preserved per decision. verify-no-secrets: the ASSIGN heuristic now requires the value to carry entropy (a digit or uppercase letter), so vendored Python kwargs like token=extraction_token no longer false-positive while real base64/hex/random secrets still trip it.
78 lines
3.0 KiB
Desktop File
78 lines
3.0 KiB
Desktop File
[Unit]
|
|
Description=Curator personal media library
|
|
Wants=network-online.target
|
|
After=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
WorkingDirectory=/home/claw/pi-workspaces/curator
|
|
Environment=PYTHONPATH=/home/claw/pi-workspaces/curator
|
|
Environment=CURATOR_PI_WORKSPACE=/home/claw/pi-workspaces/curator
|
|
Environment=CURATOR_PI_SESSION_DIR=/home/claw/.local/share/pi-curator/sessions
|
|
Environment=CURATOR_PI_MODEL=zenmux/openai/gpt-5.6-luna
|
|
Environment=CURATOR_PI_THINKING=high
|
|
Environment=CURATOR_PI_FALLBACK_MODEL=zenmux/x-ai/grok-4.6
|
|
Environment=CURATOR_PI_TIMEOUT_SECONDS=120
|
|
Environment=CURATOR_WECHAT_ARTICLE_BASE_URL=http://192.168.50.145:8091
|
|
EnvironmentFile=/home/claw/.config/curator/curator.env
|
|
ExecStart=/usr/bin/python3 -m curator serve
|
|
Restart=on-failure
|
|
RestartSec=5
|
|
TimeoutStartSec=60
|
|
TimeoutStopSec=20
|
|
|
|
# --- filesystem -------------------------------------------------------------
|
|
# The whole hierarchy is read-only apart from the paths listed below. Verified
|
|
# with systemd-run before being applied: the database, library, staging, backup
|
|
# and cover directories are writable and pi starts cleanly.
|
|
ProtectSystem=strict
|
|
ProtectHome=read-only
|
|
ReadWritePaths=/home/claw/.local/share/curator
|
|
ReadWritePaths=/mnt/truenas/multimedia/books
|
|
ReadWritePaths=/mnt/truenas/multimedia/curator
|
|
ReadWritePaths=/home/claw/.local/share/pi-curator
|
|
# pi takes a lock beside ~/.pi/agent/settings.json on startup. With a read-only
|
|
# home it cannot, and then reports the settings file as invalid and ignores it --
|
|
# which would silently discard the agent's configuration.
|
|
ReadWritePaths=/home/claw/.pi
|
|
|
|
# The agent's own prompt and launch contract are read-only to the service that
|
|
# runs it, so a compromised agent cannot rewrite the rules it runs under.
|
|
ReadOnlyPaths=/home/claw/pi-workspaces/curator
|
|
|
|
PrivateTmp=true
|
|
UMask=0077
|
|
|
|
# --- privileges -------------------------------------------------------------
|
|
NoNewPrivileges=true
|
|
ProtectKernelTunables=true
|
|
ProtectKernelModules=true
|
|
ProtectKernelLogs=true
|
|
ProtectControlGroups=true
|
|
ProtectClock=true
|
|
ProtectProc=invisible
|
|
RestrictSUIDSGID=true
|
|
RestrictRealtime=true
|
|
RestrictNamespaces=true
|
|
LockPersonality=true
|
|
MemoryDenyWriteExecute=false
|
|
# node's JIT needs writable-executable pages, so MemoryDenyWriteExecute cannot
|
|
# be enabled while pi runs as a child of this service.
|
|
|
|
# --- resources --------------------------------------------------------------
|
|
# pi is a node process and the service may run several sequentially. These are
|
|
# ceilings that turn a runaway into a restart instead of host memory pressure.
|
|
MemoryMax=3G
|
|
MemoryHigh=2G
|
|
TasksMax=512
|
|
|
|
# NOTE: the listener is still on CURATOR_HOST=0.0.0.0, which reaches every
|
|
# interface including six docker bridges, and access genuinely arrives from both
|
|
# the LAN and 127.0.0.1. The defence is now authentication (plan P2-6): every
|
|
# route except /api/health and /login requires CURATOR_WEB_TOKEN, which is what
|
|
# makes an unaudited LAN host into a read-only observer instead of a write
|
|
# primitive. Do not unset CURATOR_WEB_TOKEN while the port is not loopback.
|
|
|
|
[Install]
|
|
WantedBy=default.target
|