Skip to main content

Architecture

thepopebot uses a two-layer architecture:

  1. Event Handler - Node.js server for webhooks, Telegram chat, and cron scheduling
  2. Docker Agent - Pi coding agent container for autonomous task execution
┌───────────────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Event Handler │ ──1──► │ GitHub │ │
│ │ (creates job) │ │ (job/* branch) │ │
│ └────────▲────────┘ └────────┬────────┘ │
│ │ │ │
│ │ 2 (triggers run-job.yml) │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────┐ │
│ │ │ Docker Agent │ │
│ │ │ (runs Pi, PRs) │ │
│ │ └────────┬────────┘ │
│ │ │ │
│ │ 3 (creates PR) │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────┐ │
│ │ │ GitHub │ │
│ │ │ (PR opened) │ │
│ │ └────────┬────────┘ │
│ │ │ │
│ │ 4a (update-event-handler.yml) │
│ │ 4b (auto-merge.yml) │
│ │ │ │
│ 5 (Telegram notification) │ │
│ └───────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────────┘

File Structure

/
├── .github/workflows/
│ ├── auto-merge.yml # Auto-merges job PRs (checks AUTO_MERGE + ALLOWED_PATHS)
│ ├── docker-build.yml # Builds and pushes Docker image to GHCR
│ ├── run-job.yml # Runs Docker agent on job/* branch creation
│ └── update-event-handler.yml # Notifies event handler on PR opened
├── .pi/
│ ├── extensions/ # Pi extensions (env-sanitizer for secret filtering)
│ └── skills/ # Custom skills for the agent
├── docs/ # Additional documentation
├── event_handler/ # Event Handler orchestration layer
│ ├── server.js # Express HTTP server
│ ├── actions.js # Shared action executor (agent, command, http)
│ ├── cron.js # Cron scheduler
│ ├── cron/ # Working directory for command-type cron jobs
│ ├── triggers.js # Webhook trigger middleware
│ ├── triggers/ # Working directory for command-type trigger scripts
│ ├── .env # Environment config (generated by setup)
│ ├── claude/ # Claude API integration
│ └── tools/ # Job creation, GitHub, Telegram utilities
├── operating_system/
│ ├── SOUL.md # Agent identity and personality
│ ├── CHATBOT.md # Telegram chat system prompt
│ ├── JOB_SUMMARY.md # Job summary prompt
│ ├── HEARTBEAT.md # Self-monitoring
│ ├── CRONS.json # Scheduled jobs
│ └── TRIGGERS.json # Webhook trigger definitions
├── setup/ # Interactive setup wizard
│ ├── setup.mjs # Main wizard script
│ └── lib/ # Helper modules
├── logs/ # Per-job directories (job.md + session logs)
├── Dockerfile # Container definition
├── entrypoint.sh # Startup script
└── SECURITY.md # Security documentation

Event Handler

The Event Handler is a Node.js Express server that provides orchestration capabilities.

API Endpoints

EndpointMethodAPI_KEYPurpose
/pingGETYHealth check, returns {"message": "Pong!"}
/webhookPOSTYGeneric webhook for job creation
/telegram/webhookPOSTNTelegram bot webhook (uses its own secret)
/telegram/registerPOSTYRegister Telegram webhook URL
/github/webhookPOSTNReceives notifications from GitHub Actions (uses its own secret)
/jobs/statusGETYCheck status of a running job

Examples:

Create a job via webhook:

curl -X POST http://localhost:3000/webhook \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"job": "Update the README with installation instructions"}'

Check job status:

curl "http://localhost:3000/jobs/status?job_id=abc123" \
-H "x-api-key: YOUR_API_KEY"

Register Telegram webhook:

curl -X POST http://localhost:3000/telegram/register \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"bot_token": "YOUR_BOT_TOKEN",
"webhook_url": "https://your-ngrok-url.ngrok-free.dev/telegram/webhook"
}'

Components

  • server.js - Express HTTP server handling all webhook routes
  • cron.js - Loads CRONS.json and schedules jobs using node-cron
  • triggers.js - Loads TRIGGERS.json and returns Express middleware for webhook triggers
  • claude/ - Claude API integration for Telegram chat with tool use
  • tools/ - Job creation, GitHub API, and Telegram utilities

GitHub Actions Workflows

WorkflowTriggerPurpose
docker-build.ymlPush to mainBuilds Docker image, pushes to GHCR
run-job.ymljob/* branch createdRuns Docker agent container
auto-merge.ymlPR opened from job/* branchChecks AUTO_MERGE + ALLOWED_PATHS, merges if allowed
update-event-handler.ymlAfter auto-merge.yml completesGathers job data and sends to event handler for Telegram notification

Flow:

  1. Event handler creates a job/uuid branch via GitHub API
  2. GitHub Actions detects branch creation → runs run-job.yml
  3. Docker agent executes task, commits results, creates PR
  4. auto-merge.yml runs → checks merge policy → squash merges (or leaves open)
  5. update-event-handler.yml runs → gathers job data → sends to event handler → Telegram notification

Docker Agent

The container executes tasks autonomously using the Pi coding agent.

Container includes:

  • Node.js 22
  • Pi coding agent
  • Playwright + Chromium (headless browser, CDP port 9222)
  • Git + GitHub CLI

Environment Variables:

VariableDescriptionRequired
REPO_URLYour repository URLYes
BRANCHBranch to work on (e.g., job/uuid)Yes
SECRETSBase64-encoded JSON with protected credentialsYes
LLM_SECRETSBase64-encoded JSON with LLM-accessible credentialsNo

Runtime Flow:

  1. Extract Job ID from branch name
  2. Start Chrome in headless mode
  3. Decode and export secrets (filtered from LLM's bash)
  4. Decode and export LLM secrets (accessible to LLM)
  5. Configure Git credentials
  6. Clone repository branch
  7. Run Pi with SOUL.md + job.md
  8. Commit all changes
  9. Create PR (auto-merge handled by auto-merge.yml workflow)

Session Logs

Each job gets its own directory at logs/{JOB_ID}/ containing both the job description (job.md) and session logs (.jsonl). These can be used to resume sessions or review agent actions.