Strategy Pipeline
[Live] — Context approval → strategy-writer → DM review → client approval → deliverable-planner
The strategy pipeline converts an approved Client Context File into a 6-month marketing strategy document, then into a structured month-by-month deliverable plan. It is the first fully AI-generated artefact the client sees and the document that drives everything downstream.
Pipeline Stages
Context approved (client)
└─► enqueueStrategyWriter()
└─► strategy-writer worker
└─► Claude generates Markdown strategy
└─► Strategy (pending_review) written to DB
└─► DM reviews → client approves
└─► enqueueDeliverablePlanner()
└─► deliverable-planner worker
└─► Goals + DeliverableTemplates writtenStrategy Writer
Worker: packages/agents/src/workers/strategy-writer.worker.ts
Queue: agent__strategy-writer
Model: Dynamic — reads AgentConfig.adapter + AgentConfig.model from DB (defaults: claude_local / claude-sonnet-4-6)
Timeout: 10 minutes
Lock duration: 11 minutes (covers cold-start + Windows DLL stall)
Per-tenant input config — TenantStrategyConfig
Each of the optional inputs below can be toggled per tenant via Manage → Tenant → Strategy Config. All flags default to true so existing tenants are unaffected if no config row exists.
| Flag | Controls | Turn off when… |
|---|---|---|
useBaseline | TenantBaseline metrics fetch | Client entered inaccurate/estimated baseline numbers |
useRagBrand | Brand knowledge-base RAG query | New tenant with no uploaded brand docs |
useRagCompetitor | Competitor research RAG query | Client is sensitive about competitor mentions |
useConnectedChannels | Active ConnectedChannel inject | Channels not connected yet but strategy should run |
API: GET /admin/v1/tenants/:tenantId/strategy-config · PUT /admin/v1/tenants/:tenantId/strategy-config
Proxy: apps/manage/src/app/api/admin/tenants/[tenantId]/strategy-config/route.ts
UI: apps/manage/src/app/(manage)/tenants/[tenantId]/StrategyConfigTab.tsx — save-on-toggle
Schema: TenantStrategyConfig model in packages/db/prisma/schema.prisma (@@map("tenant_strategy_config"))
Help topic: strategy-config in apps/manage/src/app/(manage)/help/_data/index.ts — accessible via the ? trigger in the Strategy Config tab header
Input data fetched
| Source | Fields read | Gated by |
|---|---|---|
AgentConfig (role=strategy-writer) | model, systemPrompt | Always |
TenantStrategyConfig | All 4 flags | Always (defaults to all-true if missing) |
ClientContext | content | Always — primary source of truth |
TenantBaseline | Monthly visitors, organic clicks, avg search position, top keywords, ad spend/CPL/conversions, social followers + engagement | useBaseline |
ConnectedChannel | type, title where isConnected: true | useConnectedChannels |
| RAG — brand query | Top 4 chunks: content examples, copywriting samples, product descriptions, marketing materials (supplementary; core brand voice already in clientContext) | useRagBrand |
| RAG — competitor query | Top 3 chunks: competitor analysis, market positioning, industry trends | useRagCompetitor |
Subscription | Plan tier name | Always |
Prompt structure
{systemPrompt}
TENANT: {tenantName}
COUNTRY: {country}
PLAN TIER: {planType} (available channels/content: {capabilities})
CLIENT CONTEXT FILE (primary source of truth — all strategy must be grounded here):
{clientContext.content}
CONNECTED CHANNELS (already authenticated — prioritise these in recommendations):
- Google Ads: Acme Corp ← omitted if useConnectedChannels=false or none connected
- LinkedIn: Acme Corp Page
When recommending a channel not in this list, note: "Requires connecting [channel] in Dashboard → Channels."
KNOWLEDGE BASE (supporting reference material — use to enrich recommendations):
{ragContext} ← omitted if both RAG flags off or search returns nothing
← results from brand + competitor queries are deduped by chunk text before injection
CURRENT PERFORMANCE BASELINE (use to set realistic, grounded targets):
{baselineContext} ← omitted if useBaseline=false or no TenantBaseline row
REVISION INSTRUCTIONS (incorporate these into the new version):
{revisionNotes} ← omitted on first-run; present on DM-requested revisionsPlan capabilities injected
| Plan | Capabilities string passed to Claude |
|---|---|
| free | blog posts, GBP posts, keyword research |
| starter | + social media |
| growth | + email newsletters, landing pages |
| professional | + Google/Meta ads, monthly reports |
| agency | all professional + white-label reporting, multi-location support |
| enterprise | all agency + custom integrations, dedicated support |
Current system prompt (as seeded)
You are the Strategy Writer agent for Leadmetrics, a digital marketing agency AI platform.
Your task is to write a comprehensive, actionable 6-month digital marketing strategy for the client described below.
STRATEGY REQUIREMENTS:
1. Write a professional Markdown document (1500–3000 words).
2. Include exactly these sections (use ## headings):
## Executive Summary
## Situation Analysis
## Target Audience Personas
## Marketing Goals & KPIs
## Channel Strategy
## Content Strategy
## SEO Strategy
## Monthly Execution Roadmap
## Budget & Resource Allocation
## Success Metrics
3. USE MARKDOWN TABLES for all structured data...
4. Use bullet lists only for genuinely unstructured content.
5. Only recommend channels available on the plan tier provided.
6. Be specific to this client — use their actual products, audience, and competitive context.
7. Every recommendation must be justified by the client context below.
Output ONLY the Markdown strategy document. No preamble, no explanation, no code fences.Output written
| Model | Action | Value |
|---|---|---|
Strategy | Upserted (one per tenant) | status: "pending_review", currentVersion incremented |
StrategyVersion | Created | Full Claude Markdown output, createdBy: "LM Agent", notes field includes RAG chunk count (e.g. — 5 RAG chunks) or — RAG unavailable |
StrategyLog | Created | Action: version_created, detail includes revision note if applicable |
CreditLedger | Credits consumed | Via getCreditCost("strategy") |
Notification | Enqueued | Email to tenant admin + content_review preference recipients |
Approval Gate
After generation, the strategy sits at pending_review. The approval flow:
- DM portal — DM team can read the strategy, change status to
rejected, or request a revision (POST /dm/v1/strategy/revise) which re-queues the worker withrevisionNotes. - Client (Dashboard) — Client approves via
POST /tenant/v1/strategy/approve, which setsstatus: "approved"and immediately callsenqueueDeliverablePlanner().
Deliverable Planner
Worker: packages/agents/src/workers/strategy.worker.ts
Queue: agent__deliverable-planner
Receives the full approved strategy Markdown and produces:
Goal[]— SMART goals extracted from strategyDeliverableTemplate[]— monthly content volumes per type, filtered by plan tierDeliverablePlan— the container record (status: "pending_review")
See docs/agents/deliverable-planner/ for full details.
Key Code Locations
| File | Role |
|---|---|
packages/agents/src/workers/strategy-writer.worker.ts | Worker + buildStrategyPrompt() |
packages/agents/src/workers/strategy.worker.ts | Deliverable planner worker |
packages/queue/src/queues.ts | enqueueStrategyWriter(), enqueueDeliverablePlanner() |
packages/queue/src/types.ts | StrategyWriterJobData type |
packages/db/prisma/schema.prisma | Strategy, StrategyVersion, StrategyLog, TenantStrategyConfig models |
packages/db/src/seed.ts | Default system prompt for strategy-writer AgentConfig row |
apps/api/src/routers/tenant/main.ts | /context/approve and /strategy/approve endpoints |
apps/api/src/routers/dm/strategy.ts | DM revision and status endpoints |
apps/api/src/routers/admin/tenants.ts | GET/PUT /tenants/:tenantId/strategy-config |
apps/manage/src/app/api/admin/tenants/[tenantId]/strategy-config/route.ts | Next.js proxy for strategy config |
apps/manage/src/app/(manage)/tenants/[tenantId]/StrategyConfigTab.tsx | Manage portal config UI |
docs/strategy/improvements.md | Improvement plan + rationale |