Every Piumy setting is an environment variable — no config file format to learn, no YAML schema to maintain. The systemd services loadDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/chamilonster/Piumy/llms.txt
Use this file to discover all available pages before exploring further.
/opt/pimywa/pimywa.env via EnvironmentFile=. Set variables there and restart the relevant service to apply changes.
pimywa.env is not committed to version control — it may contain secrets
such as PIMYWA_API_KEY and PIMYWA_BACKUP_KEY. The example file at
deploy/pimywa.env.example contains only safe placeholder values.Core paths
Path to the SQLite database that stores messages, chats, and settings. In
production deployments this lives at
/opt/pimywa/data/pimywa.db.Path to
status.json — the data contract between the core and the display
adapter. In production this is typically /opt/pimywa/data/status.json or a
tmpfs path under /run/pimywa/. See status.json contract.Path to
router.json — the whitelist and routing configuration. See
router.json reference.Path to the WhatsApp session SQLite database managed by whatsmeow. This holds
your linked-device credentials — back it up with
PIMYWA_BACKUP_KEY.Directory where downloaded media files (images, videos, stickers) are written.
Never stored in SQLite. Controlled by the
PIMYWA_MEDIA_MAX_MB GC policy.Network & auth
Listen address for the MCP server (streamable HTTP). Accepts any
host:port
form; :8081 listens on all interfaces.Listen address for the REST API. Accepts any
host:port form.MCP bearer token (
Authorization: Bearer <token>). Empty means open — any
client can connect without authentication. Set via pimywa auth setup. This
is a separate secret from PIMYWA_API_KEY.REST API key. When set, every
/api/* request must include it via the
X-API-Key header or ?key= query param. Empty means the API is open —
development only, always bind to a private interface in that case.Display name shown on the e-paper display and in the dashboard footer.
Gateway
WhatsApp backend to use.
whatsmeow enables the real connection;
none disables all WhatsApp connectivity — safe for development or
off-Pi builds.Label shown in WhatsApp under Linked Devices. Only applies at pairing
time — changing this after linking does not rename an existing session.
Avoid names that reveal the underlying library to reduce ban fingerprinting
risk (e.g. use
Chrome (Windows) for better camouflage).How long the gateway exposes a QR code before auto-stopping the link flow.
Only enforced when the device is not yet linked. Set to
0 for no timeout
(infinite exposure).Dashboard
Enable or disable the built-in web dashboard. Accepts
on, off, true,
false, 1, yes.Listen address for the dashboard HTTP server.
Dashboard login username.
Dashboard password in plaintext. Hashed with bcrypt in memory at startup.
If neither
PIMYWA_DASH_PASS nor PIMYWA_DASH_PASS_HASH is set, a random
password is generated and logged once via journalctl -u pimywa-core.Pre-computed bcrypt hash of the dashboard password. When set, this takes
precedence over
PIMYWA_DASH_PASS. Generate with htpasswd -nbB admin <password>.Anti-ban delays
These delay windows bound the randomized human-pacing the gateway applies before each WhatsApp action. They can be loosened (slower) at runtime via the dashboard orPOST /api/settings, but never tightened below the defaults — the defaults are the anti-ban floor.
Minimum delay before each outbound WhatsApp send.
Maximum delay before each outbound WhatsApp send.
Minimum delay before marking a message as read (delivering the read receipt).
Maximum delay before marking a message as read.
Minimum delay before other WhatsApp-server-facing actions (contact/group
sync fetches, etc.).
Maximum delay before other server-facing actions.
Rate limits
Maximum number of outbound messages the governor allows per minute. Can be
tightened at runtime via
POST /api/settings but never raised past this
configured ceiling.Maximum number of outbound messages per day. Set to
0 to disable the daily
cap. Can be tightened at runtime but never raised past this configured ceiling.How many failed send attempts an outbox item is given before it is
dead-lettered. Prevents infinite retry loops that could trigger a ban.
MCP anti-flood
These rate limits apply to inbound MCP tool calls from a connected AI agent — separate from the outbound WhatsApp send limits above. Paced per MCP client session. Configurable at runtime viaPOST /api/mcp-guard.
Maximum general tool calls per minute per MCP session. Protects against a
buggy or runaway agent hammering the server.
Maximum emit tool calls (send_message, escalate) per minute per session.
Stricter than the general rate because these cause real-world side effects.
Number of consecutive throttled calls that trip the circuit breaker, fully
blocking the offending session until the cooldown expires.
How long a tripped (circuit-breaker) session remains fully blocked before
being allowed to try again.
Default TTL for
claim_chat locks when the caller omits ttl_sec. The hard
ceiling (30 minutes) is a Go constant and cannot be configured.Session backup
Passphrase used to derive the session backup encryption key via scrypt. When
empty, backups are completely disabled — the WhatsApp session is never
written to disk in any form other than its live database. Set a strong
passphrase to enable periodic and on-demand backups.
Directory where encrypted session backup files are written. Note: the default
path is on the same SD card as the live session — this protects against DB
corruption but not against SD failure. For real disaster recovery, point this
at an off-SD path (NFS, USB stick, etc.).
How many of the newest backup files to retain. Older files are deleted on
each rotation.
How often the periodic backup ticker runs, in addition to
POST /api/backup
on-demand triggers and the automatic post-link backup.Battery & status heartbeat
Path to the battery sidecar written by the power adapter (
adapters/power/).
The core is the only writer of status.json; the power adapter writes here
instead and the core merges this reading in on its heartbeat. Lives in tmpfs
by default — zero SD wear.How old a
battery.json reading can be before the core treats it as stale
(returns null for battery fields rather than showing an old value). Set to
4× the power adapter’s default 30s poll interval to tolerate a missed poll
or two without flickering.How often the core re-writes
status.json even when no event has occurred —
merges fresh sidecar readings and keeps updated_at current. Cheap: by
default status.json lives in tmpfs so this costs zero SD wear.Path to the discharge/charge trace CSV appended to by the power adapter. The
core only reads this file (
GET /api/battery/log) — it never writes it.
Uses the same variable name on both the Go and Python sides for consistency.Path to the face sidecar written by the display adapter. The display adapter
writes the live kaomoji face here; the core merges it into
status.json on
its heartbeat. Lives in tmpfs by default.How old a
face.json reading can be before the core treats it as stale
(returns null for the face field rather than showing an old value).
Defaults to 120s — the same as PIMYWA_BATTERY_MAX_AGE.Auto-reply bridge
AI bridge plugin for the auto-reply worker.
none disables auto-drafting
(chats in auto mode receive no automatic reply until a plugin is chosen).
direct-api uses the DeepSeek API.DeepSeek API key. Secret — never logged, never exposed in the agent’s MCP
context. Required when
PIMYWA_BRIDGE=direct-api.DeepSeek API base URL. Override to point at a compatible proxy or local model.
DeepSeek model name to use for auto-reply drafts.
Hard cap on total bridge API calls. Once reached the bridge stops calling the
API entirely — an anti-runaway-cost circuit breaker, not a soft warning.
How often the auto-reply worker sweeps pending auto-mode chats for new
messages that need a draft response.
Pacing between successive bridge API calls within a single sweep. This is
courtesy rate-limiting against a paid API, not a WhatsApp anti-ban delay.
Misc
Queue depth at which the resting mood switches from
few to swamped.
Messages 1 through PIMYWA_SWAMPED_AT give the few mood; more than that
gives swamped.How long the MCP server waits with no tool calls from a session before it
clears that session’s
agent_connected state.Override for the mDNS/footer hostname shown in
status.json and the
dashboard. When empty, the OS hostname with .local appended is used.Network interface queried for the current SSID via
iw dev <iface> link.
Adjust for boards that use a different interface name (e.g. wlp2s0 or
wlan1 with a USB dongle).Path to the editable decision-policy Markdown file. The MCP server loads this
at runtime — edit it live without recompiling. If the file does not exist,
the server falls back to its embedded default policy.