Skip to main content

System Architecture

Genie Helper is a multi-service platform that combines AnythingLLM, Directus CMS, Ollama, and Stagehand browser automation into a unified AI operations platform for content creators.

Architecture Overview

Service Layout

AnythingLLM

Port: 3001
PM2 Name: anything-llm
Role: Chat API, AI agent, embed widget
Files: server/, storage/

Directus CMS

Port: 8055
PM2 Name: agentx-cms
Role: Collections, auth, REST API
Files: cms/

Stagehand

Port: 3002
PM2 Name: stagehand-server
Role: Browser automation
Files: scripts/stagehand-mcp-server.mjs

Dashboard

Port: 3100
PM2 Name: genie-dashboard
Role: React SPA (serve dashboard/dist/)
Files: dashboard/

Media Worker

Port:
PM2 Name: media-worker
Role: BullMQ consumer (Redis)
Files: media-worker/

Collector

Port:
PM2 Name: anything-collector
Role: Document ingestion
Files: AnythingLLM collector scripts

Ollama

Port: 11434
PM2 Name: (system)
Role: Local LLM inference
Files: System service

MCP Servers (29 Tools Total)

Genie Helper uses the Model Context Protocol to give the AI agent access to three core systems:

Directus MCP (17 Tools)

Script: scripts/directus-mcp-server.mjs
  • list-collections — List all available collections
  • get-collection-schema — Get schema for a specific collection
  • read-items — Read multiple items from a collection
  • read-item — Read a single item by ID
  • create-item — Create a new item in a collection
  • update-item — Update an existing item
  • delete-item — Delete an item
  • search-items — Search items with filters
  • trigger-flow — Trigger a Directus Flow
  • get-me — Get current user info
  • list-users — List all users
  • get-user — Get a specific user
  • update-user — Update user details
  • create-user — Create a new user
  • list-files — List uploaded files
  • get-file — Get file details
  • list-flows — List all automation flows

Ollama MCP (3 Tools)

Script: scripts/ollama-mcp-server.mjs
  • generate — Generate text completions
  • chat — Interactive chat with model
  • list-models — List available local models

Stagehand MCP (9 Tools)

Script: scripts/stagehand-mcp-server.mjs
  • start-session — Initialize browser session
  • navigate — Navigate to URL
  • act — Perform browser action (click, type, etc.)
  • extract — Extract data from page
  • observe — Observe page state
  • close-session — Close browser session
  • set-cookies — Set browser cookies
  • get-cookies — Get browser cookies
  • screenshot — Capture screenshot

MCP Configuration

Config File: storage/plugins/anythingllm_mcp_servers.json
Auto-boot: Patched server/utils/boot/index.jsbootMCPServers() on startup

Data Layer (Directus Collections)

Genie Helper uses Directus as its primary data store with 11+ key collections:
All platform credentials are encrypted with AES-256-GCM using server/utils/credentialsCrypto.js before storage.

Action Runner System

The Action Runner is a middleware layer that intercepts special tags from the AI model’s output:

How It Works

1

Model Emits Action Tag

The AI model outputs: [ACTION:taxonomy-tag:{"media_id":123}] in its prose
2

Action Runner Intercepts

The action-runner plugin detects the tag and strips it from visible chat
3

Flow Execution

Looks up taxonomy-tag in action_flows collection and executes the steps JSON
4

Status Streaming

Streams execution status back to the chat interface in real-time
5

Audit Logging

Records execution to agent_audits (success/error/miss)

Available Actions

Media Worker (BullMQ)

The Media Worker is a BullMQ consumer that processes asynchronous jobs: Queues:
  • scrape-jobs — Profile scraping
  • media-jobs — Media processing
  • onboarding-jobs — User onboarding workflows
Job Types:

scrape_profile

Uses Stagehand to log into OnlyFans, extract stats and content, store in scraped_media

publish_post

Cross-platform posting via Stagehand browser automation

apply_watermark

ImageMagick-based image watermarking (100ms per operation)

create_teaser

FFmpeg video preview generation (~30s CPU per clip)

post_scheduler

Polls scheduled_posts every 60s and publishes ready posts
Worker File: media-worker/index.js
Redis Backend: Required for BullMQ job queue

Dashboard (React SPA)

Path: dashboard/
Stack: React 18 + Vite + Tailwind CSS + React Router v6
Doc Root: dashboard/dist/ served at geniehelper.com/

Routes

Public Routes:
  • / — Home
  • /pricing — Pricing plans
  • /about — About page
  • /register — Registration (invite-gated)
  • /login — Login
Authenticated Routes (/app/*):
  • /app/dashboard — Main dashboard
  • /app/media — Media library
  • /app/calendar — Post calendar
  • /app/fans — Fan management
  • /app/analytics — Performance analytics
  • /app/platforms — Platform connections
  • /app/settings — User settings
Admin Routes:
  • /admin — Directus + AnythingLLM iframes
  • /view-as — User impersonation

AI Chat Widget

AnythingLLM embed widget injected bottom-right on all /app/* routes:
  • Embed ID: cf54a9c0-224c-469d-b97b-5dc8095eac82 (Administrator workspace)
  • Greeting: Set via data-greeting attribute on script tag
  • Component: dashboard/src/components/AgentWidget/index.jsx
  • Trigger: window.__genieOpenChat()

API Proxies

Nginx Configuration:
  • /api/directus/http://localhost:8055
  • /api/llm/http://localhost:3001
Authentication:
  • Directus JWT (auto-refresh)
  • sessionStorage for impersonation tabs
Registration:
  • Invite-gated — Alpha invite code validated against AnythingLLM invite API

Data Flow Examples

Profile Scraping Flow

1

User Clicks 'Scrape Profile'

Dashboard sends POST to /api/queue/scrape-profile with creator_profile_id
2

Job Enqueued

BullMQ job created in scrape-jobs queue, record added to media_jobs
3

Media Worker Picks Up Job

Worker checks platform_sessions for encrypted cookies
4

Stagehand Session Started

If cookies exist: set-cookies + navigate to platform
If cookies missing: Create hitl_sessions record (yellow dashboard banner)
5

Data Extraction

Stagehand extract tool scrapes stats, content URLs, engagement metrics
6

Data Storage

Items created in scraped_media collection via Directus API
7

Job Completion

media_jobs record updated with status and result count

Content Classification Flow

1

User Asks 'Tag this content'

Chat message sent to AnythingLLM agent
2

Agent Emits Action

Model outputs: [ACTION:taxonomy-tag:{"media_id":123}]
3

Action Runner Intercepts

Looks up taxonomy-tag flow in action_flows collection
4

Step 1: Read Media

MCP call: directus:read-item from scraped_media
5

Step 2: AI Classification

MCP call: ollama:generate with scout-fast-tag model
6

Step 3: Update Tags

MCP call: directus:update-item with classified tags
7

Audit Log

Execution recorded in agent_audits collection

Security Architecture

Credential Encryption

File: server/utils/credentialsCrypto.js
Key Points:
  • AES-256-GCM encryption
  • No encryption keys in browser — all crypto is server-side only
  • Handles both new object format and legacy raw strings

Authentication Flow

  1. User logs in via /login (React form)
  2. Credentials sent to /api/directus/auth/login
  3. Directus returns JWT access token + refresh token
  4. Dashboard stores tokens in localStorage
  5. All API requests include Authorization: Bearer <token>
  6. Auto-refresh when access token expires

RBAC Synchronization

User roles are synced between Directus and AnythingLLM: Endpoint: server/endpoints/api/rbacSync.js
Webhook: Directus fires webhook on user create/update
Secret: RBAC_SYNC_WEBHOOK_SECRET validates webhook authenticity

Nginx Reverse Proxy

Plesk Users: All nginx changes via Plesk UI only. Never add location / — Plesk generates its own, duplicate causes startup failure.
Current proxy layout (full config in docs/nginx/geniehelper.com.vhost_nginx.conf):
Critical rules:
  • Sub-path locations (/app/, /api/llm/) and exact-match (= /path) are safe
  • SPA routing: error_page 404 =200 /index.html;
  • WebSocket: use "upgrade" literal for Connection header

Project Structure

Performance Considerations

Server Specs: $100/mo IONOS dedicated VPS, self-hosted
Resource Usage:
  • LLM inference: CPU-bound Qwen2.5 7B ~2-5s/call, ~4.8GB RAM pinned
  • Stagehand sessions: ~300MB RAM/active browser → ~33 concurrent sessions hard ceiling (10GB available)
  • FFmpeg clip generation: ~30s CPU per clip (real bottleneck)
  • Sharp/ImageMagick watermark: ~100ms (effectively zero cost → unlimited justified)
Scaling Limits:
  • Current Plesk VPS is CPU-only
  • dolphin3:8b and any >7B model will stall on CPU
  • Production upgrade: GPU VPS or stick with qwen-2.5:latest

Next Steps

Quick Start

Install and configure Genie Helper on your server

API Reference

Explore the Directus and AnythingLLM API endpoints

MCP Servers

Learn how to extend MCP servers with custom tools

Deployment

Production deployment best practices