Skip to content

Repository files navigation

Numen

Content, animated by AI.

CILicense: MITPHPLaravelVersion

AI-first headless CMS. You write briefs. AI writes content.

Instead of opening a text editor, you describe what you need. A pipeline of AI agents handles generation, SEO optimization, and quality review — then publishes automatically (or waits for human sign-off if you want it). Every frontend gets a clean REST API.


How It Works

Traditional CMS: human opens editor → writes content → hits publish.

Numen: you submit a brief → pipeline runs in the background → content appears.

Brief
└─► Content Creator (claude-sonnet-4-6) — writes the article
└─► AI Illustrator (multi-provider) — generates hero image from content
└─► SEO Expert (claude-haiku-4-5-20251001) — optimizes metadata & keywords
└─► Editorial Director (claude-opus-4-6) — quality gate (score ≥ 80 → publish)
└─► Auto-Publish — goes live automatically

Each stage is a queued job. The pipeline is event-driven. Stages are defined in DB — add, remove, or reorder without deploying code. You can plug in a human_gate stage anywhere to pause for manual review.



Features

AI Content Quality Scoring

New in v0.10.0. Automated multi-dimensional content quality analysis across five dimensions:

  • Readability — Flesch-Kincaid metrics, sentence and word complexity
  • SEO — Keyword density, heading structure, meta optimization
  • Brand Consistency — LLM-powered brand voice and tone analysis
  • Factual Accuracy — Cross-referenced claim validation
  • Engagement Prediction — AI-predicted engagement score

Features: real-time score ring in the editor sidebar, quality dashboard with Chart.js trend visualization, space leaderboard, configurable pipeline quality gates, auto-score on publish, and a quality.scored webhook event.

Content Generation Pipeline

Submit a brief → AI agents generate, illustrate, optimize, and quality-gate content → auto-publish or human review.

Conversational CMS

New in v0.9.0. Talk to your CMS — create content, run pipelines, query data, all via natural language.

  • Natural language admin: describe what you want, the AI figures out the action
  • Intent routing to real CMS operations: create, update, delete, publish, query, pipeline trigger
  • Real-time SSE streaming with typed chunks (text, intent, action, confirm, error, done)
  • Confirmation flow for destructive actions — nothing irreversible without your approval
  • Sliding-window + summarization context management for long conversations
  • Per-user rate limiting (20 req/min) and daily cost budget (configurable)
  • Context-aware suggestion chips based on current UI route

AI Content Repurposing Engine

New in v0.8.0. One-click content repurposing to 8 formats:

  • Twitter thread, LinkedIn post, Newsletter section, Instagram caption
  • Podcast script outline, Product page copy, FAQ section, YouTube description
  • Tone-aware & brand-consistent via Persona/LLM system
  • Batch repurposing (50 items) + cost estimation
  • Staleness detection (auto-repurpose when source updates)
  • Custom format templates per space

AI-Powered Content Knowledge Graph

New in v0.9.0. Automatically maps relationships between content items into an interactive knowledge graph:

  • 5 edge types: Semantic similarity, shared tags, co-author, series order, shared named entities
  • Topic clustering: Groups content into named topic clusters using AI embeddings
  • Content gap analysis: Surfaces under-covered topics with opportunity scores and suggested titles
  • D3.js visualization: Force-directed interactive graph in Numen Studio — nodes by cluster, edges by weight
  • Related content widget: for headless frontend sidebars
  • 7 REST endpoints: Related, clusters, cluster contents, gaps, path, node metadata, reindex

Multi-Provider AI

Swap between Anthropic, OpenAI, Azure OpenAI, Together AI — no code changes. Fallback chain auto-retries on rate limits.

Multi-Provider Image Generation

OpenAI, Together AI, fal.ai, Replicate — choose the best model for your brand. Images auto-download and link to content.

RBAC with AI Governance

Role-based access control (Admin, Editor, Author, Viewer) with space-scoped permissions, AI budget limits, and immutable audit logs.

Webhooks Admin UI

Manage webhook endpoints and event subscriptions directly from the admin panel (Settings → Webhooks). Create, edit, delete endpoints; select event subscriptions; view delivery logs; rotate signing secrets; and manually redeliver webhooks (rate-limited to 10/minute per user).

CLI for Automation

8 commands for content, briefs, and pipeline management — perfect for CI/CD hooks and server-side workflows.

GraphQL API Layer

New in v0.9.0. A full-featured GraphQL API powered by Lighthouse PHP.

  • Endpoint:POST /graphql — all Numen resources in one schema
  • 20+ types with cursor-based pagination (Relay-spec)
  • Mutations for content, briefs, media, and pipeline operations
  • Real-time subscriptions for content events and pipeline progress
  • Automatic Persisted Queries (APQ), complexity scoring, field-level caching
  • GraphiQL explorer at /graphiql for interactive development
  • See docs/graphql-api.md for the full guide

AI Pipeline Templates & Preset Library

New in v0.10.0. Reusable AI pipeline templates for accelerated content creation workflows.

Features:

  • 8 built-in templates: Blog Post Pipeline, Social Media Campaign, Product Description, Email Newsletter, Press Release, Landing Page, Technical Documentation, Video Script
  • Template library API: Browse, rate, and install templates from community library
  • Space-scoped templates: Custom templates per content space with RBAC
  • One-click install wizard: Auto-configures personas, stages, and variables from template schema
  • Template versioning: Version management with changelog and rollback support
  • Template packs: Plugin-registered template collections with metadata
  • Plugin hooks:registerTemplateCategory() and registerTemplatePack() for extending the library
  • Template ratings: Community feedback and quality metrics

Endpoints:

  • GET /api/v1/spaces/{space}/pipeline-templates — List templates
  • POST /api/v1/spaces/{space}/pipeline-templates — Create custom template
  • POST /api/v1/spaces/{space}/pipeline-templates/{template}/publish — Publish template
  • POST /api/v1/spaces/{space}/pipeline-templates/{template}/versions — Create new version
  • POST /api/v1/spaces/{space}/pipeline-templates/installs/{version} — Install template
  • POST /api/v1/spaces/{space}/pipeline-templates/{template}/ratings — Rate template

See docs/pipeline-templates.md for the complete feature guide.

Plugin & Extension System

First-class plugin architecture. Extend pipelines, register custom LLM providers, add admin UI, and react to content events — all from a self-contained plugin package.

Architecture

┌─────────────────────────────────────────────────────────────┐
│ Admin UI │
│ Inertia.js + Vue 3 (SPA) │
└────────────────────────┬────────────────────────────────────┘
│
┌────────────────────────▼────────────────────────────────────┐
│ Laravel 12 App │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │
│ │ REST API │ │ Pipeline │ │ AI Agents │ │
│ │ /api/v1/* │ │ Engine │ │ + LLM Manager │ │
│ └──────────────┘ └──────┬───────┘ └────────┬────────┘ │
│ │ │ │
│ ┌───────▼──────┐ ┌─────────▼────────┐ │
│ │ Queue Jobs │ │ Provider Layer │ │
│ │ (Redis) │ │ Anthropic │ │
│ └──────────────┘ │ OpenAI │ │
│ │ Azure OpenAI │ │
│ │ Together AI │ │
│ │ fal.ai │ │
│ │ Replicate │ │
│ ┌──────────────┐ ┌───────────────┐ └──────────────────┘ │
│ │ SQLite/MySQL│ │ Media Assets │ │
│ │ (content DB)│ │ (AI images) │ │
│ └──────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────┘

Key design decisions:

  • Provider abstraction — swap Anthropic ↔ OpenAI ↔ Azure without touching pipeline code. Fallback chain auto-retries on rate limits.
  • Multi-provider image generation — Four image providers supported: OpenAI (GPT Image 1.5 / DALL-E 3), Together AI (FLUX models), fal.ai (FLUX / SD3.5 / Recraft), and Replicate (any model). An ImagePromptBuilder (powered by Haiku) crafts optimized prompts from content metadata; images are downloaded, stored as MediaAsset records, and attached to content. The active provider is configured per-persona via generator_provider / generator_model.
  • Media Library & Digital Asset Management — Organize media assets into folders and collections with drag-and-drop upload. Automatic metadata extraction (MIME, dimensions, file size), optional AI auto-tagging via Claude vision, and image editing (crop/rotate/resize). Automatic variant generation (thumbnail, medium, large) for web delivery. Public headless API (/v1/public/media) for CDN edge caching; full REST API with Sanctum auth. MediaPicker Vue component for seamless integration with content editor. Usage tracking prevents accidental deletion of in-use assets.
  • RBAC with AI governance — role-based access control (Admin, Editor, Author, Viewer) with space-scoped permissions, AI budget limits per role, and immutable audit logs. Tokens inherit a subset of user permissions. No external dependencies — Numen's own implementation.
  • Pipeline-as-config — stages defined in DB, not hardcoded. Add/remove/reorder stages without deploying code. Supports human_gate stages for manual review checkpoints.
  • Block-based content — every piece of content is a collection of typed ContentBlock records. Flexible for headless delivery.
  • Full provenance — every AI call logged (AIGenerationLog) with model, tokens, cost, and which pipeline stage triggered it. Image generation costs tracked per asset. Audit logs track all sensitive actions (publish, role assignment, AI generation, etc.).

Stack

LayerTech
BackendPHP 8.4, Laravel 12
Frontend (admin)Inertia.js, Vue 3
AuthLaravel Sanctum (API tokens)
QueueRedis (or database for dev)
DatabaseSQLite (dev), MySQL (prod)
AI providers (text)Anthropic, OpenAI, Azure OpenAI
AI providers (image)OpenAI, Together AI, fal.ai, Replicate

Quick Start

You need PHP 8.4, Composer, Node.js 18+, and Redis (or switch to QUEUE_CONNECTION=database). An Anthropic API key is required minimum — OpenAI and Azure are optional.

# 1. Clone
git clone https://github.com/byte5labs/numen.git
cd numen
# 2. Install dependencies
composer install
npm install
# 3. Configure
cp .env.example .env
php artisan key:generate

Open .env and set your API key:

ANTHROPIC_API_KEY=sk-ant-your-key-here
# 4. Database
touch database/database.sqlite
php artisan migrate
# 5. Seed demo data (creates a Space, Personas, and a pipeline)
php artisan db:seed --class=DemoSeeder
# 6. Start everything (three terminals)
php artisan serve # → http://localhost:8000
php artisan queue:work # processes pipeline jobs
npm run dev # Vite (admin UI hot-reload)

That's it. Hit http://localhost:8000 for the admin UI.

For dev without Redis, add QUEUE_CONNECTION=database to .env and run php artisan queue:table && php artisan migrate first.


Create Your First Content

Get an API token from the admin UI (Settings → API Tokens), then:

# Submit a brief — this kicks off the full pipeline
curl -X POST http://localhost:8000/api/v1/briefs \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{ "space_id": "YOUR_SPACE_ID", "title": "10 Reasons to Use a Headless CMS in 2026", "description": "A developer-focused blog post covering performance, flexibility, and DX benefits of headless architecture", "content_type_slug": "blog_post", "target_keywords": ["headless cms", "jamstack", "api-first"], "priority": "high" }'# → Returns a pipeline_run_id. Poll it for status:
curl http://localhost:8000/api/v1/pipeline-runs/PIPELINE_RUN_ID \
-H "Authorization: Bearer YOUR_TOKEN"

Watch the queue worker terminal — you'll see each stage fire in sequence. Content is auto-published if the Editorial Director scores it ≥ 80.


CLI Reference

Numen ships a full artisan-based CLI for server-side automation, scripted workflows, and CI/CD integration.

Security note: The CLI runs with full application privileges. Restrict server access accordingly — CLI is not intended for untrusted users.

Installation

The CLI is available automatically via artisan once the app is installed:

php artisan list numen

Commands

numen:status — System Health Check

# Quick health overview
php artisan numen:status
# With AI provider model details
php artisan numen:status --details

Shows: database connectivity, content stats, cache, queue driver, and AI provider configuration.


numen:content:list — List Content

# List all content (latest 20)
php artisan numen:content:list
# Filter by type and status
php artisan numen:content:list --type=blog_post --status=published --limit=50

numen:content:import — Bulk Import from JSON

# Import from file
php artisan numen:content:import --file=storage/exports/content.json
# Preview without writing (dry run)
php artisan numen:content:import --file=storage/exports/content.json --dry-run
# Import into specific space
php artisan numen:content:import --file=content.json --space-id=<uuid>

Import file format (JSON array):

[
{
"slug": "my-first-article",
"title": "My First Article",
"content_type": "blog_post",
"status": "draft",
"locale": "en",
"excerpt": "A short summary of the article.",
"body": "Full article body in HTML or Markdown.",
"seo_data": {
"meta_title": "My First Article | Numen",
"meta_description": "A short summary."
}
}
]

Valid status values: draft, published, archived (invalid values default to draft).


numen:content:export — Export to JSON or Markdown

# Export all content to storage/exports/ (default)
php artisan numen:content:export
# Export as Markdown to a specific file
php artisan numen:content:export --format=markdown --output=/tmp/export.md
# Filter by type and status
php artisan numen:content:export --type=blog_post --status=published
# Export a single item by ID
php artisan numen:content:export --id=<uuid>

When --output is omitted, exports default to storage/exports/<timestamp>.json.


numen:brief:create — Create a Content Brief

# Create a brief and trigger the pipeline
php artisan numen:brief:create --title="10 Tips for Laravel Performance"# Full options
php artisan numen:brief:create \
--title="SEO Guide 2026" \
--type=guide \
--persona=seo-expert \
--priority=high \
--keywords=laravel --keywords=performance \
--description="Comprehensive SEO guide for developers"# Create without running the pipeline
php artisan numen:brief:create --title="Draft Idea" --no-run

Valid --priority values: low, normal, high, urgent (invalid values default to normal).


numen:brief:list — List Briefs

# List latest 20 briefs
php artisan numen:brief:list
# Filter by status and space
php artisan numen:brief:list --status=pending --limit=50

numen:pipeline:run — Trigger Pipeline Run

# Run the active pipeline for a brief
php artisan numen:pipeline:run --brief-id=<uuid># Run a specific pipeline
php artisan numen:pipeline:run --brief-id=<uuid> --pipeline-id=<uuid>

numen:pipeline:status — Check Pipeline Status

# Show recent pipeline runs
php artisan numen:pipeline:status
# Show only running pipelines
php artisan numen:pipeline:status --running
# Show more history
php artisan numen:pipeline:status --limit=50

API Reference

Authentication

Public read endpoints require no auth. Management endpoints use Sanctum bearer tokens.

-H "Authorization: Bearer YOUR_TOKEN"

The full OpenAPI 3.1.0 specification is available at GET /api/documentation.

Rate limits (public endpoints): 60 requests/minute for content and pages; 30 requests/minute for component types.

Content Delivery (public)

# List published content
curl http://localhost:8000/api/v1/content
# Get by slug
curl http://localhost:8000/api/v1/content/my-article-slug
# Filter by content type
curl http://localhost:8000/api/v1/content/type/blog_post
# Filter by taxonomy
curl "http://localhost:8000/api/v1/content?taxonomy[categories]=laravel&taxonomy[tags]=tutorial"# List pages
curl http://localhost:8000/api/v1/pages
# Get page by slug
curl http://localhost:8000/api/v1/pages/about
# List taxonomy vocabularies
curl http://localhost:8000/api/v1/taxonomies
# Browse term tree
curl http://localhost:8000/api/v1/taxonomies/categories
# Content by term
curl http://localhost:8000/api/v1/taxonomies/categories/terms/laravel/content

Content Management (authenticated)

# Create a brief (starts the pipeline)
curl -X POST http://localhost:8000/api/v1/briefs \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"space_id":"...","title":"...","description":"...","content_type_slug":"blog_post"}'# List briefs
curl http://localhost:8000/api/v1/briefs \
-H "Authorization: Bearer TOKEN"# Check pipeline status
curl http://localhost:8000/api/v1/pipeline-runs/RUN_ID \
-H "Authorization: Bearer TOKEN"# Approve a human-gate stage
curl -X POST http://localhost:8000/api/v1/pipeline-runs/RUN_ID/approve \
-H "Authorization: Bearer TOKEN"# List active personas
curl http://localhost:8000/api/v1/personas \
-H "Authorization: Bearer TOKEN"# Cost analytics (last 100 day-model-purpose groups)
curl http://localhost:8000/api/v1/analytics/costs \
-H "Authorization: Bearer TOKEN"

Component Types (headless page builder)

# List registered component types
curl http://localhost:8000/api/v1/component-types
# Get specific type schema
curl http://localhost:8000/api/v1/component-types/hero_banner

Webhooks

Webhooks enable real-time event delivery to external systems. Subscribe to events like content publication, pipeline completion, or media uploads, and receive signed HTTP POST requests when they occur.

Overview

A webhook is a URL endpoint + event filter you configure in Numen. When a subscribed event fires, Numen serializes it into a JSON payload, signs it with HMAC-SHA256, and delivers it asynchronously to your endpoint with automatic retries.

Key features:

  • Event subscriptions — Choose which events trigger deliveries (e.g., content.published, pipeline.completed, or * for all)
  • HMAC-SHA256 signing — Every delivery includes an X-Numen-Signature header. Verify it consumer-side to ensure authenticity.
  • Secure secrets — Webhook secrets are encrypted at rest; never logged or exposed in API responses.
  • Audit trail — Every delivery (attempt, success, failure) is recorded and queryable.
  • Automatic retries — Failed deliveries retry with exponential backoff (3 attempts, 60+ seconds apart).
  • Rate limiting — 60 webhook creations/minute per space; 10 manual redelivery attempts/minute per webhook.
  • SSRF protection — URLs are validated to prevent Server-Side Request Forgery (private IP ranges blocked).

Event Catalog

Subscribe to one or more events. Wildcards supported: content.*, pipeline.*, media.*, user.*, or * (all events).

EventPayload ContainsFired When
content.publishedcontent_id, space_id, title, content_type, published_at, versionContent item published (either directly or after pipeline approval)
content.updatedcontent_id, space_id, title, content_type, versionContent metadata updated (title, type, tags, etc.)
content.deletedcontent_id, space_idContent permanently deleted
pipeline.startedpipeline_id, space_id, run_idNew pipeline run initiated
pipeline.completedpipeline_id, space_id, run_id, ai_score, completed_atPipeline run finished successfully
pipeline.failedpipeline_id, space_id, run_id, stage, completed_atPipeline run failed at a stage
media.uploadedasset_id, space_id, filename, mime_type, urlMedia asset uploaded
media.processedasset_id, space_id, filename, mime_type, urlMedia processed (image generated, etc.)
media.deletedasset_id, space_id, filenameMedia asset deleted
user.createduser_id, space_idUser added to space
user.updateduser_id, space_idUser permissions changed
user.deleteduser_id, space_idUser removed from space

Webhook Payload Format

Every webhook POST includes:

{
"id": "evt_abc123def456",
"event": "content.published",
"timestamp": "2026-03-15T11:30:45.000Z",
"data": {
"content_id": "ctn_xyz789",
"space_id": "spc_001",
"title": "My First Article",
"content_type": "blog_post",
"published_at": "2026-03-15T11:30:00.000Z",
"version": 2
}
}

Headers included in every delivery:

  • Content-Type: application/json
  • X-Numen-Event: content.published (event type)
  • X-Numen-Delivery: <deliveryId> (delivery record ID for audit trail)
  • X-Numen-Signature: sha256=<hmac> (HMAC-SHA256 signature)
  • Any custom headers you configure on the webhook

HMAC Signature Verification

Verify every incoming webhook by recomputing the HMAC and comparing it to the header.

PHP Example:

<?php// Get the signature from headers$signature = $_SERVER['HTTP_X_NUMEN_SIGNATURE'] ?? '';
// Get the raw request body (BEFORE json_decode!)$body = file_get_contents('php://input');
// Get your webhook secret (stored securely)$secret = env('NUMEN_WEBHOOK_SECRET');
// Compute expected signature
[$algo, $hash] = explode('=', $signature);
$computed = hash_hmac($algo, $body, $secret);
// Constant-time comparison to prevent timing attacksif (!hash_equals($hash, $computed)) {
http_response_code(401);
die('Unauthorized: Invalid signature');
}
// Safe to process$payload = json_decode($body, true);
echo"✓ Event received: {$payload['event']}\n";

JavaScript (Node.js) Example:

importcryptofrom'crypto';importexpressfrom'express';constapp=express();constsecret=process.env.NUMEN_WEBHOOK_SECRET;app.post('/webhook',express.json({verify: (req,res,buf)=>{constsignature=req.get('x-numen-signature');const[algo,hash]=signature.split('=');constcomputed=crypto.createHmac(algo,secret).update(buf).digest('hex');if(!crypto.timingSafeEqual(hash,computed)){thrownewError('Unauthorized: Invalid signature');}}}),(req,res)=>{console.log(`✓ Event received: ${req.body.event}`);res.json({success: true});});app.listen(3000);

Quick Setup Example

Create a webhook via API:

curl -X POST http://localhost:8000/api/v1/webhooks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "space_id": "spc_001", "url": "https://my-app.example.com/webhooks/numen", "events": ["content.published", "pipeline.completed"], "is_active": true, "headers": { "X-Custom-Header": "my-value" } }'

Response:

{
"data": {
"id": "wbk_abc123",
"space_id": "spc_001",
"url": "https://my-app.example.com/webhooks/numen",
"events": ["content.published", "pipeline.completed"],
"is_active": true,
"secret": "wbk_secret_long_random_string_here",
"created_at": "2026-03-15T11:00:00.000Z"
}
}

Store the secret securely — you'll need it to verify incoming signatures. Never share or log it.

Listen at https://my-app.example.com/webhooks/numen:

// Assume you already verified the signature (see above)constpayload=req.body;switch(payload.event){case'content.published':
console.log(`Article published: ${payload.data.title}`);// Sync to search index, email subscribers, etc.break;case'pipeline.completed':
console.log(`Pipeline ${payload.data.run_id} finished with score ${payload.data.ai_score}`);// Update dashboard, notify stakeholders, etc.break;}res.status(200).json({received: true});

Rate Limits

ActionLimit
Create/update webhook60/min per space
Redeliver webhook10/min per webhook
HTTP delivery timeout10 seconds per attempt

Webhooks use standard HTTP 429 (Too Many Requests) when rate limits are exceeded. Check the Retry-After header for backoff.

Audit & Troubleshooting

List deliveries for a webhook:

curl http://localhost:8000/api/v1/webhooks/wbk_abc123/deliveries \
-H "Authorization: Bearer YOUR_TOKEN"

Response includes status, HTTP response code, and response body (first 4KB):

{
"data": [
{
"id": "dly_123",
"webhook_id": "wbk_abc123",
"event_id": "evt_abc123",
"event_type": "content.published",
"status": "delivered",
"http_status": 200,
"attempt_number": 1,
"scheduled_at": "2026-03-15T11:05:00.000Z",
"delivered_at": "2026-03-15T11:05:01.000Z"
},
{
"id": "dly_456",
"webhook_id": "wbk_abc123",
"event_id": "evt_def456",
"event_type": "pipeline.completed",
"status": "abandoned",
"http_status": null,
"attempt_number": 3,
"scheduled_at": "2026-03-15T11:06:00.000Z",
"response_body": "Connection timeout"
}
]
}

Status values:

  • pending — Scheduled, waiting to be delivered
  • delivered — Successfully delivered (HTTP 2xx)
  • abandoned — Failed after 3 retry attempts; needs manual redeliver or debugging

Manually retry a failed delivery:

curl -X POST http://localhost:8000/api/v1/webhooks/wbk_abc123/deliveries/dly_456/redeliver \
-H "Authorization: Bearer YOUR_TOKEN"


Model Allocation

Each pipeline stage uses the right model for the job — balance cost vs. capability.

StageDefault ModelRoleEst. Cost/Article
Content Generationclaude-sonnet-4-6Full article writing~$0.05–0.15
Image Promptclaude-haiku-4-5-20251001Crafts image prompts from content metadata~$0.001–0.005
Image Generationmulti-providerHero image via OpenAI / Together AI / fal.ai / Replicate~$0.04–0.08
SEO Optimizationclaude-haiku-4-5-20251001Meta, keywords, slug~$0.005–0.02
Editorial Reviewclaude-opus-4-6Quality scoring & feedback~$0.10–0.30
Planning / Strategyclaude-opus-4-6Brief analysis, outlines~$0.05–0.15
Classificationclaude-haiku-4-5-20251001Tagging, categorization~$0.001–0.005
Premium Generationclaude-opus-4-6High-stakes content~$0.20–0.50

All model assignments are configurable via env vars — see Configuration below. You can route any role to OpenAI or Azure with AI_MODEL_GENERATION=openai:gpt-4o. Image generation supports four providers (OpenAI, Together AI, fal.ai, Replicate); the active provider is configured per-persona and gracefully skips if no key is configured.

Rough running cost: ~$35/month for 100 articles with images with the default setup.


Configuration

Copy .env.example to .env. Required variables are marked required.

Core

VariableDefaultNotes
APP_KEYRequired. Set by php artisan key:generate
APP_URLhttp://localhost:8000Public URL of your installation
DB_CONNECTIONsqlitesqlite or mysql
DB_DATABASEdatabase/database.sqlitePath for SQLite, DB name for MySQL
QUEUE_CONNECTIONredisredis (prod) or database (dev)

AI Providers

At least one API key is required.

VariableDefaultNotes
AI_DEFAULT_PROVIDERanthropicanthropic, openai, or azure
AI_FALLBACK_CHAINanthropic,openai,azureComma-separated, tried in order on failure
ANTHROPIC_API_KEYGet from console.anthropic.com
OPENAI_API_KEYOptional, enables OpenAI fallback
AZURE_OPENAI_API_KEYOptional, enables Azure fallback
AZURE_OPENAI_ENDPOINTRequired if using Azure

Model Assignments

Override which model handles each role. Format: model-name or provider:model-name.

VariableDefaultExample Override
AI_MODEL_GENERATIONclaude-sonnet-4-6openai:gpt-4o
AI_MODEL_GENERATION_PREMIUMclaude-opus-4-6anthropic:claude-opus-4-6
AI_MODEL_SEOclaude-haiku-4-5-20251001openai:gpt-4o-mini
AI_MODEL_REVIEWclaude-opus-4-6openai:gpt-4o
AI_MODEL_PLANNINGclaude-opus-4-6claude-sonnet-4-6
AI_MODEL_CLASSIFICATIONclaude-haiku-4-5-20251001openai:gpt-4o-mini

Cost Controls

VariableDefaultNotes
AI_COST_DAILY_LIMIT50USD. Pipeline stops when exceeded
AI_COST_MONTHLY_LIMIT500USD
AI_COST_PER_CONTENT_LIMIT2USD per content piece

Pipeline Behavior

VariableDefaultNotes
AI_AUTO_PUBLISH_SCORE80Editorial score (0–100) required for auto-publish
AI_HUMAN_GATE_TIMEOUT48Hours before a paused pipeline times out
AI_CONTENT_REFRESH_DAYS30Days before content is eligible for AI refresh

Project Structure

app/
├── Agents/ # AI agent system
│ ├── Agent.php # Abstract base (extend for custom agents)
│ ├── AgentFactory.php # Resolves agent type → implementation
│ └── Types/
│ ├── ContentCreatorAgent.php
│ ├── SeoExpertAgent.php
│ └── EditorialDirectorAgent.php
├── Pipelines/
│ └── PipelineExecutor.php # Orchestrates stage execution
├── Services/AI/
│ ├── LLMManager.php # Provider routing + fallback chain
│ ├── CostTracker.php # Per-call cost accounting
│ └── Providers/ # AnthropicProvider, OpenAIProvider, AzureOpenAIProvider
├── Models/ # 16 Eloquent models
│ ├── Content.php / ContentBlock.php / ContentVersion.php
│ ├── ContentBrief.php / ContentPipeline.php / ContentType.php
│ ├── Persona.php / Space.php / Page.php / PageComponent.php
│ ├── ComponentDefinition.php
│ ├── AIGenerationLog.php / PipelineRun.php
│ └── MediaAsset.php / Setting.php / User.php
├── Jobs/ # Queue jobs for pipeline stages
├── Events/ # PipelineStarted, StageCompleted, etc.
└── Http/Controllers/Api/ # Content delivery + management controllers
config/
└── numen.php # All Numen config (providers, models, pipeline, costs)

Documentation


Contributing

Contributions are welcome. Read CONTRIBUTING.md before opening a PR.

  • Found a bug? Open an issue
  • Want to add a feature? Check existing issues first, then open a discussion
  • First contribution? Look for issues tagged good first issue

Roadmap

See CHANGELOG.md for what's in each release.

Shipped (post-0.1.1):

  • Larastan level 5 static analysis — 199 errors fixed, 0 remaining ✅
  • Multi-provider image generation (OpenAI, Together AI, fal.ai, Replicate) ✅
  • User management (CRUD) with admin frontend pages ✅
  • Self-service password change ✅
  • Permanent content deletion with cascade cleanup ✅
  • Role-Based Access Control (RBAC) with space-scoped roles, AI budget governance, and audit logs ✅
  • 134+ tests (up from 117 in 0.1.1) ✅
  • Taxonomy & Content Organization — hierarchical vocabularies, drag-and-drop term trees, AI auto-categorization, full REST API (docs) ✅
  • Multi-Language & i18n Support — content localization, AI-powered translation, locale management, intelligent fallback chains, and translation workflow (docs) ✅

Near-term (0.2.0):

  • Deduplicate config numen.anthropic block (duplicates numen.providers.anthropic)
  • AgentContract interface extracted from Agent abstract class

Medium-term (0.3.0):

  • Extract formal interfaces (AgentContract, PipelineExecutorContract)
  • Docker / docker-compose setup

License

MIT — see LICENSE.

Built by byte5.labs.

About

Numen — AI-First Headless CMS. You write briefs. AI writes content.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages