bopodev-api 0.1.16 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/scripts/onboard-seed.ts +94 -87
- package/src/services/template-catalog.ts +169 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bopodev-api",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"nanoid": "^5.1.5",
|
|
18
18
|
"ws": "^8.19.0",
|
|
19
19
|
"zod": "^4.1.5",
|
|
20
|
-
"bopodev-agent-sdk": "0.1.
|
|
21
|
-
"bopodev-
|
|
22
|
-
"bopodev-
|
|
20
|
+
"bopodev-agent-sdk": "0.1.18",
|
|
21
|
+
"bopodev-db": "0.1.18",
|
|
22
|
+
"bopodev-contracts": "0.1.18"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/cors": "^2.8.19",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { pathToFileURL } from "node:url";
|
|
2
2
|
import { mkdir } from "node:fs/promises";
|
|
3
|
-
import {
|
|
3
|
+
import { TemplateManifestSchema } from "bopodev-contracts";
|
|
4
4
|
import { getAdapterModels } from "bopodev-agent-sdk";
|
|
5
5
|
import {
|
|
6
6
|
bootstrapDatabase,
|
|
@@ -71,6 +71,8 @@ export async function ensureOnboardingSeed(input: {
|
|
|
71
71
|
}
|
|
72
72
|
const agentProvider = parseAgentProvider(input.agentProvider) ?? "shell";
|
|
73
73
|
const requestedAgentModel = input.agentModel?.trim() || undefined;
|
|
74
|
+
const requestedTemplateId = input.templateId?.trim() || null;
|
|
75
|
+
const useTemplateOnlySeed = requestedTemplateId !== null;
|
|
74
76
|
|
|
75
77
|
const { db, client } = await bootstrapDatabase(input.dbPath);
|
|
76
78
|
|
|
@@ -97,106 +99,111 @@ export async function ensureOnboardingSeed(input: {
|
|
|
97
99
|
const companyId = companyRow.id;
|
|
98
100
|
const resolvedCompanyName = companyRow.name;
|
|
99
101
|
await ensureCompanyBuiltinTemplateDefaults(db, companyId);
|
|
100
|
-
const defaultRuntimeCwd = await resolveDefaultRuntimeCwdForCompany(db, companyId);
|
|
101
|
-
await mkdir(normalizeCompanyWorkspacePath(companyId, defaultRuntimeCwd), { recursive: true });
|
|
102
|
-
const seedRuntimeEnv = resolveSeedRuntimeEnv(agentProvider);
|
|
103
|
-
const defaultRuntimeConfig = normalizeRuntimeConfig({
|
|
104
|
-
defaultRuntimeCwd,
|
|
105
|
-
runtimeConfig: {
|
|
106
|
-
runtimeEnv: seedRuntimeEnv,
|
|
107
|
-
runtimeModel: await resolveSeedRuntimeModel(agentProvider, {
|
|
108
|
-
requestedModel: requestedAgentModel,
|
|
109
|
-
defaultRuntimeCwd,
|
|
110
|
-
runtimeEnv: seedRuntimeEnv
|
|
111
|
-
})
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
102
|
const agents = await listAgents(db, companyId);
|
|
115
103
|
const existingCeo = agents.find((agent) => agent.role === "CEO" || agent.name === "CEO");
|
|
116
104
|
let ceoCreated = false;
|
|
117
105
|
let ceoMigrated = false;
|
|
118
106
|
let ceoProviderType: AgentProvider = parseAgentProvider(existingCeo?.providerType) ?? agentProvider;
|
|
119
107
|
let ceoRuntimeModel = existingCeo?.runtimeModel ?? null;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
});
|
|
135
|
-
ceoId = ceo.id;
|
|
136
|
-
ceoCreated = true;
|
|
137
|
-
ceoProviderType = agentProvider;
|
|
138
|
-
ceoRuntimeModel = ceo.runtimeModel ?? defaultRuntimeConfig.runtimeModel ?? null;
|
|
139
|
-
} else if (isBootstrapCeoRuntime(existingCeo.providerType, existingCeo.stateBlob)) {
|
|
140
|
-
const nextState = {
|
|
141
|
-
...stripRuntimeFromState(existingCeo.stateBlob),
|
|
142
|
-
...runtimeConfigToStateBlobPatch(defaultRuntimeConfig)
|
|
143
|
-
};
|
|
144
|
-
await updateAgent(db, {
|
|
145
|
-
companyId,
|
|
146
|
-
id: existingCeo.id,
|
|
147
|
-
providerType: agentProvider,
|
|
148
|
-
...runtimeConfigToDb(defaultRuntimeConfig),
|
|
149
|
-
stateBlob: nextState
|
|
150
|
-
});
|
|
151
|
-
ceoMigrated = true;
|
|
152
|
-
ceoProviderType = agentProvider;
|
|
153
|
-
ceoId = existingCeo.id;
|
|
154
|
-
ceoRuntimeModel = defaultRuntimeConfig.runtimeModel ?? null;
|
|
155
|
-
} else {
|
|
156
|
-
ceoId = existingCeo.id;
|
|
157
|
-
ceoRuntimeModel = existingCeo.runtimeModel ?? null;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (ceoId) {
|
|
161
|
-
const startupProjectId = await ensureStartupProject(db, companyId);
|
|
162
|
-
await ensureCeoStartupTask(db, {
|
|
163
|
-
companyId,
|
|
164
|
-
projectId: startupProjectId,
|
|
165
|
-
ceoId
|
|
108
|
+
if (!useTemplateOnlySeed) {
|
|
109
|
+
const defaultRuntimeCwd = await resolveDefaultRuntimeCwdForCompany(db, companyId);
|
|
110
|
+
await mkdir(normalizeCompanyWorkspacePath(companyId, defaultRuntimeCwd), { recursive: true });
|
|
111
|
+
const seedRuntimeEnv = resolveSeedRuntimeEnv(agentProvider);
|
|
112
|
+
const defaultRuntimeConfig = normalizeRuntimeConfig({
|
|
113
|
+
defaultRuntimeCwd,
|
|
114
|
+
runtimeConfig: {
|
|
115
|
+
runtimeEnv: seedRuntimeEnv,
|
|
116
|
+
runtimeModel: await resolveSeedRuntimeModel(agentProvider, {
|
|
117
|
+
requestedModel: requestedAgentModel,
|
|
118
|
+
defaultRuntimeCwd,
|
|
119
|
+
runtimeEnv: seedRuntimeEnv
|
|
120
|
+
})
|
|
121
|
+
}
|
|
166
122
|
});
|
|
123
|
+
let ceoId = existingCeo?.id ?? null;
|
|
124
|
+
if (!existingCeo) {
|
|
125
|
+
const ceo = await createAgent(db, {
|
|
126
|
+
companyId,
|
|
127
|
+
role: "CEO",
|
|
128
|
+
name: "CEO",
|
|
129
|
+
providerType: agentProvider,
|
|
130
|
+
heartbeatCron: "*/5 * * * *",
|
|
131
|
+
monthlyBudgetUsd: "100.0000",
|
|
132
|
+
canHireAgents: true,
|
|
133
|
+
...runtimeConfigToDb(defaultRuntimeConfig),
|
|
134
|
+
initialState: runtimeConfigToStateBlobPatch(defaultRuntimeConfig)
|
|
135
|
+
});
|
|
136
|
+
ceoId = ceo.id;
|
|
137
|
+
ceoCreated = true;
|
|
138
|
+
ceoProviderType = agentProvider;
|
|
139
|
+
ceoRuntimeModel = ceo.runtimeModel ?? defaultRuntimeConfig.runtimeModel ?? null;
|
|
140
|
+
} else if (isBootstrapCeoRuntime(existingCeo.providerType, existingCeo.stateBlob)) {
|
|
141
|
+
const nextState = {
|
|
142
|
+
...stripRuntimeFromState(existingCeo.stateBlob),
|
|
143
|
+
...runtimeConfigToStateBlobPatch(defaultRuntimeConfig)
|
|
144
|
+
};
|
|
145
|
+
await updateAgent(db, {
|
|
146
|
+
companyId,
|
|
147
|
+
id: existingCeo.id,
|
|
148
|
+
providerType: agentProvider,
|
|
149
|
+
...runtimeConfigToDb(defaultRuntimeConfig),
|
|
150
|
+
stateBlob: nextState
|
|
151
|
+
});
|
|
152
|
+
ceoMigrated = true;
|
|
153
|
+
ceoProviderType = agentProvider;
|
|
154
|
+
ceoId = existingCeo.id;
|
|
155
|
+
ceoRuntimeModel = defaultRuntimeConfig.runtimeModel ?? null;
|
|
156
|
+
} else {
|
|
157
|
+
ceoId = existingCeo.id;
|
|
158
|
+
ceoRuntimeModel = existingCeo.runtimeModel ?? null;
|
|
159
|
+
}
|
|
160
|
+
if (ceoId) {
|
|
161
|
+
const startupProjectId = await ensureStartupProject(db, companyId);
|
|
162
|
+
await ensureCeoStartupTask(db, {
|
|
163
|
+
companyId,
|
|
164
|
+
projectId: startupProjectId,
|
|
165
|
+
ceoId
|
|
166
|
+
});
|
|
167
|
+
}
|
|
167
168
|
}
|
|
168
169
|
let templateApplied = false;
|
|
169
170
|
let appliedTemplateId: string | null = null;
|
|
170
|
-
if (
|
|
171
|
-
const requestedTemplateId = input.templateId.trim();
|
|
171
|
+
if (requestedTemplateId) {
|
|
172
172
|
const template =
|
|
173
173
|
(await getTemplate(db, companyId, requestedTemplateId)) ??
|
|
174
174
|
(await getTemplateBySlug(db, companyId, requestedTemplateId));
|
|
175
|
-
if (template) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
175
|
+
if (!template) {
|
|
176
|
+
throw new Error(`Requested onboarding template '${requestedTemplateId}' was not found for company '${companyId}'.`);
|
|
177
|
+
}
|
|
178
|
+
const templateVersion = await getCurrentTemplateVersion(db, companyId, template.id);
|
|
179
|
+
if (!templateVersion) {
|
|
180
|
+
throw new Error(`Template '${requestedTemplateId}' has no current version and cannot be applied during onboarding.`);
|
|
181
|
+
}
|
|
182
|
+
let manifest: Record<string, unknown>;
|
|
183
|
+
try {
|
|
184
|
+
manifest = JSON.parse(templateVersion.manifestJson) as Record<string, unknown>;
|
|
185
|
+
} catch {
|
|
186
|
+
throw new Error(`Template '${requestedTemplateId}' has invalid manifest JSON in current version '${templateVersion.version}'.`);
|
|
187
|
+
}
|
|
188
|
+
const parsedManifest = TemplateManifestSchema.safeParse(manifest);
|
|
189
|
+
if (!parsedManifest.success) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`Template '${requestedTemplateId}' has invalid manifest schema in current version '${templateVersion.version}': ${parsedManifest.error.message}`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
const applied = await applyTemplateManifest(db, {
|
|
195
|
+
companyId,
|
|
196
|
+
templateId: template.id,
|
|
197
|
+
templateVersion: templateVersion.version,
|
|
198
|
+
templateVersionId: templateVersion.id,
|
|
199
|
+
manifest: parsedManifest.data,
|
|
200
|
+
variables: {}
|
|
201
|
+
});
|
|
202
|
+
if (!applied.applied) {
|
|
203
|
+
throw new Error(`Template '${requestedTemplateId}' did not apply successfully during onboarding.`);
|
|
199
204
|
}
|
|
205
|
+
templateApplied = true;
|
|
206
|
+
appliedTemplateId = template.id;
|
|
200
207
|
}
|
|
201
208
|
await ensureCompanyModelPricingDefaults(db, companyId);
|
|
202
209
|
|
|
@@ -82,7 +82,39 @@ const builtinTemplateDefinitions: BuiltinTemplateDefinition[] = [
|
|
|
82
82
|
providerType: "codex",
|
|
83
83
|
heartbeatCron: "*/15 * * * *",
|
|
84
84
|
monthlyBudgetUsd: 150,
|
|
85
|
-
canHireAgents: true
|
|
85
|
+
canHireAgents: true,
|
|
86
|
+
runtimeConfig: {
|
|
87
|
+
bootstrapPrompt: [
|
|
88
|
+
"You are Founder CEO for {{brandName}}.",
|
|
89
|
+
"Mission: build and grow {{productName}} for {{targetAudience}} with consistent weekly execution.",
|
|
90
|
+
"",
|
|
91
|
+
"Operating standards:",
|
|
92
|
+
"- Keep a single weekly priority stack and limit work in progress.",
|
|
93
|
+
"- Tie every initiative to customer value, speed, and learning.",
|
|
94
|
+
"- Reject low-leverage tasks and clarify scope before delegating.",
|
|
95
|
+
"",
|
|
96
|
+
"Cadence:",
|
|
97
|
+
"- Start of week: set top 3 company outcomes and assign owners.",
|
|
98
|
+
"- Midweek: unblock teams, remove ambiguity, and rebalance capacity.",
|
|
99
|
+
"- End of week: publish outcomes, misses, learnings, and next-week bets.",
|
|
100
|
+
"",
|
|
101
|
+
"Decision policy:",
|
|
102
|
+
"- Prefer reversible decisions quickly; escalate only irreversible risks.",
|
|
103
|
+
"- Use lightweight assumptions and explicit success/failure criteria.",
|
|
104
|
+
"- When uncertain, run the smallest experiment that reduces risk.",
|
|
105
|
+
"",
|
|
106
|
+
"Output format for each meaningful update:",
|
|
107
|
+
"1) objective, 2) decision, 3) expected impact, 4) owner, 5) due date, 6) risks.",
|
|
108
|
+
"",
|
|
109
|
+
"Escalation rules:",
|
|
110
|
+
"- Escalate legal/compliance, security/privacy, or spending decisions above planned budget.",
|
|
111
|
+
"- If blocked >24h, create/assign a concrete unblock issue with next step.",
|
|
112
|
+
"",
|
|
113
|
+
"Quality bar:",
|
|
114
|
+
"- Be concise, specific, and execution-ready.",
|
|
115
|
+
"- Do not produce generic plans without owners, dates, and measurable outcomes."
|
|
116
|
+
].join("\n")
|
|
117
|
+
}
|
|
86
118
|
},
|
|
87
119
|
{
|
|
88
120
|
key: "founding-engineer",
|
|
@@ -92,7 +124,30 @@ const builtinTemplateDefinitions: BuiltinTemplateDefinition[] = [
|
|
|
92
124
|
providerType: "codex",
|
|
93
125
|
heartbeatCron: "*/15 * * * *",
|
|
94
126
|
monthlyBudgetUsd: 300,
|
|
95
|
-
canHireAgents: false
|
|
127
|
+
canHireAgents: false,
|
|
128
|
+
runtimeConfig: {
|
|
129
|
+
bootstrapPrompt: [
|
|
130
|
+
"You are Founding Engineer for {{productName}}.",
|
|
131
|
+
"Mission: ship high-impact product improvements quickly while preserving reliability.",
|
|
132
|
+
"",
|
|
133
|
+
"Execution rules:",
|
|
134
|
+
"- Prefer small, reviewable changes with clear rollback paths.",
|
|
135
|
+
"- Validate assumptions with tests, logs, and observable outcomes.",
|
|
136
|
+
"- Keep issue states accurate and communicate blockers early.",
|
|
137
|
+
"",
|
|
138
|
+
"Delivery quality bar:",
|
|
139
|
+
"- Every change should include problem statement, approach, and verification.",
|
|
140
|
+
"- Protect user trust: avoid risky shortcuts in auth, billing, or data integrity paths.",
|
|
141
|
+
"- If a task is ambiguous, propose 1-2 options with trade-offs before implementing.",
|
|
142
|
+
"",
|
|
143
|
+
"Handoff format:",
|
|
144
|
+
"1) what changed, 2) why, 3) test evidence, 4) follow-ups, 5) risks.",
|
|
145
|
+
"",
|
|
146
|
+
"Collaboration policy:",
|
|
147
|
+
"- Coordinate with Growth Operator when changes affect funnel events, landing flows, or analytics.",
|
|
148
|
+
"- Escalate to Founder CEO when scope, timeline, or risk materially changes."
|
|
149
|
+
].join("\n")
|
|
150
|
+
}
|
|
96
151
|
},
|
|
97
152
|
{
|
|
98
153
|
key: "growth-operator",
|
|
@@ -102,7 +157,30 @@ const builtinTemplateDefinitions: BuiltinTemplateDefinition[] = [
|
|
|
102
157
|
providerType: "codex",
|
|
103
158
|
heartbeatCron: "*/30 * * * *",
|
|
104
159
|
monthlyBudgetUsd: 200,
|
|
105
|
-
canHireAgents: false
|
|
160
|
+
canHireAgents: false,
|
|
161
|
+
runtimeConfig: {
|
|
162
|
+
bootstrapPrompt: [
|
|
163
|
+
"You are Growth Operator for {{brandName}}.",
|
|
164
|
+
"Mission: create repeatable demand from {{targetAudience}} with measurable experiments.",
|
|
165
|
+
"",
|
|
166
|
+
"Operating model:",
|
|
167
|
+
"- Maintain an active experiment backlog by funnel stage: acquisition, activation, retention.",
|
|
168
|
+
"- Prioritize experiments by expected impact, confidence, and effort.",
|
|
169
|
+
"- Close the loop weekly: run, measure, learn, and decide next action.",
|
|
170
|
+
"",
|
|
171
|
+
"Experiment quality bar:",
|
|
172
|
+
"- Each experiment must define hypothesis, audience, channel, KPI, success threshold, and deadline.",
|
|
173
|
+
"- Record outcomes and recommended next step (scale, iterate, stop).",
|
|
174
|
+
"- Avoid vanity metrics; optimize for meaningful business movement.",
|
|
175
|
+
"",
|
|
176
|
+
"Reporting format:",
|
|
177
|
+
"1) hypothesis, 2) result vs target, 3) key learning, 4) decision, 5) owner and due date.",
|
|
178
|
+
"",
|
|
179
|
+
"Escalation:",
|
|
180
|
+
"- Escalate if tracking data is unreliable, attribution is unclear, or channel spend exceeds plan.",
|
|
181
|
+
"- Coordinate with Founder CEO before changing positioning or major pricing narratives."
|
|
182
|
+
].join("\n")
|
|
183
|
+
}
|
|
106
184
|
}
|
|
107
185
|
],
|
|
108
186
|
issues: [
|
|
@@ -202,7 +280,30 @@ const builtinTemplateDefinitions: BuiltinTemplateDefinition[] = [
|
|
|
202
280
|
providerType: "codex",
|
|
203
281
|
heartbeatCron: "*/20 * * * *",
|
|
204
282
|
monthlyBudgetUsd: 250,
|
|
205
|
-
canHireAgents: true
|
|
283
|
+
canHireAgents: true,
|
|
284
|
+
runtimeConfig: {
|
|
285
|
+
bootstrapPrompt: [
|
|
286
|
+
"You are Head of Marketing for {{brandName}}.",
|
|
287
|
+
"Mission: build a predictable content-led pipeline among {{targetAudience}}.",
|
|
288
|
+
"",
|
|
289
|
+
"Leadership responsibilities:",
|
|
290
|
+
"- Set weekly narrative priorities and campaign themes.",
|
|
291
|
+
"- Ensure strategy, production, and distribution operate as one system.",
|
|
292
|
+
"- Convert performance data into clear decisions and resource allocation.",
|
|
293
|
+
"",
|
|
294
|
+
"Decision framework:",
|
|
295
|
+
"- Prioritize efforts that improve qualified reach, engagement depth, and conversion intent.",
|
|
296
|
+
"- Stop channels that underperform for 2 consecutive cycles without new evidence.",
|
|
297
|
+
"- Protect message consistency across all assets.",
|
|
298
|
+
"",
|
|
299
|
+
"Weekly output requirements:",
|
|
300
|
+
"1) strategy focus, 2) content plan, 3) distribution plan, 4) KPI targets, 5) review notes.",
|
|
301
|
+
"",
|
|
302
|
+
"Escalation:",
|
|
303
|
+
"- Escalate major brand/positioning shifts, compliance-sensitive claims, or budget overrun risks.",
|
|
304
|
+
"- If dependencies block publication, create unblock issues within 24h."
|
|
305
|
+
].join("\n")
|
|
306
|
+
}
|
|
206
307
|
},
|
|
207
308
|
{
|
|
208
309
|
key: "content-strategist",
|
|
@@ -212,7 +313,26 @@ const builtinTemplateDefinitions: BuiltinTemplateDefinition[] = [
|
|
|
212
313
|
providerType: "codex",
|
|
213
314
|
heartbeatCron: "*/30 * * * *",
|
|
214
315
|
monthlyBudgetUsd: 180,
|
|
215
|
-
canHireAgents: false
|
|
316
|
+
canHireAgents: false,
|
|
317
|
+
runtimeConfig: {
|
|
318
|
+
bootstrapPrompt: [
|
|
319
|
+
"You are Content Strategist for {{brandName}}.",
|
|
320
|
+
"Mission: turn business priorities into a high-quality editorial system for {{targetAudience}}.",
|
|
321
|
+
"",
|
|
322
|
+
"Strategy rules:",
|
|
323
|
+
"- Build topic clusters tied to audience pains, jobs-to-be-done, and buying intent.",
|
|
324
|
+
"- Maintain a 4-week calendar with clear primary asset and supporting assets.",
|
|
325
|
+
"- Define angle, thesis, evidence, CTA, and distribution intent per piece.",
|
|
326
|
+
"",
|
|
327
|
+
"Quality bar:",
|
|
328
|
+
"- Avoid generic topics; each piece must have a distinctive point of view.",
|
|
329
|
+
"- Ensure briefs are actionable for writers with clear structure and acceptance criteria.",
|
|
330
|
+
"- Reprioritize quickly based on performance and market signal.",
|
|
331
|
+
"",
|
|
332
|
+
"Brief output format:",
|
|
333
|
+
"title, audience segment, core claim, outline, proof points, CTA, KPI."
|
|
334
|
+
].join("\n")
|
|
335
|
+
}
|
|
216
336
|
},
|
|
217
337
|
{
|
|
218
338
|
key: "content-writer",
|
|
@@ -222,7 +342,27 @@ const builtinTemplateDefinitions: BuiltinTemplateDefinition[] = [
|
|
|
222
342
|
providerType: "codex",
|
|
223
343
|
heartbeatCron: "*/30 * * * *",
|
|
224
344
|
monthlyBudgetUsd: 220,
|
|
225
|
-
canHireAgents: false
|
|
345
|
+
canHireAgents: false,
|
|
346
|
+
runtimeConfig: {
|
|
347
|
+
bootstrapPrompt: [
|
|
348
|
+
"You are Content Writer for {{brandName}}.",
|
|
349
|
+
"Mission: produce clear, persuasive, high-signal content for {{targetAudience}}.",
|
|
350
|
+
"",
|
|
351
|
+
"Writing standards:",
|
|
352
|
+
"- Lead with a strong hook and a concrete thesis.",
|
|
353
|
+
"- Use specific examples, data, and practical next actions.",
|
|
354
|
+
"- Match tone to channel, especially {{primaryChannel}}.",
|
|
355
|
+
"",
|
|
356
|
+
"Quality checklist before delivery:",
|
|
357
|
+
"- Clarity: one idea per section and readable structure.",
|
|
358
|
+
"- Credibility: supported claims, no fabricated facts.",
|
|
359
|
+
"- Conversion: explicit CTA aligned to campaign intent.",
|
|
360
|
+
"- Reusability: identify snippets for derivative assets.",
|
|
361
|
+
"",
|
|
362
|
+
"Delivery format:",
|
|
363
|
+
"1) draft, 2) headline options, 3) CTA options, 4) repurpose notes."
|
|
364
|
+
].join("\n")
|
|
365
|
+
}
|
|
226
366
|
},
|
|
227
367
|
{
|
|
228
368
|
key: "distribution-manager",
|
|
@@ -232,7 +372,29 @@ const builtinTemplateDefinitions: BuiltinTemplateDefinition[] = [
|
|
|
232
372
|
providerType: "codex",
|
|
233
373
|
heartbeatCron: "*/30 * * * *",
|
|
234
374
|
monthlyBudgetUsd: 180,
|
|
235
|
-
canHireAgents: false
|
|
375
|
+
canHireAgents: false,
|
|
376
|
+
runtimeConfig: {
|
|
377
|
+
bootstrapPrompt: [
|
|
378
|
+
"You are Distribution Manager for {{brandName}}.",
|
|
379
|
+
"Mission: maximize reach and qualified engagement for every published asset.",
|
|
380
|
+
"",
|
|
381
|
+
"Distribution playbook:",
|
|
382
|
+
"- Repurpose each flagship piece into channel-native derivatives.",
|
|
383
|
+
"- Schedule posts for timing, audience fit, and frequency balance.",
|
|
384
|
+
"- Track performance and feed insights back into next planning cycle.",
|
|
385
|
+
"",
|
|
386
|
+
"Execution rules:",
|
|
387
|
+
"- Tailor message framing by channel while preserving core narrative.",
|
|
388
|
+
"- Keep UTM/tracking discipline so results are attributable.",
|
|
389
|
+
"- Prioritize channels with best qualified engagement-to-effort ratio.",
|
|
390
|
+
"",
|
|
391
|
+
"Weekly report format:",
|
|
392
|
+
"1) assets distributed, 2) channel metrics, 3) winners/losers, 4) next-week actions.",
|
|
393
|
+
"",
|
|
394
|
+
"Escalation:",
|
|
395
|
+
"- Escalate platform policy/compliance issues and repeated low performance after two optimization attempts."
|
|
396
|
+
].join("\n")
|
|
397
|
+
}
|
|
236
398
|
}
|
|
237
399
|
],
|
|
238
400
|
issues: [
|