markus — Automation Pipeline Core
All social media automations use this shared library. Supports multiple apps with two pipeline types:
- ai-generated — full pipeline: self-improve → AI post generation → scheduling → publishing
- manual — pre-built launches with
launchIdin queue; schedule only, no AI engine
Platform-specific behavior is defined in platforms.js (config registry) and app.json (per-app config). No per-platform scripts needed.
Quick Start
# 1. Clone and install git clone https://github.com/joshchoi4881/markus.git cd markus npm install # canvas is optional — only needed for visual formats (TikTok/Instagram slideshows). # If it fails to install, text-only formats still work fine. # To install canvas manually (requires system deps): # macOS: brew install pkg-config cairo pango libpng jpeg giflib librsvg && npm install canvas # Ubuntu: sudo apt install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev && npm install canvas # 2. Set up environment (pick one) # Option A: Shell script cp templates/load-env.example.sh load-env.sh # Edit load-env.sh, then: source load-env.sh # Option B: .env file cp templates/.env.example .env # Edit .env, then: source .env # 3. Pick a template and run setup node setup.js --list-templates node setup.js --template dropspace-content-engine # 4. Validate your setup source load-env.sh # or: source .env node scripts/test-pipeline.js --app myapp
Credentials
Required for all templates:
DROPSPACE_API_KEY— get from dropspace.dev/settingsANTHROPIC_API_KEY— for text generation
For visual/video formats (TikTok, Instagram):
FAL_KEY— for image/video generation via fal.ai
For clipper/slideshow templates (Google Drive access):
- Option A: Set
GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILEto your GWS credentials JSON path - Option B: Set
GWS_VAULT_PATHfor 1Password-based credential loading
For X/Twitter research + fact-checking (recommended):
- Bird CLI —
npm install -g @nicepkg/birdorbrew install steipete/formulae/bird - Export browser cookies:
BIRD_AUTH_TOKENandBIRD_CT0 - Used for: x-research cron (trending hooks) AND self-improve fact-checking (verifying claims about recent events/people before posting)
- Without Bird: x-research is skipped, and fact-checking falls back to web_search only (less current for Twitter-specific topics)
For Slack notifications (optional):
SLACK_BOT_TOKEN— Slack bot token (xoxb-...). Scripts send reports directly to each app's configured Slack channel after runs complete.- Configure
notifications.slackChannelin each app'sapp.jsonwith the target channel ID. - Without this: scripts still run fine, reports just go to stdout only (cron agent can still relay if configured).
App Configuration
All app config is centralized in ~/markus/apps/{app}/app.json.
Custom data directory: Set
APPS_DATA_ROOTto override the default~/markus/apps/location. All scripts use this for path resolution.
Example:
{
"name": "dropspace",
"pipelineType": "ai-generated",
"notifications": { "channel": "slack", "target": "YOUR_CHANNEL_ID" },
"skipDays": [],
"platforms": {
"tiktok": {
"enabled": true,
"postingTimes": ["08:00", "13:00", "18:00"],
"weekdaysOnly": false
}
},
"integrations": { "supabase": {}, "stripe": {}, "posthog": {} }
}Key fields:
- pipelineType:
ai-generatedormanual - notifications:
{channel, target}for cron delivery (supports slack, telegram, discord, etc.) - skipDays: Array of day numbers (0=Sunday, 6=Saturday) to skip all posting
Layout
~/markus/apps/
├── dropspace/ # App: Dropspace (ai-generated)
│ ├── app.json # App identity + integrations + platform config
│ ├── shared-failures.json # Cross-platform directive failure rules
│ ├── insights.json # Cross-platform strategy notes
│ ├── x-research-signals.json # Latest X research
│ ├── reports/ # Cross-platform analysis reports
│ ├── tiktok/
│ │ ├── strategy.json # Queue, notes (posting times in app.json)
│ │ ├── posts.json # Historical performance
│ │ ├── failures.json # Directive failure rules
│ │ ├── experiments.json # Format experiment tracking
│ │ ├── pending-batches.json # (visual only)
│ │ └── posts/ # Image assets
│ ├── instagram/
│ ├── facebook/
│ ├── twitter/
│ ├── linkedin/
│ └── reddit/
├── myapp/ # App: Your App
├── cache/ # Shared API response cache
└── node_modules/ # Shared deps (canvas)
Scripts
~/markus/
├── core/
│ ├── paths.js # Single source of truth for all path resolution
│ ├── platforms.js # Platform config registry (replaces 27 wrapper scripts)
│ ├── helpers.js # Timezone, JSON I/O, CLI parsing, referrer mapping
│ ├── api.js # Dropspace, Stripe, Supabase, PostHog, Sentry, GA4 API clients
│ ├── formats.js # Format registry (FORMATS + FORMAT_PLATFORMS) with generator types
│ │ # Generator types: ai-visual, ai-text, ai-video,
│ │ # drive-photos, drive-clips, manual
│ ├── correlations.js # Data-driven failure detection (replaces text failure rules)
│ ├── launch.js # Publish + verify + dequeue helpers
│ ├── media-gen.js # Image/video generation (fal, replicate, openai)
│ ├── overlay.js # Canvas text overlay
├── engines/
│ ├── self-improve-engine.js # Analytics + strategy optimization
│ ├── create-visual-post-engine.js # Image gen → overlay → compress → upload (TikTok, IG, FB)
│ ├── create-text-post-engine.js # Text post → upload (Twitter, LinkedIn, Reddit)
│ └── create-video-post-engine.js # Video post → Drive upload → Dropspace
├── scripts/
│ ├── schedule-day.js # Schedule all posts for the day in one pass
│ │ # Pre-configured posts: PATCH launchId with scheduled date
│ │ # AI-generated posts: run engine to create + schedule
│ ├── add-posts.js # Atomically add posts + strategy notes to queue
│ ├── run-x-research.js # X/Twitter research via Bird CLI
│ ├── run-self-improve-all.js # Run all ai-generated apps with auto-retry on failure
│ ├── cleanup-posts.js # Remove old post image assets
│ ├── cross-platform-report.js # Cross-platform analysis
│ ├── midnight-report.js # Data report for midnight ops
│ ├── init-app.js # Scaffold a new app (dirs + templates)
│ ├── daily-schedule-report.js # Today's schedule summary
│ ├── refresh-tracking.js # Pull analytics into TRACKING.md
│ ├── refresh-context.js # Refresh context files
│ ├── setup-crons.js # Print cron configuration
│ ├── list-templates.js # List available templates
│ └── test-pipeline.js # End-to-end pipeline test
├── docs/
│ ├── CRON_RULES.md # Self-healing protocol + pipeline architecture
│ └── ANTI-PATTERNS.md # Banned AI writing patterns
├── load-env.sh # Load env vars (copy from templates/load-env.example.sh)
└── README.md
Script Invocation
All scripts use --app and --platform (where applicable):
# Self-improve for a platform node engines/self-improve-engine.js --app dropspace --platform tiktok --days 14 # Create a visual post node engines/create-visual-post-engine.js --app dropspace --platform tiktok --next --schedule "2026-03-04T12:00:00Z" # Create a text post node engines/create-text-post-engine.js --app dropspace --platform twitter --next --schedule "2026-03-04T14:30:00Z" # Schedule all posts for the day node scripts/schedule-day.js --app dropspace # Add posts to queue echo '{"posts":[...], "notes":"...", "crossNotes":"..."}' | node scripts/add-posts.js --app dropspace --platform tiktok # Initialize a new app node scripts/init-app.js --app myapp --platforms tiktok,instagram,twitter
Daily Cron Flow (per app)
12:00 AM midnight → Monitoring, reports, maintenance, image cleanup
12:30 AM x-research → Bird CLI scans X → x-research-signals.json
1:00 AM self-improve-all → All ai-generated apps/platforms in one session. Analyze + generate posts + fact-check via web_search/bird.
2:00 AM schedule-day → Create all posts via Dropspace
ai-generated: run engines on-demand
manual: PATCH launchId with scheduled date
7AM-7PM Dropspace publishes → Webhook → Slack report
Ongoing Analytics cron → Detects post deletions → post.deleted webhook → Slack
Adding a New App
# 1. Scaffold node ~/markus/scripts/init-app.js --app myapp --platforms tiktok,instagram,twitter # 2. Configure vim ~/markus/apps/myapp/app.json # Fill in: pipelineType, notifications, skipDays, integrations, posting times # 3. Add crons (stagger times so they don't overlap with existing apps)
Pre-configured Pipeline Flow
For apps with pipelineType: "manual" (e.g. Community Events):
- Queue entries are added with a
launchId— the launch already exists in Dropspace (e.g. created by the clipper skill) schedule-day.jsPATCHes each launch with ascheduled_dateinstead of running an AI engineself-improve-engine.jsis skipped (no AI content generation needed)- Analytics still flow back via Dropspace webhooks → posts.json
Framework Setup Guides
See frameworks/ for install instructions tailored to specific AI tools: OpenClaw, Claude Code, Cursor, and Manus.