Skip to Content
StrategyStrategy Writer — Improvement Plan

Strategy Writer — Improvement Plan

Analysis of the current strategy-writer output quality and a prioritised list of improvements.


Current State Assessment

The strategy writer produces structurally valid output (correct sections, tables, Markdown) but the content quality is inconsistent — it tends toward generic recommendations that could apply to many clients rather than being specific to the tenant’s actual products, audience, and competitive position.

Root causes

1. System prompt has no quality floor
The prompt specifies structure and format well, but gives Claude no explicit rule against generic advice. A strategy can satisfy all 7 requirements with sentences like “increase brand awareness through targeted content” — factually correct but useless.

2. Connected channels are not passed in
The worker never queries ConnectedChannel. Claude can recommend LinkedIn when it hasn’t been connected, or ignore Google Ads even when it is live and running. Channel recommendations are based purely on plan tier, not actual OAuth state.

3. Roadmap has no calendar anchor
”Month 1”, “Month 2” etc. are abstract. The strategy has no awareness of the current date, so the roadmap cannot map to real calendar months.

4. RAG is sparse and the queries are too broad
Only 7 chunks total (4 brand + 3 competitor). The brand query was previously "brand voice tone messaging target audience products services" — too broad and overlapped with brand voice already appended to clientContext. Updated (April 2026) to "content examples copywriting samples product descriptions marketing materials brand story" to pull supplementary materials instead. Deduplication across queries also added. Pricing, service tiers, customer success stories, and keyword data are still not queried — see improvement C.

5. Baseline data is underused
When TenantBaseline exists, it’s appended as bullet points with a one-line instruction to “set realistic targets.” The system prompt has no explicit rule requiring delta-based goals (e.g., “if monthly visitors = 2,000, your 6-month target must be expressed as +X visitors, not a standalone number”).

6. Single-pass generation
Claude writes the strategy in a single pass with no structured reasoning step. A hidden thinking step (analysis of the situation before writing) would improve depth in the Situation Analysis and Goals sections.

7. Minimum output check is trivially low
The worker rejects output below 200 characters. A broken or near-empty run could pass this check.


Improvements

Priority 1 — High impact, low effort (system prompt only)

A. Add quality rules to the system prompt

Append to the systemPrompt in packages/db/src/seed.ts (and update the row in the DB via manage portal):

QUALITY RULES — every rule must be satisfied or the strategy is invalid: - Every KPI row in the Goals table must contain a numeric target (e.g. "+40% organic clicks", "500 impressions/month") — vague targets like "increase traffic" are not acceptable - Every channel recommendation in the Channel Strategy section must name a specific product, service, or audience segment from the context file that justifies it - No sentence may apply generically to any business — every claim must be verifiable from the client context provided - The Situation Analysis must name at least 2 competitors from the context file and contrast the client's position against them - The Monthly Execution Roadmap must use actual calendar months (e.g. "May 2026", "June 2026") starting from the month provided in CURRENT MONTH below - The What to Avoid section must include at least one channel or tactic the client currently uses (or could use) that is not a good fit — with a specific reason

Also add CURRENT MONTH: {month} to the prompt (e.g., “May 2026”) so Month 1 is anchored to a real date.

Implementation: packages/agents/src/workers/strategy-writer.worker.ts — add currentMonth to buildStrategyPrompt() params and pass new Date().toLocaleString("en-IN", { month: "long", year: "numeric" }) from the worker.


Priority 2 — High impact, small code change

B. Pass connected channels into the prompt

Currently missing. The worker should query ConnectedChannel and include the result so Claude knows exactly which channels are already authenticated and which would need setup.

Implementation: In strategy-writer.worker.ts, after the baseline fetch (line 134):

const connectedChannels = await db.connectedChannel.findMany({ where: { tenantId: data.tenantId, status: "active" }, select: { platform: true, name: true }, });

Add to buildStrategyPrompt() params and inject into the prompt:

CONNECTED CHANNELS (already authenticated — prioritise these in recommendations): {connectedChannels.map(c => `- ${c.platform}: ${c.name}`).join("\n")} Channels on this plan not yet connected: {derived list} When recommending an unconnected channel, note: "Requires connecting [channel] in Dashboard → Channels."

Priority 3 — Medium impact, medium effort

C. Add more targeted RAG queries

The current 2 queries (brand + competitor) miss pricing, service details, customer outcomes, and keyword data. Add 2 more parallel queries:

search({ query: `pricing packages tiers case studies customer results testimonials`, topK: 3 }), search({ query: `SEO keywords search intent content opportunities ranking`, topK: 3 }),

Also bump the existing queries from topK: 4 and topK: 3 to topK: 5 and topK: 4. Total chunks: 15 (up from 7).


D. Enforce delta targets when baseline data exists

When baselineContext is present, add to the system prompt:

BASELINE USAGE RULE: Every row in the Success Metrics table must show a delta from the baseline figure provided above (e.g. "2,000 → 3,000 visitors" or "+1,000 visitors"). Standalone targets without a baseline comparison are not acceptable when baseline data has been provided.

Priority 4 — Lower effort, good hygiene

E. Raise the minimum output length check
strategy-writer.worker.ts line 296: change < 200 to < 3000. A valid strategy document will never be under 3,000 characters; this catches broken runs early.

F. Log RAG chunk count at INFO level (done April 2026)
ragChunksUsed is now tracked and written to StrategyVersion.notes (— N RAG chunks or — RAG unavailable). The INFO log now includes total and deduped counts. Catch block logs tenantId so failures are traceable per tenant.


Per-Tenant Strategy Config (implemented)

A TenantStrategyConfig DB row (one per tenant) lets the manage portal toggle which inputs are fed to the strategy writer. All flags default to true so existing tenants are unaffected.

Model:

model TenantStrategyConfig { id String @id @default(cuid()) tenantId String @unique useBaseline Boolean @default(true) // include TenantBaseline metrics useRagBrand Boolean @default(true) // include brand knowledge-base docs useRagCompetitor Boolean @default(true) // include competitor research docs useConnectedChannels Boolean @default(true) // inject connected OAuth channels tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) @@map("tenant_strategy_config") }

API: GET + PUT /admin/v1/tenants/:tenantId/strategy-config
UI: Config sub-tab inside the Strategy tab on the manage tenant detail page.
Worker: Reads the config row at startup; gates each input fetch behind its flag.


Implementation Order

StepChangeFileEffort
0Per-tenant strategy config (schema + API + UI + worker)Schema, tenants.ts, StrategyTab, worker~2 h (done)
1Quality rules + current month in system promptseed.ts + strategy-writer.worker.ts + DB row~30 min
2Additional RAG queries (pricing + keyword)strategy-writer.worker.ts~20 min
3Delta target rule when baseline presentstrategy-writer.worker.ts (buildStrategyPrompt)~15 min
4Raise minimum output length to 3,000 charsstrategy-writer.worker.ts5 min
5Log RAG chunk countstrategy-writer.worker.ts5 min

What “Good” Looks Like

A high-quality strategy output should:

  • Name specific competitors and explain exactly why the client is better positioned on at least one dimension
  • Include KPI targets that are derived from the baseline numbers (e.g., “+25% organic clicks from current 1,200/month baseline”)
  • Recommend channels in priority order with a specific reason tied to the client’s product or audience, not a generic category heuristic
  • Have a Monthly Execution Roadmap that uses real calendar months and references specific content types (e.g., “4 blog posts on drain unblocking + 8 GBP posts” not “content calendar”)
  • Call out at least one thing the client should not do, with a reason grounded in their context (e.g., “Do not invest in LinkedIn — your audience is homeowners, not businesses”)

Not In Scope

  • Multi-pass / agentic strategy writing — having Claude research and draft iteratively. Would require a separate agentic loop, significant cost increase, and a different adapter pattern. Worth revisiting once the above improvements are shipped and baselined.
  • Structured goal extraction — parsing the Goals table into SmartGoal DB records post-generation. The current schema has StrategyVersion.content only; adding a structured goals model is a separate data model change.
  • Strategy versioning diff UI — showing what changed between v1 and v2. Useful but a UI concern, not a generation quality concern.

© 2026 Leadmetrics — Internal use only