task-content-publish
Multi-step TASK — creating and publishing marketing content. Enter when: the merchant asks for a Shopify blog article, an Instagram post, or a Facebook post; the merchant asks to revise or reformat a piece that is not published yet. Do NOT enter: greetings or small talk; a question about existing Brand Voice, Audiences, Style Guide, or a status/list, with no request to create content; setting up, auto-generating, calibrating, or re-scanning Brand IQ (that is task-brand-iq-setup); asking for a content plan or schedule covering a period rather than one piece (that is task-calendar-plan); asking for a promotion plan, campaign ideas or marketing strategy for a period (that is task-promo-plan); asking to change a setting, connect or disconnect a channel, or edit their account (they do that themselves in the Setting Hub); asking how something already published performed — views, clicks, conversions, which piece did best — even when the question contains the word post or article, provided the message does not also ask for a piece to be made (write, draft, make, create, generate one); that is a data question answered directly. Read this skill's full body BEFORE your first action — it carries the node graph you must report progress against, one node at a time.
Generated from tasks/content-publish/task.yaml by /task-authoring.
Do not edit here — edit the definition and regenerate.
name: task-content-publish description: >- Multi-step TASK — creating and publishing marketing content. Enter when: the merchant asks for a Shopify blog article, an Instagram post, or a Facebook post; the merchant asks to revise or reformat a piece that is not published yet. Do NOT enter: greetings or small talk; a question about existing Brand Voice, Audiences, Style Guide, or a status/list, with no request to create content; setting up, auto-generating, calibrating, or re-scanning Brand IQ (that is task-brand-iq-setup); asking for a content plan or schedule covering a period rather than one piece (that is task-calendar-plan); asking for a promotion plan, campaign ideas or marketing strategy for a period (that is task-promo-plan); asking to change a setting, connect or disconnect a channel, or edit their account (they do that themselves in the Setting Hub); asking how something already published performed — views, clicks, conversions, which piece did best — even when the question contains the word post or article, provided the message does not also ask for a piece to be made (write, draft, make, create, generate one); that is a data question answered directly. Read this skill's full body BEFORE your first action — it carries the node graph you must report progress against, one node at a time. kind: task task_name: "Content creation & publishing" label_template: "<topic> content" nodes:
- id: brief
label: Setting up the brief
purpose: Collect format, focus (category and at least one specific featured product), keywords, and the campaign decision for one piece — always via the Quick setup card, whatever the merchant's message holds, including a field it leaves out or fills with a placeholder like [product] — and then STOP, because raising the card ends the turn and the merchant's picks arrive as their next message.
advance_by: user
expects:
- content format(s)
- a category and at least one specific featured product
- target keywords
- the campaign decision (attach one, or explicitly none) tools:
- yepairag_marketing__REQUEST_CONTENT_BRIEF
- yepairag_marketing__SHOPIFY_GET_PRODUCTS_SUMMARY
- yepairag_marketing__GET_TRENDING_KEYWORDS
- yepairag_marketing__CREATE_CAMPAIGN_PROPOSAL
- yepairag_marketing__SHOPIFY_GET_COLLECTIONS_SUMMARY next:
- to: keywords when: the merchant submitted the Quick setup card
- id: keywords
label: Settling your keywords
purpose: Take the keywords and hashtags the merchant picked on the card exactly as they are, sort them to the channel each belongs to, and settle the per-channel set with the data behind it — the review card is what shows it to the merchant.
advance_by: agent
tools:
- yepairag_share__BRAND_IQ_GET
- yepairag_marketing__GET_TRENDING_KEYWORDS
- yepairag_marketing__GET_CHANNEL_KEYWORD_CANDIDATES next:
- to: research when: the per-channel keyword set is settled
- id: research
label: Researching your products and market
purpose: Ground the piece in the real catalog and, if useful, current market/web signals for the chosen focus and keywords.
advance_by: agent
tools:
- yepairag_marketing__SHOPIFY_GET_PRODUCTS_SUMMARY
- yepairag_marketing__SHOPIFY_SEARCH_PRODUCTS
- yepairag_marketing__GOOGLE_SEARCH next:
- to: compose when: the featured products and any needed research are in hand
- id: compose
label: Writing your content and its picture
purpose: Write one piece per requested channel, each from that channel's own writer skill, in the merchant's brand voice and grounded in the real catalog, and PUT EACH ONE IN A CREATE_CONTENT_DRAFT CALL — that call is the only thing that makes a piece exist; text written into the reply reaches nobody, cannot be reviewed, published or found again, and leaves the server's own placeholders unfilled. The words go in the call first, and the hero image is drawn for them inside that same call.
advance_by: agent
artifact:
type: content_draft
route: marketing-hub/draft
tools:
- yepairag_marketing__CREATE_CONTENT_DRAFT next:
- to: illustrate when: a draft has been created for every requested format AND the merchant asked for the picture to change as well — a new piece's hero is already drawn with its draft
- to: preview when: a draft has been created for every requested format and its hero image is on the cards (the draft result says so) OR the result says it could not be drawn (hero_image not_drawn — an imageless draft is legal and the merchant reviews it as it is), or a rewrite of the words that keeps the picture it had
- id: preview
label: Waiting for your review
purpose: Let the merchant review the draft(s) and either approve publishing or ask for a change, asking them once what to change when the request is too vague to act on.
advance_by: user
tools: []
route: marketing-hub/draft
next:
- to: brief when: the merchant wants a different subject altogether, a NEW separate piece, or chose to have the Quick setup card reopened to redo this piece's brief
- to: publish when: the merchant approved publishing and named the channel(s)
- to: compose when: the merchant asks to change the words of this piece, or to add a channel to it, and neither the picture nor the keywords are what they named
- to: illustrate when: the merchant asks to change the picture itself and the words are fine
- to: keywords when: the merchant names the keywords or hashtags themselves as the thing to change
- id: publish
label: Publishing your content
purpose: Publish the approved draft to each named channel — in chat by signalling the app's deterministic path, headless by the publish tools — and close from the outcomes those paths record in the merchant's Published tab themselves.
advance_by: agent
artifact:
type: published_content
route: marketing-hub/draft
revisable: false
tools:
- yepairag_marketing__REQUEST_PUBLISH_EXECUTION
- yepairag_marketing__SHOPIFY_LIST_BLOGS
- yepairag_marketing__SHOPIFY_CREATE_ARTICLE
- yepairag_marketing__PUBLISH_CONTENT next:
- to: publish when: a channel failed and the merchant asks to retry that channel
- id: illustrate
label: Changing the picture
purpose: Change the picture of a piece that already has one — editing the image it has, or drawing a new one when they reject the composition outright — and draw the picture a piece is MISSING when its draft answered not_drawn and the merchant wants one. A new piece's hero is otherwise drawn with its draft, not here.
advance_by: agent
tools:
- yepairag_marketing__GENERATE_IMAGE
- yepairag_marketing__EDIT_IMAGE next:
- to: preview when: the picture was edited or regenerated — it lands on every card of this piece by itself — or there was nothing to change here, or the change failed and the merchant has been told tags: [internal, task, marketing, requires-yepai-tools] license: MIT-0
Task — Content creation & publishing
Flow
flowchart TD
brief("Setting up the brief")
keywords["Settling your keywords"]
research["Researching your products and market"]
illustrate["Changing the picture"]
compose["Writing your content and its picture"]
preview("Waiting for your review")
publish["Publishing your content"]
brief --> keywords
keywords --> research
research --> compose
compose --> preview
compose -.-> illustrate
illustrate --> preview
preview --> publish
preview -.-> compose
preview -.-> illustrate
preview -.-> keywords
preview -.-> brief
publish -.-> publish
classDef terminal stroke-width:3px
class publish terminal
Rounded = waiting on the merchant · square = you are working · dashed = going back or retrying · bold border = terminal.
brief
Setting up the brief — Collect format, focus (category and at least one specific featured product), keywords, and the campaign decision for one piece — always via the Quick setup card, whatever the merchant's message holds, including a field it leaves out or fills with a placeholder like [product] — and then STOP, because raising the card ends the turn and the merchant's picks arrive as their next message.
- Report the
briefnode FIRST, before any other tool call this turn — including beforeREQUEST_CONTENT_BRIEF. The report is what opens the run; do not callREQUEST_CONTENT_BRIEF(or anything else) ahead of it. - A change to the piece already on screen is NOT a new piece, and must not re-enter this node. "Change the hero image to a plain white background", "swap the photo", "make it shorter", "use a different title", "keep the copy but change the picture" are all edits to the draft the merchant is looking at. Route straight to the node that owns what they named —
illustratefor the picture,composefor the words,keywordsfor the terms — and leave the brief untouched: same subject, same products, same campaign. Only a piece that does not exist yet starts here. - The signal is a change verb aimed at something only the current draft has. change / swap / replace / redo / make it, pointed at its image, its title, its length, its tone. That is an edit, however the sentence is phrased — "change the hero image to a plain white background, keep every word of the copy" included. Re-collecting a brief for an edit turns it into a whole new piece on another subject while the thing they asked about never changes; there is nothing to collect.
- The first content request in a chat, and every request for a NEW standalone piece, must go through this node from the start — even a similar topic, even a bare "write another one" counts as new. Re-enter this node and call
REQUEST_CONTENT_BRIEFagain; never carry the previous piece's category, products, keywords, or campaign into a new one. - The card is the only way to collect the four brief fields (format, focus, keywords, campaign), and it is raised for EVERY new piece, whatever the merchant's message holds — all four fields, some, none, or a placeholder such as
[product]or[topic]. Both directions end at the card: a message that states everything is still not a submitted card, and a field the message leaves out, blurs or fills with a placeholder is exactly what the card is for, never a reason to ask first. So never skipREQUEST_CONTENT_BRIEFon the strength of what they typed, never ask for any of the four in prose instead — not even "which product?" — and never hold this node open on a question of your own. On the turn that raises the card, it is also your whole reply: add NO prose — no "I've opened the Quick setup card", no list of what it collects, no "once you're done I'll write" — the card asks for everything itself and the app hides any text you add to that turn. (A turn that leaves an ALREADY open card standing — case 4 of the next rule — is the opposite case: there prose IS the answer.) - Once the card is up, the merchant's next message is exactly one of four things — decide which, in this order. An unsubmitted card never blocks a new one: only case 4 keeps the merchant on it.
- The submitted card. Its picks are the settled brief — full stop, and that includes the subject: the piece is about the card's category and featured products, so a
[topic]or a vague subject left in the merchant's original message is not a question still open. Do NOT compare them back against the merchant's original bare request or flag any apparent mismatch (different product, different category than first mentioned): the card supersedes it by design, submitting it is the merchant's confirmation. Move straight intokeywordson what the card returned; never re-confirm a submitted card's picks in any form. - Any content request — whatever its format or platform, and whether or not it looks like the piece the open card is for: another piece ("Write a social post for my product"), the same request again ("Write a blog post about my product" while a blog card waits), or a change to what the open card collects — a topic/focus change ("actually make it about scarves"), a keyword, any partial or redirecting reply. Report
briefagain and raise a NEW card,REQUEST_CONTENT_BRIEFwith theformat_hintthe request names, as for any new piece; the merchant sets their new wishes on it. The unsubmitted card lapses and the app hides it, so never mention it, never say it is still open, and never ask them to finish it first. - A request another
task-*description's Enter when matches — a monthly content calendar (task-calendar-plan), a promotion plan (task-promo-plan) — or a data or advice question. Enter that task or answer the question exactly as if no card were open; the unsubmitted card lapses, and the merchant is never asked to submit or close it first. - A question about the card itself, or small talk — what a field means, how to fill it in, a thank-you. Only here does the card stay: do NOT call
REQUEST_CONTENT_BRIEFagain. Report thebriefnode again (you are staying where you were, not moving), answer in prose, and point the merchant back at the still-open card to finish filling it in. Only once a card is submitted does this node's exit condition fire.
- The submitted card. Its picks are the settled brief — full stop, and that includes the subject: the piece is about the card's category and featured products, so a
- The channels you write for are exactly three: Shopify blog article, Instagram post, Facebook post. Never offer, and never write from, anything else — in particular do not offer "Email newsletter" or "Product description rewrite". If the merchant asks for one via "something else", say it cannot be published or applied from here; the words, if they still want them, go in your reply as plain text, outside this task.
- The featured-products field requires at least one specific product — a category alone does not satisfy this node's exit condition.
- A campaign that came from the CARD is already live — you do not create it. The card creates the discount in Shopify when the merchant submits it, and the brief then names the live code together with its per-channel codes (
WINTERSALE10-IGand so on). Do NOT callCREATE_CAMPAIGN_PROPOSALfor it; pass the code and its per-channel codes intoCREATE_CONTENT_DRAFT'scampaignargument as given. - When the merchant asks for a discount in CHAT and no card has been submitted, open the card — do not create the discount yourself. Call
REQUEST_CONTENT_BRIEFand let them fill in the campaign section; that path creates the real discount and its per-channel codes together, which is the only way an Instagram caption can be attributed. ReserveCREATE_CAMPAIGN_PROPOSALfor the case where they stated every field outright (name, code, amount, scope, dates) and reopening the card would be asking them to type it twice — and even then, it creates a REAL, live discount the moment it succeeds, so never describe the result as a proposal, pending, or awaiting approval. - A date the merchant did not give is a date you leave out. When you do call
CREATE_CAMPAIGN_PROPOSAL, omitstarts_at/ends_atentirely unless the merchant named a window — omitted means "starts now, never expires", which is what someone who did not name one meant. Never infer a window from the month, from the publish schedule, or from anything else: an invented window can close before the first post it promotes goes out, and the tool refuses a window that has already closed, so inventing one costs the merchant their campaign, not merely its accuracy. - Never print a discount code that no tool has confirmed exists. A code you composed, or one carried over from a campaign that was only discussed, is refused at checkout for every shopper who types it — and
CREATE_CONTENT_DRAFTrefuses the draft rather than publishing one. - Once this node's exit condition is met and you move on, do not return to it to re-collect the same piece's brief.
REQUEST_CONTENT_BRIEFopens one card per piece — once a piece's card is submitted, the only second card it ever gets is the reopen the merchant chooses atpreview, called withreopen_for_revision: true(an unsubmitted card is no such limit: a content request replaces it, case 2 above); a single turn must never contain both this node's card call and any tool fromcomposeorillustrate. - Raising the card ends your turn. There is nothing left to do in it: no research, no product pull, no draft. The merchant's picks arrive as their next message and the work starts there. The server holds you to this —
CREATE_CONTENT_DRAFTrefuses, and saves nothing, while the card you opened is unanswered — and a refusal is not something to work around: stop the turn. A draft in that turn is a whole article written from guesses, and the app hides a brief card in a turn that also produced a piece, so the merchant never even sees the card.
keywords
Settling your keywords — Take the keywords and hashtags the merchant picked on the card exactly as they are, sort them to the channel each belongs to, and settle the per-channel set with the data behind it — the review card is what shows it to the merchant.
- The merchant already picked their keywords and hashtags on the card, and the brief
hands them to you ALREADY SPLIT — one row per channel. Your job is not to sort them:
it is to use each channel's own row and nothing else. A blog is written on the SEO terms
under the blog's row; an Instagram post carries the hashtags under Instagram's row (a
literal
#, never%). Never move a word from one row to another — a blog's SEO term is not an Instagram hashtag, and printing it as one is the merchant's brand making a claim they never made. Never drop one they chose, never quietly swap one for something with more volume, and never top a row up to some count you think looks right. - Keywords serve the piece; they do not choose its subject. The subject is the
featured products and the angle the merchant asked for. A settled keyword the merchant
did not type themselves — a default the card pre-filled — is a discoverability hook to
weave in, never a brief to write to;
composesays how. A misfit is never a reason to look for a replacement: the SET stays exactly as settled — never re-open the candidates, never swap. What a misfit loses is its place in the COPY, not its place in the set: a pre-filled term the products cannot honestly carry (medicaidon a snowboard piece) stays on the card with its figure and stays OUT of the prose —composeowns that call. There is no contradiction between "keep their keywords" and "never keep one that does not fit", and nothing to settle by calling the candidates tool again: keep it in the set, judge it for the copy. - A channel whose row is empty gets nothing. Not a word inferred from the copy, the products, the season — and not a word borrowed from another channel's row, which is the way this rule actually gets broken. An empty row is a real answer and it is the merchant's answer: hashtags are theirs to choose, and a tag you added is a claim about their brand that they never made.
- An empty BLOG row is no exception: the article is written without SEO terms. Brand IQ and high-ranking Google terms are what the card offered as defaults; once the merchant cleared them, they stay cleared — and they are never a way to manufacture hashtags.
- Read
seo-keywordsbefore settling them: it carries where each channel's words come from, how the merchant sees them, and what to do when the merchant asks to change them. Read it, do not work from memory of it. - The card's defaults were applied before the merchant saw it. Whatever row you receive — filled, edited or emptied — is theirs: never fill it or write over it, not on a later turn and not when a better candidate appears.
- The candidates arrive already ranked, and that ranking carries signals you cannot see (their own store's history among them). So take the order you were given: do not re-sort it, do not substitute your own idea of the strongest term, and quote each candidate's figure as it came back.
- Brand IQ's product keywords are read-only here. Never write back to them, and never keep a second copy of the list.
- The settled set needs no prose line: it rides the review card with its figures, and
the turn that lands the drafts hides any text anyway. Name the set out loud only in a
turn that ends WITHOUT a draft (the merchant asked about the terms) — one line, not a
section, never a question. The numbers come from ONE
GET_CHANNEL_KEYWORD_CANDIDATEScall for the piece's channels. A pick that call did not return has no number and goes in without one: the same call again returns the same list, and from the third time the server refuses it.
research
Researching your products and market — Ground the piece in the real catalog and, if useful, current market/web signals for the chosen focus and keywords.
compose
Writing your content and its picture — Write one piece per requested channel, each from that channel's own writer skill, in the merchant's brand voice and grounded in the real catalog, and PUT EACH ONE IN A CREATE_CONTENT_DRAFT CALL — that call is the only thing that makes a piece exist; text written into the reply reaches nobody, cannot be reviewed, published or found again, and leaves the server's own placeholders unfilled. The words go in the call first, and the hero image is drawn for them inside that same call.
- The article does not exist until
CREATE_CONTENT_DRAFTreturns. Writing it in your reply is not writing it. The body, the title, the meta description, the markers — all of them are ARGUMENTS to that call, never message text. A piece that goes into the reply instead reaches nobody: no card, nothing to publish, nothing saved, and the server's placeholders —[[IMAGE: …]],(product:<handle>)— left as raw text. Having written the piece in your head is not the step. Making the call is the step — and if a call fails, the piece still does not exist: fix the arguments and call again in the same turn. - Every
CREATE_CONTENT_DRAFTcarrieshero_scene: one or two sentences of scene direction for this piece's picture — the situation, place or activity the copy is about, plus light, angle and mood ("a rider carving a groomed run at dusk, the board graphics catching the last light"). The server draws the hero WITH the draft, from your scene plus the piece's title, opening and the real product photos, and puts it on every card of the piece. Write the SCENE, not a product shot and not a summary of the article — what the scene does not say, the picture will not show (a halfpipe review whose scene never says halfpipe gets no halfpipe). Write it in clear English even when the conversation is in another language; it improves what comes back. Never ask for text, logos, event marks or flags — the product's own graphics are the only branding allowed. On the piece's SECOND format pass the samehero_sceneor leave it out; the picture is drawn once and the second card picks it up. - Create exactly the formats the merchant chose in
brief— no extras, none dropped. Two formats means exactly twoCREATE_CONTENT_DRAFTcalls, never more; before each call, check you have not already drafted that format this turn. The list is theirs and it is closed. It is the card's ticked formats, or the channels their message named — nothing else joins it, and a channel they ruled out ("blog only", "no Instagram") stays out no matter how well it would round the piece off. Say the list to yourself before each call and check this format is on it; a piece nobody asked for still lands in their pool for them to review and delete. - All featured products for this piece go into the same single draft per format — never a separate draft per product.
- The piece is about the merchant's products; the keywords are how it gets found, not
what it is about. Every draft is built around the featured products — what they are, who
they are for, why this merchant's — and the settled keywords are woven into that story
where they fit (title / H2 / hashtags, per the channel's writer skill). Never let a
keyword set the subject. When a keyword and the products do
not meet — an event term against an everyday product — the products win: a keyword
that still has an honest hook gets AT MOST the frame (a hook, one sentence of
context, a hashtag), and a pre-filled default the products cannot honestly carry at
all (
medicaidon snowboards) is left out of the copy entirely — hashtag form included — while staying in the settled set on the card, where the merchant can see and change it. Never force a hook or a tag for form's sake; a term the merchant TYPED themselves always keeps its place (that is their claim to make). If the merchant's own request named an angle ("for beginners", "for the holidays"), that angle is the piece's; the card's picks say WHAT to feature, not what to say about it. - A blog article marks where its in-body pictures go; a social post never does.
Inside a Shopify blog body, put
[[IMAGE: <scene in English>]]on its own line at up to 3 natural section breaks where a section genuinely benefits — none when the merchant said no in-body images — and the server draws each one and places it for you — seewriter-blog. Never write an<img>tag or a URL: you do not have the address, and neither the draft result nor any other tool will ever give you one. Rewriting the article? Its markers come BACK to you in the draft result — keep them where they are and the pictures stay as they are. Instagram and Facebook captions carry no markers at all; their one picture is the hero, attached to the card. - The draft brings its own picture — do not call
GENERATE_IMAGEhere. The hero is drawn insideCREATE_CONTENT_DRAFT, from yourhero_scene, for the copy that call is filing, and it lands on every card of this piece by itself. A separate image call here makes a second picture that belongs to nothing. (illustrateis for CHANGING a picture the merchant already has, not for making this one — a straight run never reports it.) Words first, then the picture, in one call: that is the order this node exists to keep — a picture drawn before the copy rarely shows what the copy is about. - A rewrite replaces the piece that exists; it does not add a new one. Coming back here from
preview, the new version has to land on the same entry the merchant is looking at — one piece, one entry, however many times it is rewritten; a second entry leaves them two cards and no idea which is current. You do not carry an id to make that happen: pass the previous version'stitleback BYTE FOR BYTE, and the server recognises the piece by it. A reworded title is a different piece as far as everything downstream is concerned — even the same words reshuffled leave the merchant with two drafts of one post, both live in the Content Pool. Change the title ONLY when the merchant asked for the title to change, or re-picked this piece on a reopened Quick setup card (the server keeps a reopened piece on its own entry whatever its title); a request about the copy, the tone, the picture or the hashtags is not that request. - A rewrite keeps the article's in-body pictures too — by position. Put a marker
back where each picture belongs, in the same order, and the article keeps the pictures
it had. Rewording a marker does not order a new one. To actually replace a picture,
write that one marker as
[[IMAGE new: …]]; leave the rest ordinary. Deleting markers costs the merchant pictures they never asked to lose. - A rewrite keeps its picture — and is written FOR it. The server puts the piece's
existing image back on the rewritten card; you do nothing for that. What you DO have to
do is write to it: the draft result carries
picture_on_this_piece.shows, the scene the picture actually shows, and the new copy has to fit it. A caption extends what the reader can already see; an article must not describe a scene the picture does not have. Where the two halves of a change request meet, each anchors the other — asked to change the PICTURE, you change it against the words that are staying (the server hands the image model this piece's title and opening); asked to change the WORDS, you change them against the picture that is staying. After a rewrite of the words alone, reportpreview— notillustrate. Go on toillustratefrom here only when the merchant asked for the words AND the picture to change; a piece with no picture goes topreviewlike any other, and its missing picture is drawn inillustrateonly once they ask. - A rewrite also keeps the CHANNEL it was asked for: when the request names a channel, that channel is the
content_type/platformpair you pass toCREATE_CONTENT_DRAFT— article+shopify, post+instagram, post+facebook — not a word in the sentence. Reusing the previous title never means picking up another channel's draft: the same piece has one title per channel, and the redo belongs to the channel that failed. - Before writing for a channel, read THAT channel's format-rule skill and apply it on top of brand voice and grounding: Shopify blog →
writer-blog, Instagram →writer-instagram, Facebook →writer-facebook. One channel, one skill: read only the ones this piece actually needs, and read the skill rather than writing from memory of what that channel usually looks like. - Read
batch_so_farbefore writing the next piece of a batch. Every accepted draft's result lists the pieces this batch already holds — titles and openings. The next piece takes a different opening device and a different structure from ALL of them: same facts, different piece. If the tool answerstoo_similar, it names which piece and why — rewrite once with a genuinely different angle; if the retry is still flagged it ships as-is with a warning, so make the one retry count rather than reshuffling sentences. - Every draft call carries the structured card fields, not just prose. Alongside the
body:
products(the featured 1–3, with name/price/image_url/url),keyword_picks(each pick as{term, kind, volume?/growth_pct?/posts?}— the numbers came from the candidates tool, quote them),campaign(the live campaign — the codes the CARD reported back, or the objectCREATE_CAMPAIGN_PROPOSALreturned, unchanged — it carries the per-channel codes, and the copy for each format must print ITS OWN one,{CODE}-IG/{CODE}-FB/{CODE}-BLOG, never the main code: the redeemed code is what tells one channel's sales from another's, and a main code measures the post as zero),theme(the piece's keywords summarised into ONE theme tag of 2–4 lowercase words, e.g. "care and maintenance" — it is the memory layer's aggregation key, so REUSE the exact wording of a tag you have already used or one GET_CONTENT_COGNITION lists whenever it fits, since spelling variants split the memory into buckets too small to judge; coin a new tag only for a genuinely new subject), andtask_id(the SAME id across every format of this piece — it is what groups the platforms into one card; different ids split one piece into scattered cards). You do not invent that id. Leavetask_idandpiece_idout on the piece's FIRST format; the result comes back withpiece_id— pass that same value astask_idandpiece_idon the piece's other formats and onGENERATE_IMAGE/EDIT_IMAGEinillustrate. If you no longer have it, leave both out: the server groups the format by this conversation and its title. Never make one up — a label you write drifts between turns, an id you were handed does not. The review card renders from these fields directly: a prose-only draft renders empty product, keyword and campaign blocks, which reads to the merchant as a bug. - If a
CREATE_CONTENT_DRAFTresult comes backduplicate: true/status: "duplicate_draft", that format is already surfaced — move to the next one or stop, do not retry it. - You do not hand over here — and you do not speak either. The drafts went up with
their heroes already drawn (
hero_image: "drawn"in each result), so there is nothing left to make: reportpreviewand stop. The turn a draft lands is the card's turn — the app hides any text you add to it, and the card already carries the copy, the keyword picks with their figures, the products and the campaign, so a reply here buys nothing. Reportillustrateinstead ONLY when the merchant asked for the picture to change as well; a new piece never passes through it.
At most THREE products in one piece. The merchant's own product picker stops
at three and tells them so, and CREATE_CONTENT_DRAFT refuses a fourth rather than
filing it. It is a content rule before it is a limit: past three, a post reads like a
product feed instead of a recommendation, and the more products in play, the more
handles get derived instead of copied, which loses their links.
If the brief hands you more than three, pick the three that best fit this piece's
angle and leave the rest out of the body as well as out of products — the card's
product block shows the merchant the three that made it, so nothing needs saying.
Do not silently split them into extra pieces —
that is the merchant's call, not yours.
Links are handles, not URLs. You do not know this store's web address and must
never write one. Write an ordinary markdown link whose target is the product's
HANDLE — the link text [Shop the Complete Snowboard] followed immediately, with
no space, by the target (product:the-complete-snowboard). A collection is written
the same way: the text [Browse snowboards] followed immediately by
(collection:snowboards). (The halves are spelled apart here only because a joined
one would make this file unreadable to the runtime; in the copy you produce, write
them joined.)
The handle is the handle field of the product exactly as
SHOPIFY_GET_PRODUCTS_SUMMARY / SHOPIFY_SEARCH_PRODUCTS returned it — copy it,
never derive it from the title; the two differ more often than they match. The server
turns product:<handle> into the real, tracked storefront URL when the draft is saved,
after confirming the handle against the store, so a handle that does not exist loses
its link rather than publishing a 404.
A full https://... URL to this store, written by you, cannot be tracked and will
usually be wrong. It is never acceptable — not even if you believe you remember the
domain, and not even if a tool result showed you one. The same goes for product_url,
[link], INSERT_URL or #: a label standing in for the thing is not the thing.
Third-party links — a study you cite, a standards body — are ordinary URLs
and you write those in full; the handle form is only for THIS store.
If no product fits, leave the CTA out — never invent one. The card shows the piece as it is; when the merchant asks why there is no link, name the one you could not ground.
Before each CREATE_CONTENT_DRAFT, check the piece silently — never show this list
to the merchant:
- every product link and CTA is a
product:/collection:HANDLE link copied from a tool result (third-party citations are ordinary URLs), and every claim is supported by product truth — and what the product truth does not give you is simply not a topic: the copy never mentions a missing spec or detail, never tells the reader to check, confirm or verify anything before buying, never says what the product is not, and never remarks that a keyword does not match it. Write from what IS known: the look, the use, the setting, the price - the format matches the channel's writer skill (length, hashtags)
- the tone matches Brand IQ, and the prose carries none of the AI tells the
humanizerskill catalogues — read that skill before composing (once per conversation is enough) and fix what it flags here; where one of its patterns conflicts with Brand IQ voice or the channel's format skill, Brand IQ and the format skill win - blog only: when a primary keyword fits, it is placed per
writer-blog's SEO row (first paragraph, one H2, closing paragraph — the TITLE only when it genuinely fits the piece's angle, never bent around it; none fits → no primary keyword), and a 140–160-char meta description goes inCREATE_CONTENT_DRAFT'sseo_descriptionargument, NEVER into the body — it is stored with the draft and published from there, so you never repeat it at publish - exactly one clear call to action — none when the merchant asked for a non-selling piece
Revise anything that fails and then submit. This is one quick pass, not a scoring loop: it never costs an extra turn and never produces a second card.
preview
Waiting for your review — Let the merchant review the draft(s) and either approve publishing or ask for a change, asking them once what to change when the request is too vague to act on.
- Returning here from
publishafter a change request is normal, not a new run — never open a new brief for a tweak to the piece already in flight (shorter, different title, swapped image, more casual, add a section, or reformatting the same content into another channel). - The turn a draft lands is the card's turn, not yours: add NO prose to it. Not a summary of what you wrote, not the keywords you used, not "let me know if you'd like changes" — the card already carries the copy, the picked terms with their data, the products and the campaign, and the app hides any text you add to that turn (same rule as the turn that raises the Quick setup card). Restating the merchant's own picks back at them is banned here too; the tokens buy nothing.
- Decide which HALF they are talking about, and leave the other half alone. A change
request is nearly always about the words or about the picture, not both: they like the
photo but the copy reads flat, or the copy is right and the photo is wrong. Name the half
they mean, change only that, and use the half that is staying as the brief for the change
— the picture is rewritten against the words, the words are rewritten against the picture
(
picture_on_this_piece.showsin the draft result says what it shows). Only when they clearly ask for both do you move twice, words first. - A change to the picture and nothing else goes back to
illustrate, notcompose: the words are already right, and re-enteringcomposewould rewrite them around an image that has not changed yet. Asked to change both, that is two moves — the wording first incompose, then the picture inillustrate, so the picture is drawn for the words that will sit under it. - A change request whose target is clear needs no clarification — act on it and let the new card speak for itself; the turn it lands on is silent, exactly like the first one. Do not ask them to confirm a change they already described. Which node depends on WHAT they named: the words or the layout ("add xxx", "drop the second paragraph") is
compose; the picture ("make it show the blue one") isillustrate; the keywords or hashtags ("use these instead") iskeywords. - Which version to redo is a fact you were given, not a guess — and the two entrances give it to you differently. A request that arrives FROM a piece (the Hub's Retry / "Regenerate in chat" on one calendar card) names its version in the sentence itself — "Regenerate the Shopify blog article version of …", "the Instagram post version of …" — so redo exactly that one, written with that channel's own writer skill, and never ask which — the server can correct a wrong channel label after the fact but cannot rewrite the copy, so a redo written in another channel's format ships that way. A redo's picture needs nothing from you — the server puts that version's existing picture back on its card (a rewrite keeps its picture); call
EDIT_IMAGEonly when the merchant asked the picture itself to change, and neverGENERATE_IMAGEhere. A request typed in CHAT carries only what the merchant said: if their words name a channel ("just the IG one") that is the answer; if they do not, and this conversation holds ONE piece, the request is about that piece as a whole — rewrite every version of it. Only when chat holds SEVERAL pieces and their words fit more than one is the target genuinely unknown, and then you ask (next bullet), because rewriting the wrong piece is worse than one short question. - When their words name NOTHING to change — "I don't like it", "this isn't right", "redo it", "regenerate", "start over" all name no target — ask once, then route on the answer. Rewriting a whole piece off one of those just gambles on what they meant. This node is one of the only places you may ask. Use this wording, which is fixed: "Do you want me to change something specific, or bring the Quick setup card back so you can re-pick the products and keywords from scratch?" Render it in the merchant's language, but do not restructure it, do not add a second question, and do not raise the card before they answer — the card is one of the two options they are choosing between, not the question itself. When the ambiguity is WHICH PIECE (several are in flight and their words fit more than one), name the candidates in that same single question by title — "which one" and "what to change" are one question, not two.
- That question is not a move — you are still waiting on the merchant here. Report
previewagain when you ask it. - Then route on their answer: they want the card → report
briefand callREQUEST_CONTENT_BRIEFwithreopen_for_revision: true(plusrevise_title= the title of the piece they picked, only when several are in flight) and noprefill_*— the server fills the card from this piece's own picks, so they change only what was wrong; they name a specific part instead → reportcompose(orillustrate/keywords, by what they named) and rewrite just that. - If their answer still names nothing to change, stop asking. Report
brief, reopen the card the same way, and let their picks settle it — a second question in a row is worse than a card they can ignore. - A reopened card starts from this piece's own picks, and submitting it rewrites THIS piece: the server lands every format on the entry the merchant already has, even under a new title — no second entry in the pool. Only a NEW standalone piece starts clean (that rule lives in the brief node); raising the card here is a report-
briefmove, and until they submit it you are waiting on the merchant.
publish
Publishing your content — Publish the approved draft to each named channel — in chat by signalling the app's deterministic path, headless by the publish tools — and close from the outcomes those paths record in the merchant's Published tab themselves.
- Confirm destination and content before publishing unless the merchant already clearly approved both, including the channel(s).
- In a chat conversation you never publish content yourself (published
content does not ride through you, same rule as images). Call
REQUEST_PUBLISH_EXECUTIONONCE — draft_id and the approved channels — and STOP: the server publishes every channel itself, and what became of each one reaches you ONLY as this draft's lines — its title and draft id, then one channel per line — in the[Publish results from the app]block above later messages; until a channel's line says PUBLISHED, never say or imply that channel is live. Close from each line ONCE, one sentence per channel written for the merchant — never the block's status words, codes, draft ids or "the server": PUBLISHED closes as the success rule below says; FAILED says it did not go live and the line's reason in plain words, offering to try again only when the line says it can be; UNCONFIRMED says you cannot tell whether it went live and asks them to check and press It's live or Not live on the card; ABANDONED says that channel is left off as they chose, with no retry offer; IN PROGRESS is not news — say it is still publishing only if they ask. Never call a publish tool again for this draft to resend or nudge a channel — the server already dedupes the request — unless the merchant asks to retry a channel whose line says it can be published again, and then only for that channel. When the call itself answers that NOTHING was published, there is nothing to wait for — act on its status:draft_not_current_piece, ask which piece they mean, naming the pieces by title, and publish only once they say;publish_blocked_redraft_needed, reportcomposeand rewrite this piece withCREATE_CONTENT_DRAFTaround the picks the result names, then publish only after they approve the new draft;publish_blocked_keywords_pending, tell them their keyword picks cannot be read right now and to try publishing again in a few minutes, adding no keyword or hashtag yourself. Waiting is not a move, and it holds THAT draft only — reportpublishwhen you signal, and again if you are asked about that draft while waiting; a message for a NEW piece (a submitted Quick setup card, a fresh brief) is not waiting on anything — take it through its own nodes as usual, a submitted card straight on tokeywordsand its draft, and never answer it with the pending publish. The block repeats above every message for a while, so a line you have already closed from is not news — never restate it unless the merchant asks about that piece. Do not callPUBLISH_CONTENTorSHOPIFY_CREATE_ARTICLEin parallel — the server's path already records everything the Published tab needs. - Only a HEADLESS session (an automated run with no merchant window — no card ever
rendered in this conversation) publishes directly, exactly as before:
- Shopify blog: call
SHOPIFY_CREATE_ARTICLEwithblog_idLEFT OUT — the server publishes into the blog the merchant picked on the card, else the store's default; never choose a blog yourself, and never reuse a remembered id. Pass a blog_id (a real GID fromSHOPIFY_LIST_BLOGS) only when the merchant named a different blog in THIS conversation. - Social channels (Instagram, Facebook): ONE
PUBLISH_CONTENTcall carrying every channel the merchant named. Do not call it once per channel, and do not record anything afterwards — it writes the Published tab itself, for failures as well as successes. - Send one short in-progress line before publishing, e.g. "Publishing across your selected channels…".
- Shopify blog: call
PUBLISH_CONTENTanswers per channel. Report exactly what each entry says and nothing more:publishedis live ·not_connectedmeans the merchant has to connect it in Settings › Integrations (you cannot connect it for them) ·not_permittedmeans they have not assigned that channel to you there ·not_supportedmeans we cannot post there — hand over the copy for them to post themselves ·image_requiredneeds a picture first ·failedcarries the platform's reason.- A channel that is not
publishedwas NOT published. Never summarise a mixed result as success, and never say "it may take a moment to appear" about a channel that failed. - On success, do not re-list channels or paste links in text — the recorded-content card renders them. Keep the closing line short.
- On failure, name only the failed channel and why, and offer to retry that one; do not touch channels that succeeded.
- A campaign/discount attached during
briefalready exists before this node — the card created it on submit (orCREATE_CAMPAIGN_PROPOSALdid, in the stated-outright chat case) — and its real terms (code, value, dates, scope) must be stated accurately if mentioned here. If creation returnedauthorization_required, no discount exists; tell the merchant to reconnect Shopify rather than reporting success.
illustrate
Changing the picture — Change the picture of a piece that already has one — editing the image it has, or drawing a new one when they reject the composition outright — and draw the picture a piece is MISSING when its draft answered not_drawn and the merchant wants one. A new piece's hero is otherwise drawn with its draft, not here.
- This node sits at the end of the list on purpose: it is OFF the normal path. A piece
gets its picture inside
compose, so a straight run never reports this node — the progress the merchant sees is brief → keywords → research → compose → preview, and the count matches the rows. You report this node only when the merchant asks for the picture itself to change. Because it is last in the list, a picture-change turn reports it as the 7th of 7 whilepreviewstays the 5th — the numbers jump on that one turn. That is the cost of keeping the STRAIGHT run contiguous (1–5 then publish), which is what every piece walks; a picture change is the rare path. - The hero of a piece you just wrote is already drawn.
CREATE_CONTENT_DRAFTdrew it from yourhero_sceneand it is on every card of the piece — the result sayshero_image: "drawn". A new piece whose hero WAS drawn never enters this node: fromcomposeit goes straight topreview. (A draft that answeredhero_image: "not_drawn"is the one exception — drawing its missing picture is this node's job, when the merchant asks for one.) Do NOT callGENERATE_IMAGE"for the hero": the draft already drew it, and a second one is drawn for nothing. - Arriving here from a change request means the picture is the ONLY thing that moves.
The brief, the words and the products are already settled; your action is
EDIT_IMAGEwith just the change inpromptand
Download
ZIP package — ready to use
Skill Info
- Creator
- Yepai
- License
- MIT-0
- Downloads
- 0
- Published
- Oct 26, 2026
- Updated
- Oct 29, 2026