name: deploy-campaign description: Turn an approved marketer brief into a JustAI Platform campaign script, saved tests, and a draft deployment. Use when a user wants to create, update, test, launch, pause, inspect, or explain a campaign through the JustAI Platform MCP.
Deploy Campaign
Use this skill when the marketer has approved the campaign direction and wants the work turned into a real JustAI Platform script.
Core rules
- Keep the marketer-facing explanation in campaign language first: audience, channel, message, timing, state, test result, and next action.
- Treat
README.md,index.js, andindex.test.jsas one campaign bundle whenever behavior changes. - Hardcoded literals are allowed for fixed campaign structure and values the
marketer is unlikely to tune. Prefer script parameters for audience IDs,
cadence values, thresholds, prompts, content IDs, channel/provider choices,
or other knobs the user is likely to change now or in the future; store saved
overrides in
parameters.json. - New or changed scripts stay
draftunless the user explicitly asks for activation. - Do not delete scripts unless the user explicitly asks for deletion.
- Scripts are managed through platform MCP tools, not local repo files. For script-only work, save with platform MCP tools and report script id/version; do not create a git branch, commit, or PR unless changing repo code.
- If activation is requested, call
get_script_readinessfirst and explain any blockers before callingset_script_state.
Workflow
Understand the brief.
- Infer the campaign goal, target audience, channel, offer, timing, and whether the user wants a draft, test, pause, archive, or activation.
- Ask only for details that block implementation.
- For updates, inspections, pauses, or activation, start with
list_scriptsandget_script.
Discover what the platform supports right now. Do this every authoring pass — the platform evolves and stale assumptions break scripts at validation time.
- Call
get_platform_contextto enumerate the available namespaces, tool names, and runtime limits for the current org. - Read each candidate tool's
inputSchemaanddescriptionfrom MCPtools/list. TheinputSchemacarries required/optional fields and types; thedescriptioncarries behavioral notes (live vs mock, what triggers a live send, deterministic vs random output, synthetic fallbacks). - For DSL method signatures (
.bind,.do,.sleep, etc.) and calling conventions, read the server-leveldescriptionthe OpenAPI MCP server publishes — the platform appendsgenerateAuthoringGuide(...)output to it, so the live DSL surface is in there. - Pick provider-scoped tools per the provider the org has configured.
- Call
Author or revise the script bundle.
index.jscontains one execution DSL builder expression.- Use hardcoded values when they are intentionally fixed for the campaign.
Use parameter helpers plus
parameters.jsonwhen the value is a business knob a marketer may reasonably ask to adjust later. - Prefer
$refs such as$.context.user.idand$.profile.attributes.email. - Use
contains(items, value)or callback array.includes(value)checks for runtime list membership, such as suppression-list guardrails. - Use stable IDs for side-effecting, durable, and UI-visible steps.
- Attach a short plain-language description to each step explaining what it does and why. The workflow panel and the run-detail timeline both surface those descriptions alongside the auto-derived labels, so they let marketers and on-call debuggers read the script without reverse-engineering the arguments. The annotated starter scripts are the reference for placement.
- Add or update
index.test.jsfor meaningful sends, suppressions, branches, waits, exits, or loops. - Add or update
README.mdwith the marketer-readable strategy summary.
Validate and save.
- Use
validate_scriptbefore saving when practical. - Use
create_scriptfor new campaigns. - For recurring or lifecycle campaigns where a user must not re-enter while
a previous run is still live, set
entry_policy: { mode: "single_live_run", identity_key: "user_id" }viacreate_scriptorupdate_script. The default allows repeat entries, and blocked triggers come back skipped, not failed. - For happy-path existing-campaign edits, prefer the OpenAPI
executetool with a short codemode program that callscodemode.request(...)to begin the edit session, patch files, validate, save, and return a compact summary. This keeps repeated validation from creating extra saved versions without requiring several separate MCP tool calls. - Use
begin_script_edit,patch_script_edit,validate_script_edit, andsave_script_editdirectly when you need step-by-step recovery or need to inspect the working bundle between calls. - Use
update_scriptonly for a small one-shot existing-campaign update where the full desired patch is already known.
- Use
Codemode edit wrapper shape:
const edit = await codemode.request({
method: "POST",
path: `/v1/scripts/${scriptId}/edit-sessions`,
});
const patched = await codemode.request({
method: "PATCH",
path: `/v1/script-edits/${edit.edit_id}`,
body: { files },
});
const validation = await codemode.request({
method: "POST",
path: `/v1/script-edits/${edit.edit_id}/validate`,
});
if (!validation.valid) {
return {
saved: false,
edit_id: edit.edit_id,
changed_paths: patched.changed_paths,
validation,
};
}
const saved = await codemode.request({
method: "POST",
path: `/v1/script-edits/${edit.edit_id}/save`,
});
return {
saved: true,
edit_id: edit.edit_id,
changed_paths: patched.changed_paths,
version: saved.saved_script?.version,
};
QA every behavior change.
- Use
run_script_tests. - Use
execute_scriptwith one representative user when the user asks for a live preview or when generated content needs review. - Use
get_run,list_runs,get_test_run, orlist_test_runsto inspect saved results before reporting back.
- Use
Explain outcome and next action.
- Summarize what changed, what was tested, whether tests passed, and whether the script remains draft or changed state.
- If activation is next, use
get_script_readinessand ask for explicit approval before activating.
Minimal script shape
This illustrates how primitives compose into a script bundle. Treat it as
workflow scaffolding only — for exact parameter shapes, DSL signatures, and
behavioral notes (live vs mock, what triggers a live send, etc.), read the
MCP tools/list schemas and the OpenAPI server description for the connected
platform. Hand-maintained references in this skill drift the moment the
platform changes; the runtime sources don't.
(() => {
return execution()
.bind(
"load_profile",
"profile",
iterable.user.get({ userId: $.context.user.id }),
)
.bind(
"draft_email",
"emailDraft",
iterable.email.generate({
prompt:
"Write a short win-back email with a clear return CTA for this user.",
user: $.profile.attributes,
length: "short",
}),
)
.do(
"send_email",
iterable.email.send({
to: $.profile.attributes.email,
subject: $.emailDraft.subject,
body: $.emailDraft.body,
}),
)
.respond({
campaign: "win-back",
userId: $.context.user.id,
email: $.profile.attributes.email,
status: "sent",
});
})();