OMP Discord Bot Integration & Lifecycle

The OMP Discord Bot (pi-discord-remote) provides a bidirectional bridge allowing authorized developers and content editors to interact with and steer active Oh My Pi (OMP) agent sessions directly from a private Discord guild.

This page serves as the Single Source of Truth (SSOT) for the architecture, process management, security, and operation of this service.


1. Core Mandate: Reboot-Survivability & Service Assurance

Because this platform operates on a Plesk-hosted environment under a non-root system user (user_freundeskreis.family), we do not have passwordless sudo rights. System-wide systemd services and Docker daemons are therefore unavailable or heavily restricted.

To guarantee that the OMP Discord Bot is always online and survives server reboots, we implement a systemd user service with lingering:

  1. User lingering (loginctl enable-linger): This is enabled (Linger=yes for the system user). It instructs the host operating system to spawn a persistent user systemd manager instance (systemd --user) immediately on boot, running even when no SSH session is active.
  2. Systemd User Unit: Managed via ~/.config/systemd/user/omp-discord.service. It hooks into systemd’s boot targets (default.target) and automatically spawns the bot wrapper.
  3. PTY (Pseudo-Terminal) Virtualization: The OMP engine and pi-discord-remote plugin require an interactive terminal (PTY) to initialize prompt sessions. Running raw binaries as background processes fails. We wrap OMP inside a detached GNU Screen instance (/usr/bin/screen -DmS omp-discord ...) to virtualize the PTY.
  4. Crash Recovery: Managed by systemd with Restart=always and a 10s backoff.
       [ Server Boot ]
              │
      (systemd PID 1)
              │
  [ Spawns systemd --user ]   <-- Enabled by loginctl linger
              │
   [ Starts omp-discord ]     <-- default.target hook
              │
     [ /usr/bin/screen ]      <-- Virtualizes PTY
              │
    [ omp-discord-bot ]       <-- Shell wrapper (injects Env & Path)
              │
    [ OMP Engine (v16) ]      <-- Loads pi-discord-remote plugin

2. In-Depth Options & Architecture Trade-Offs

Below is a systematic comparison of daemon hosting architectures evaluated for this host.

A. Systemd User Service with Linger (Chosen Perfect Option)

  • Mechanics: Configured via ~/.config/systemd/user/omp-discord.service. Uses standard systemd lifecycle control.
  • PTY Handling: Wrapped via screen -DmS.
  • Pros:
    • Integrates with system log daemon (journalctl --user).
    • Full user-space independence (zero root/sudo required).
    • Auto-restarts on crash and survives reboots natively.
  • Cons: Requires screen/tmux for PTY virtualization, which can leave orphaned sessions if not cleanly killed (prevented by ExecStop configuration).

B. System-Wide Systemd Service

  • Mechanics: Unit file under /etc/systemd/system/ managed by PID 1.
  • Pros: Deepest OS-level integration.
  • Cons: IMPOSSIBLE on this host. Non-root user has no write access to system directories and no sudo privilege.

C. PM2 (Process Manager 2)

  • Mechanics: Node.js process supervisor.
  • Pros: Rich metrics console, automated log rotation, clustering.
  • Cons:
    • Configuring PM2 to run on boot (pm2 startup) requires root.
    • Running in user space requires launching a secondary supervisor (via cron @reboot pm2 resurrect or systemd), introducing redundant supervisor nesting.
    • Overhead of a persistent Node.js watcher process.

D. Docker Container

  • Mechanics: Isolating the bot inside a container with --restart always.
  • Pros: Sandbox execution.
  • Cons:
    • No access to the host Docker daemon under this Plesk subscription.
    • OMP must read and edit the TYPO3 codebases and file repositories located in /var/www/vhosts/freundeskreis.family/httpdocs/. Bridging these volumes to a Docker container introduces complex permission and mounting overheads.

E. Cron @reboot with Screen/Tmux

  • Mechanics: Crontab entry: @reboot screen -DmS omp-discord ~/.local/bin/omp-discord-bot.
  • Pros: Zero-dependency, lightweight, easy to understand.
  • Cons: No process watchdog (stays dead if it crashes post-boot), no log management, and no graceful shutdown.

Options Decision Matrix

ParameterA. systemd —userB. systemd SystemC. PM2D. DockerE. Cron @reboot
Plesk Feasibility5/5 (Native)1/5 (Blocked)2/5 (No Sudo)1/5 (Blocked)5/5 (Native)
Crash Recovery5/5 (Native)5/5 (Native)5/5 (Native)5/5 (Native)1/5 (None)
PTY Suitability4/5 (via Screen)4/5 (via Screen)3/5 (Needs hack)3/5 (Needs hack)4/5 (via Screen)
Logging / Ops5/5 (Journald)5/5 (Journald)5/5 (PM2 logs)4/5 (Docker logs)1/5 (Raw file)
Maintenance5/5 (Standard)5/5 (Standard)3/5 (Supervisor)2/5 (Isolate)3/5 (Brittle)
Total Score24/25 (Winner)20/2518/2515/2514/25

3. OMP Plugin Subsystem Mechanics (omp plugin)

OMP manages extensions using a structured plugin controller. The omp plugin CLI command regulates installation, updates, and options.

A. CLI Commands Reference

  • omp plugin list:
    • Queries and lists all loaded packages.
    • Active on this host:
      • ● @mporenta/pi-discord-remote@0.3.11 (provides this Discord bridge).
      • ● pi-langfuse@1.4.3 (provides OpenTelemetry tracing).
  • omp plugin doctor:
    • Assures filesystem health, checks manifest integrity (package.json), and verifies dynamic module resolutions.
  • omp plugin features <plugin>:
    • Lists or toggles optional feature sets inside a plugin (e.g. --enable trace_all or --disable debug_verbose).
  • omp plugin config <action> <plugin> [key] [value]:
    • Actions: list, get, set, delete, validate.
    • Modifies settings schema registered by a plugin in the OMP local store.
    • (Note: @mporenta/pi-discord-remote bypasses this schema in favor of reading raw environment variables from .env.discord for bootstrap speed).
  • omp plugin install <package>:
    • Installs a plugin from npm, local directory, or git.
    • Flags: --scope=user (installs to ~/.omp/plugins/), --dry-run, --force.
  • omp plugin link <path>:
    • Symlinks a local extension codebase to the plugins folder for development.

B. Plugin Lifecycle Hooks

  1. Pre-load: OMP parses ~/.omp/plugins/package.json to resolve packages.
  2. ESM Import: OMP dynamically imports the plugin’s entry files.
  3. Event Hooks:
    • OMP plugins register handlers on the OMP event bus:
      • turn_start / turn_end: Triggered when an agent begins or ends executing a task.
      • assistant_message: Fires on every stream token emitted by the LLM.
      • tool_call / tool_result: Intercepts tool usage parameters and output payloads.
    • pi-discord-remote taps assistant_message to stream tokens to Discord, and pipes inbound Discord chat into OMP’s stdin queue using pi.sendUserMessage(...).
    • pi-langfuse hooks into the trace events and exports OpenTelemetry spans to the Langfuse backend. Both plugins function in parallel without conflict.

4. Operational Configuration

A. The systemd Service: ~/.config/systemd/user/omp-discord.service

[Unit]
Description=OMP Discord Bot (pi-discord-remote)
After=network-online.target
Wants=network-online.target
 
[Service]
Type=simple
# Run OMP inside screen so it gets a PTY (the discord extension needs session_start)
ExecStart=/usr/bin/screen -DmS omp-discord %h/.local/bin/omp-discord-bot
ExecStop=-/usr/bin/screen -S omp-discord -X quit
# Environment
Environment=HOME=%h
Environment=TERM=xterm-256color
WorkingDirectory=%h/httpdocs
 
# Restart policy: always restart with backoff
Restart=always
RestartSec=10
 
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=omp-discord
 
[Install]
WantedBy=default.target

(Notice the ExecStop=- prefix. The minus sign tells systemd to ignore the exit code of the screen cleanup command, preventing the service from transitioning into a failed state if the screen session was already closed).

B. The Daemon Wrapper: ~/.local/bin/omp-discord-bot

#!/usr/bin/env bash
# omp-discord-bot — keeps an OMP session alive so pi-discord-remote stays connected.
# Designed for systemd: restarts automatically on crash.
set -euo pipefail
 
# Source profile for PATH, NODE_PATH, BUN_INSTALL, PI_DISCORD_ENV_FILE
[ -f "$HOME/.profile" ] && . "$HOME/.profile"
 
export PI_DISCORD_ENV_FILE="${PI_DISCORD_ENV_FILE:-$HOME/.env.discord}"
 
# Working directory for the OMP session
OMP_CWD="${OMP_CWD:-/var/www/vhosts/freundeskreis.family/httpdocs}"
 
exec omp \
  --cwd "$OMP_CWD" \
  --allow-home \
  --no-title \
  --approval-mode yolo \
  --no-session \
  "$@"

5. Security & Isolation Hardening Checklist

Because the Discord bot links directly to OMP (which executes shell commands and edits filesystem assets), allowlisted Discord users gain equivalent capabilities to ssh access.

  • Private Bot Application: The Discord bot token belongs to a dedicated application in the Discord Developer portal.
  • Isolated Server Guild: The bot is invited only to a private guild, not shared servers.
  • Privileged Intents Enabled: Message Content Intent is explicitly enabled in the Discord Developer panel.
  • Explicit Allowlist: PI_DISCORD_USER_IDS is populated in .env.discord with specific developer Snowflake IDs. The plugin will refuse to start if this is empty.
  • Secret Isolation: All credentials (bot token, user lists) live in /var/www/vhosts/freundeskreis.family/.env.discord, which is heavily protected by .htaccess rules and excluded from git versioning.

6. Maintenance & Troubleshooting Cheatsheet

Routine Administration

# Check the status of the background daemon
systemctl --user status omp-discord
 
# Restart the bot (required to apply changes in .env.discord)
systemctl --user restart omp-discord
 
# Stop the daemon
systemctl --user stop omp-discord
 
# View real-time logs
journalctl --user -u omp-discord -n 100 -f
 
# Verify that the screen session is active
screen -ls

Common Issue Resolution

1. “No screen session found” on Stop

  • Diagnosis: The OMP process exited before the systemd stop command executed.
  • Remedy: This is normal behavior and is safely handled by the ExecStop=- configuration. No action is required.

2. Bot is offline but Service is active

  • Diagnosis: OMP may be running but unable to connect to the Discord API due to network timeouts, rate limits, or an invalid token.
  • Remedy: Check the logs using journalctl --user -u omp-discord -n 50. If the bot token is invalid, retrieve a new one from the Discord developer console, paste it into ~/.env.discord, and run systemctl --user restart omp-discord.

3. Subdomain not responding

  • Diagnosis: Subdomain q.freundeskreis.family requires lingering active on the user session.
  • Remedy: Run loginctl show-user $(whoami) | grep Linger. If it displays Linger=no, request the server admin to run sudo loginctl enable-linger user_freundeskreis.family.