Action Items
[To Build]
Action Items are one-time strategic tasks generated alongside the deliverable plan to support goal achievement. Unlike Deliverable Templates (which produce recurring monthly activities), Action Items represent foundational or milestone work that only needs to happen once — such as a technical SEO audit, profile optimisation, or competitor analysis.
Where They Fit in the Pipeline
Context (approved)
└─► strategy-writer
└─► Strategy (approved)
└─► deliverable-planner
├─► Goals[]
├─► DeliverableTemplate[] (recurring, monthly)
└─► ActionItem[] (one-time, period-assigned)
└─► Plan approved
└─► activity-planner (per period)
├─► Activities from DeliverableTemplates
└─► Activities from ActionItems assigned to this periodConcept
| Concept | Description |
|---|---|
| Deliverable Template | Recurring work — e.g., “8 blog posts/month”. Generates activities every period. |
| Action Item | One-time work — e.g., “Technical SEO Audit”. Generates activities once in a specific period. |
| Suggested Period | Period number (1, 2, 3…) relative to planStartDate. Claude assigns this based on goal sequencing logic. |
| planStartDate | Set to the calendar month when the deliverable plan is approved. Period 1 = that month, Period 2 = next month, etc. |
Why separate from Deliverable Templates?
Deliverable Templates have a monthlyVolume — they are fundamentally recurring. Action Items have no volume; they execute once. Mixing them into the same model would require awkward isOneTime flags and break the activity planner’s period logic.
Data Model
model ActionItem {
id String @id @default(cuid())
deliverablePlanId String
deliverablePlan DeliverablePlan @relation(fields: [deliverablePlanId], references: [id])
tenantId String
goalId String?
goal Goal? @relation(fields: [goalId], references: [id])
title String
description String
agentQueue String // e.g. "agent__seo-optimizer"
suggestedPeriod Int // 1-based relative period number
rationale String // Claude's reasoning for the suggested period
estimatedCost Int // credits
status ActionItemStatus @default(pending_review)
assignedPeriodId String? // set when activity-planner runs for that period
deliverablePeriod DeliverablePeriod? @relation(fields: [assignedPeriodId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([deliverablePlanId])
@@index([tenantId])
}
enum ActionItemStatus {
pending_review // awaiting plan approval
approved // plan approved, waiting for its period to be reached
in_progress // activity-planner has created activities for this item
done // all activities completed
skipped // DM manually skipped it
}DeliverablePlan gets a new relation:
model DeliverablePlan {
// ... existing fields
actionItems ActionItem[]
planStartDate DateTime? // set on plan approval
}Deliverable Planner Changes
Prompt Addition
The deliverable planner prompt gains a new output section instructing Claude to generate action items:
## Action Items
List one-time strategic tasks needed to achieve the goals above.
These are NOT recurring — each executes once in a specific period.
Rules:
- Suggest the period number (1 = first month of the plan) based on sequencing logic
- Front-load foundational work (audits, research, setup) in periods 1-2
- Sequence action items so dependencies come before execution tasks
- Link each to the goal it supports (use the goal's position index)
- Only include tasks that require an agent — no manual human tasks
- Maximum 8 action items per plan
Output as JSON array under key "actionItems".Output Schema Addition
interface DeliverablePlannerOutput {
goals: Goal[]
deliverableTemplates: DeliverableTemplate[]
actionItems: ActionItemOutput[] // new
monthlyCostEstimate: number
planningNotes: string
}
interface ActionItemOutput {
title: string
description: string
goalIndex: number | null // index into goals array
agentQueue: string
suggestedPeriod: number // 1-based
rationale: string
estimatedCost: number
}DB Write
After saving goals and templates, the worker saves action items:
await db.actionItem.createMany({
data: actionItems.map(item => ({
deliverablePlanId: plan.id,
tenantId,
goalId: item.goalIndex !== null ? savedGoals[item.goalIndex].id : null,
title: item.title,
description: item.description,
agentQueue: item.agentQueue,
suggestedPeriod: item.suggestedPeriod,
rationale: item.rationale,
estimatedCost: item.estimatedCost,
status: "pending_review",
}))
})Period Mapping
When the deliverable plan is approved (POST /tenant/v1/deliverable-plan/:planId/approve), planStartDate is set to the first day of the current calendar month:
const planStartDate = `${year}-${month}-01` // string formatting, not toISOString()
await db.deliverablePlan.update({
where: { id: planId },
data: { status: "approved", planStartDate }
})Period number → calendar month:
function resolvePeriodDate(planStartDate: string, periodNumber: number): string {
const [year, month] = planStartDate.split("-").map(Number)
const targetMonth = month + periodNumber - 1
const y = year + Math.floor((targetMonth - 1) / 12)
const m = ((targetMonth - 1) % 12) + 1
return `${y}-${String(m).padStart(2, "0")}-01`
}All action items are updated to approved status on plan approval. Their suggestedPeriod is already stored — no further mapping needed until the activity planner runs.
Activity Planner Integration
When the activity planner runs for a period, it fetches action items assigned to that period:
const periodNumber = computePeriodNumber(plan.planStartDate, periodStart)
const actionItemsForPeriod = await db.actionItem.findMany({
where: {
deliverablePlanId: plan.id,
suggestedPeriod: periodNumber,
status: "approved",
}
})These are passed to the activity planner prompt as an additional section:
## One-Time Action Items for This Period
The following one-time tasks must also be sequenced this period:
| # | Title | Description | Agent Queue |
|---|---|---|---|
| 1 | Technical SEO Audit | Full crawl and issue report | agent__seo-optimizer |
Treat these as regular activities. Assign due dates and dependencies as appropriate.
Flag them with isOneTime: true in the output.After activity creation, action items are updated to in_progress. When all their activities complete, they move to done.
DM Period Override
DM can change the suggested period for any approved action item before its period is reached. This is available on the /strategy/deliverable-plan page.
API endpoint:
PATCH /tenant/v1/action-items/:id
Body: { suggestedPeriod: number }Rules:
- Cannot change period if status is
in_progressordone - Cannot set to a period that has already passed (i.e.,
resolvePeriodDate(period) < today)
Approval Flow
Action items follow the deliverable plan approval — no separate approval gate:
deliverable-planner generates action items (status: pending_review)
└─► Shown on /strategy/deliverable-plan alongside goals and templates
└─► DM reviews, optionally edits suggestedPeriod
└─► Client approves plan
└─► All action items → status: approved
└─► Each period: activity-planner picks up items for that period
└─► status: in_progress → donePlan Refresh Safety
When the deliverable plan is refreshed (new channels, strategy revision), action items are only regenerated if their status is pending_review. Items that are approved, in_progress, or done are preserved unchanged.
// On refresh: delete only pending_review action items before re-running planner
await db.actionItem.deleteMany({
where: { deliverablePlanId: planId, status: "pending_review" }
})UI Changes
/strategy/deliverable-plan — new section
A third section is added below Deliverable Templates:
[ Goals ]
[ Deliverable Templates ]
[ Action Items ] ← new
┌─────────────────────────────────────────────────────┐
│ Title │ Goal │ Period │ Rationale │
│ Tech SEO Audit │ +40% traffic│ Month 1 │ "Must run…" │
│ Profile Optim. │ +25% social │ Month 1 │ "Before…" │
└─────────────────────────────────────────────────────┘
DM can edit the Period column inline before approving./goals — optional chip
Each goal card shows a small badge: “2 action items” linking back to the plan page. Read-only.
/deliverables — automatic
Once an action item’s activities are created for a period, they surface in the deliverables page naturally — no changes needed.
Cost Estimation
The deliverable plan summary shows two cost lines:
Monthly recurring cost: ₹ 4,200 (from deliverable templates)
One-time action items: ₹ 800 (sum of all action item estimatedCost)The monthlyCostEstimate field on DeliverablePlan is not changed — it remains recurring-only. A new actionItemsCostEstimate field is added.
Key Code Locations
| File | Role |
|---|---|
packages/db/prisma/schema.prisma | Add ActionItem model + planStartDate to DeliverablePlan |
packages/agents/src/workers/strategy.worker.ts | Deliverable planner — add action items to prompt + output parsing + DB write |
packages/agents/src/workers/activity.worker.ts | Activity planner — fetch + inject action items for current period; update status |
packages/queue/src/types.ts | No changes needed (same job data) |
apps/api/src/routers/tenant/main.ts | Plan approve endpoint — set planStartDate, approve action items |
apps/api/src/routers/tenant/main.ts | New PATCH /tenant/v1/action-items/:id for DM period override |
apps/api/src/services/strategy.service.ts | approveDeliverablePlan() — include action item approval + planStartDate |
apps/dashboard/src/app/(dashboard)/strategy/deliverable-plan/ | Add Action Items section to plan viewer |
apps/dm/src/app/(dm)/strategy/deliverable-plan/ | Same — DM can edit period inline |
apps/dashboard/src/app/(dashboard)/goals/ | Optional: add action item count chip to goal cards |