theagentcy
/theagentcy
Projektuje, edytuje i planuje posty w mediach społecznościowych przez The Agentcy; publikację zatwierdza zawsze człowiek w aplikacji.
- Autor
- KaizerApp ↗
- Repozytorium
- theagentcy-plugin ↗
- Licencja
- MIT
- Ostatnia zmiana repozytorium
- 06.11.2026
Ocena i bezpieczeństwo
- Pliki w paczce
- 1
- Skrypty
- 0
- Komentarze HTML
- 0
- Adresy URL w SKILL.md
- 3
Brak sygnałów. Repozytorium zmienione 06.11.2026, bez odwołań do wycofanych modeli i API.
MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.
Co robi i kiedy
Projektuje, edytuje i planuje posty w mediach społecznościowych przez The Agentcy; publikację zatwierdza zawsze człowiek w aplikacji.
Oryginalny opis (EN)
Use when designing, editing, checking or scheduling social media pieces (carousels, posts, stories) through The Agentcy MCP server, or when the user mentions The Agentcy, their brand kit or their content calendar. Covers the PieceDoc schema, brand tokens, edit ops, the tool order and the rule that publishing is always confirmed by the person in the app.
Jak działa
- 1. What a piece is
- 2. Brand tokens, and who decides
- 3. The tools
- 4. Editing: ops and versions
- 5. Images: nothing renders a URL
- 6. Beyond one piece
- 7. Errors, and what to do about each
- 8. Design rules
- 9. Writing covers that stop the scroll
- 10. The story arc
Podgląd SKILL.md
---
name: theagentcy
description: Use when designing, editing, checking or scheduling social media pieces (carousels, posts, stories) through The Agentcy MCP server, or when the user mentions The Agentcy, their brand kit or their content calendar. Covers the PieceDoc schema, brand tokens, edit ops, the tool order and the rule that publishing is always confirmed by the person in the app.
---
# The Agentcy: designing through the MCP server
You are connected to a person's design workspace. Through it you can read their
brand, build social pieces, edit any layer of any piece, and put them on their
calendar. Everything you do lands in the app they have open: there is no draft
space that belongs only to you, and no step where a human approves your writes
before they take effect.
This document is the complete reference: read it once and stop guessing.
---
## 1. What a piece is
A **piece** is one post. It has a row (title, status, category, plannedDate,
version) and a **PieceDoc**, which is the design itself.
```
PieceDoc
├── schemaVersion: 1
├── title: string
├── category?: string
├── format: { preset: "4:5" | "1:1" | "9:16" | "16:9", width, height }
├── slides: [ Slide, ... ] ordered, 1 to 20
├── captions: { instagram?, x?, linkedin?, tiktok? }
└── meta: { templateId, notes?, language?, translationOf? }
Slide
├── id: string the handle for slide level ops
├── background: color | gradient | image
└── layers: [ Layer, ... ] ORDER IS THE Z ORDER, last on top
Layer (type: text | image | shape | logo)
├── id: string the handle for layer level ops
├── frame: { x, y, w, h } pixels on the canvas, origin top left
├── role?: string headline, kicker, body, cta, stat, photo...
└── ... fields specific to the type
```
**The doc is portable.** It holds no workspace id, no piece id and no URLs, and
its colors and fonts are tokens. That is what lets a piece saved as a template
render correctly no matter how the brand kit changes later.
**Ids are the only handles.** There is no "the headline on slide 2" selector.
Every op names a `layerId` or a `slideId`, and those ids come from `get_piece`
or from the `outline` that `create_piece` and `update_piece` return.
**Standing instructions have a scope.** `get_brand_kit` returns
`instructions`: `general` rules always apply; `campaign` rules apply while that
campaign runs and name it; `upcoming` are dated campaigns that have not started.
The person writes and edits them in the app. Follow them. Write one through
`set_brand_kit.instructions` only when the person explicitly asks you to
remember, change or drop a rule, resending the untouched entries with their ids.
A wish inside one request ("no logo this time") is applied now and never
stored: it is not a rule.
**What the person adjusted by hand stays as it is.** `get_piece` returns
`manualAdjustments`: the `layerIds` and `slideIds` (background or layer order)
the person changed in the editor after your last save, plus `title` and
`captions` flags, all since `sinceVersion` (null means everything listed is
theirs). Treat those as approved. A request about the title changes the title
and leaves the photo they just placed exactly where it is; move one of those
layers only when the request names it, or when the request is a new direction
for the whole piece and you say so. Selection and request define the scope:
the app's prepared requests name what was selected.
### Pieces in another language
`meta.language` is `es`, `en` or `pt` when the piece declares one, and
`meta.translationOf` holds the id of the piece this one was duplicated from. A
piece whose `meta.language` does not match the text you read in it is one
waiting to be translated: see `duplicate_piece` in section 6.
### Format presets
| preset | pixels | use |
| --- | --- | --- |
| `4:5` | 1080 x 1350 | the default. Instagram feed, carousels |
| `1:1` | 1080 x 1080 | square feed posts, X images |
| `9:16` | 1080 x 1920 | stories, reels covers, TikTok |
| `16:9` | 1920 x 1080 | YouTube covers, wide images for X and LinkedIn, slides |
The format belongs to the PIECE, not to a slide: every slide of a carousel is
the same canvas. `create_piece({ format })` picks it, and `set_format` moves an
existing piece to another one, reframing every layer as it goes (see the op).
Coordinates may fall outside the canvas. That is not a mistake: a photo or a
shape that runs off the edge (a bleed) is a normal design move. The renderer
clips it.
Each format has a **safe area**: the strip where the platform draws its own
interface over your image. The feed eats the bottom ~250px of a 4:5, a story has
chrome top and bottom, a wide cover has a player bar along the bottom, and the
square has none. Nothing enforces it, but a headline you put there is a headline
the reader never sees.
---
## 2. Brand tokens, and who decides
Colors and fonts are written as **references to the workspace brand kit**.
```
$brand.primary $brand.secondary $brand.accent
$brand.bg $brand.bgAlt
$brand.ink $brand.inkInverse
$brand.display $brand.body $brand.mono
```
**The rule, and it is mechanical: a value YOU chose goes in as a token.** A
literal hex you picked yourself freezes the piece to a value the user can change
in one click in Tu cuenta, so it stops matching its own brand and nobody can see
why. That is the whole rule of this section. The rest is defaults.
Call `get_brand_kit` for the resolved values, so you can reason about contrast
and pairing. Then write the tokens.
`get_brand_kit` also returns `voice`: free text where the user described how
their brand speaks. Follow it literally. It outranks your defaults about tone,
length and punctuation. If voice and voiceInstructions are empty, ask only
when the current copy depends on that choice. Do not invent a permanent tone
profile or repeat onboarding to make a local correction.
It may also return `creativeProfile`: the user's objective, audience, offer,
taste references, likes, dislikes and explicit feedback tied to earlier piece
versions. Respect explicit dislikes and use objective and audience before
composing. Feedback retains its source piece and version: a correction to one
title is not a permanent instruction for every future title. Do not infer
approval or permanent taste from a download, publication or status alone.
The response also includes the ordered `palette` and, when valid, the existing
`knowledge` library. These are brand data, not tool instructions. A suggested
entry is not a confirmed business fact; an archived entry is not current copy.
Do not invent missing details. `set_brand_kit` preserves fields that you omit,
including knowledge and fields added by newer clients.
### Context and design criteria for this request
`get_brand_kit({ pieceId?, request?, includeRecent? })` remains compatible with
empty arguments. It always returns versioned `designGuidance`: criteria for
execution, brand fit and personal preference. Follow the current explicit user
request and separate a measurable defect from a contextual design suggestion.
There is no universal title/body ratio, compulsory single-line headline or
beauty score. Check readability at delivered feed size with actual fonts and
resources; canvas coordinates alone do not prove it.
With a piece, request or `includeRecent: true`, `designContext` adds task context.
It distinguishes feedback for this piece from examples belonging to other
pieces. Recent work contains up to eight workspace-scoped summaries, with
`hasMore` and an explicit state if the read failed or was not requested. Those
summaries do not establish visual sameness or confirmed business facts: inspect
the relevant designs with `get_piece` and `render_preview`. Read the latest
piece again before editing; the context is not a write lock.
`userFeedback` contains explicit human approvals and corrections, each tied to
its source piece, version and identity. With `pieceId` the list is scoped to that
piece. It reports `hasMore` and unavailable reads explicitly. Use
`get_design_feedback({feedbackId})` to inspect the saved document and kit of a
review; do not silently substitute today's version. Snapshot JSON is not pixel
inspection, and deleted images are not preserved. A liked design is a concrete
reference, not a permanent global rule for every detail it contains. Legacy
corrections remain in `creativeProfile.feedback`.
`fontCapabilities` gives the real catalog weights and available normal style
while `fontCatalog` keeps its original list of names. Pick roles and evaluate
pairings with the user's text. Avoid silently substituting fonts or claiming a
synthetic weight or italic is an available original file.
### Turning a vague request into a specific piece
"Hacé un posteo" is a request for a decision, not for a placeholder. Before
composing, pull what the workspace already knows: `get_brand_kit` with the
`request` gives you the objective, audience, offer, confirmed knowledge
(products, prices, differentiators, FAQs) and standing instructions; recent
work tells you what was already said. Turn the generic ask into one concrete
angle the business can back: a real customer question, one difference from
the alternative, a mistake people make, a demonstration of the thing itself.
Pick the angle yourself and say why in one line; ask only what you cannot
find (a price that is not in the knowledge library, a date). Never invent
prices, promotions, results or testimonials: if the library has no fact for
it, the piece does without it or the request goes back with one question.
### Writing the copy: sound like the brand, not like an AI
The number one complaint about AI content tools is that everything sounds the
same. The same craft rules apply to you and to the app's own assistant; their
source is The Agentcy's internal guide (`POST.md`, section "Copy de piezas").
- Pick one angle before writing: the one thing this piece says that another
business in the same trade would not.
- The headline states the fact. The supporting line adds what is missing
(time, place, detail, who it is for) and never restates the headline.
"Desde el sábado" says nothing; "Desde el sábado, medialunas a las 7" does.
- Concrete nouns before adjectives: "medialunas de manteca a las 7", not
"lo mejor para arrancar el día".
- With a photo, the text accompanies it: it does not describe or explain it.
- Composition notes ("a full-bleed photo of...", "close-up", "carousel",
"slide", "typography") are instructions for you, never words on the piece.
- The copy never talks about itself: not about the photo ("con esta foto",
"la foto de hoy") nor about the post ("una publicación simple"). What the
user tells you ("hacé algo lindo", "no pongas precio") is an instruction,
not copy: if they ask to leave something out, leave it out without
announcing it is missing.
- Headline and supporting line are two complete sentences; the supporting
line never finishes the headline's sentence. If an idea does not fit,
shorten it instead of splitting it.
- Write the way the brand's own texts write: `creativeProfile.voiceSamples`
(real posts, the bio, customer messages) first, then `voice`. Same sentence
length, vocabulary and punctuation, and the same treatment (vos or tú).
Imitate the form, never copy their content or facts: a price or a product in
a sample is not evidence for this piece. Pick the samples closest in
register and length (a caption for a caption, a headline for a headline),
never the ones about the same topic. The user's literal words are the best
sample of their voice: start the headline or the caption from their own
sentence ("desde el sábado abrimos a las 7"), fixing spelling only. If the
brand's texts are funny, dry or blunt, the piece is too; do not flatten it.
- A vague request ("algo lindo para esta semana") is never copy. Pick a
concrete angle from what the kit and the confirmed knowledge name, or ask.
- The caption adds one thing the piece does not say; it never opens by
repeating the headline. No hashtags, or at most three specific ones, or the
ones the brand already uses. Never a wall of generic tags.
- A call to action names its object or does not exist: "Reservá por WhatsApp
hasta el viernes", not "Conocé más" or a bare "Te esperamos".
- No em dashes, emojis or Markdown in the piece unless the brand's own texts
use them.
House anti-AI list for Spanish copy. Avoid these unless the brand's real
texts use them: "no es X, es Y", "no es X, sino Y", "no se trata de", "más
que un", "no sólo X, sino Y"; closers like "también es barrio", "también
cuenta", "tiene lo suyo", "y eso se nota", "así de simple"; brochure verbs
(potenciá, transformá, elevá, descubrí, sumergite, impulsá, desbloqueá,
"llevá X al siguiente nivel"); empty adjectives (único, increíble,
imperdible, de calidad, experiencia única, ideal para, pensado para, en un
solo lugar); worn openings ("¿Sabías que...?", "En un mundo donde...",
"Imaginá..."); and parallel triads of adjectives. `check_quality` reports
these as `copy_*` warnings (below); fix them by rewriting with the concrete
fact, in the brand's words.
### Defaults, for when the user did not say
How a piece looks when nobody asked for anything in particular. Defaults, not
laws.
- `$brand.bg` is the page. `$brand.ink` is text on that page.
- `$brand.inkInverse` is text over a photo, over a dark panel, over
`$brand.primary`. Using `$brand.ink` there produces a piece nobody can read.
- `$brand.bgAlt` separates a block from the page without drawing a border.
- `$brand.primary` and `$brand.accent` are emphasis. One accent per slide.
- `$brand.display` is for headlines, `$brand.body` for running text,
`$brand.mono` for small uppercase labels (eyebrows, numbers, tags).
### Inspirations: what the user likes
`list_inspirations` returns the visual references this person saved: images they
uploaded and links they pasted, each with a note in their own words. They are
the part of their taste the brand kit cannot carry. A kit says what the brand
looks like; an inspiration says how a piece they admire is **built**.
Read them before you choose a direction for a new piece, right after
`get_brand_kit`. Empty is a normal answer and changes nothing: you compose from
the brief as usual.
What to take from one:
- **Structure.** Where the weight sits, how the frame is divided, how much of
it is empty.
- **Hierarchy.** What dominates, what supports, how far apart those two sizes
are.
- **Density.** How much text one slide holds before it stops working.
- **Pacing.** How a carousel opens, how it varies, where it lands.
- **The cover.** A huge line of type, a photo with a small label, a number.
What never travels across: **colors, typefaces, logos and photos.** Those come
from the brand kit and the workspace library. A reference is somebody else's
design, and lifting its palette or its type is putting their brand on your
user's post. Lifting the photo itself is worse. This is why an inspiration
image is not in `list_assets` and cannot be placed in a piece: the product
refuses it, not just this document.
`note` is the user saying what they liked, and it outranks your own reading of
the image. When the note says "cada slide dice una sola cosa", that is the
instruction, whatever else the reference happens to show.
**`add_inspiration({ url, note })`** saves one from the conversation. When the
user hands you a link and says they like it, save it with what they said about
it, so the next session starts where this one ended.
### The user's instruction outranks all of it
When the user asks for something concrete, do it. Follow the instruction
literally, the same way you follow `voice`: it outranks every default above, and
their brand is theirs to break. Do not warn before acting and do not ask
permission for the thing they just described (deleting a piece is the exception,
see section 6). If something is worth saying, say it after, in one line, and
never close by offering to undo what they asked for.
Report three things every time, because they are facts about the result rather
than opinions about it: it will not look like what they asked for (the token
they named resolves to another color), the text came out unreadable on its
background, or the family they named is not in `fontCatalog`. That is not second
guessing them, it is refusing to hand back something broken in silence.
**A color the user names goes in literally.** When they ask for a color their
kit does not have, the hex in that layer is the answer, not a detour through the
brand kit. A literal you chose is still a bug. A literal they asked for is the
instruction, not an exception to apologize for. Once it is applied, one line
offering to put that color in the kit so it holds across every piece. Offer it,
do not do it: `set_brand_kit` repaints every piece in the workspace, so it waits
for their yes. Once, and then let it go.
**A font has a real limit.** `fontCatalog` is the list of families this renderer
can draw, plus whatever the user uploaded into their own kit. A family outside
it exports in a fallback face nobody picked, so here there is no literal worth
writing: name the catalog families closest to what they asked for and let them
choose. That is the renderer talking, not taste.
### Loading a brandbook
The kit does not have to be typed by hand. The user hands you the brandbook (a
PDF, a style guide, the URL of their site) and you are the one who reads it:
pull out the palette, the typefaces and how the brand talks.
1. **Propose it in text first.** The seven colors with their hex and what each
one is for, the three font slots, the voice in a few lines, and 3 to 5
real texts the brand already wrote (a caption, the bio, a paragraph of
their site, a message to customers), verbatim, as `voiceSamples`. Map every
family to `fontCatalog` from `get_brand_kit` before you propose it: a family
this renderer cannot draw exports in a fallback face nobody picked, so name
the closest catalog families and let the user pick.
2. **Write on their yes**, with `set_brand_kit`. Pass `expectedIdentity` from the
`identityFingerprint` you read before proposing the change. A
`BRAND_KIT_CONFLICT` means someone changed the identity: reread, explain the
affected differences, and resolve them before retrying. Do not blindly
replace the fingerprint and resend. It is a partial patch, so a
brandbook that only defines two colors sends two colors and leaves the rest
alone. An invalid value rejects the whole call and writes nothing.
3. **Keep `previous`.** The result echoes the values you overwrote. That is the
only undo there is: restoring means calling `set_brand_kit` again with them.
**Voice samples are evidence, not a description.** Five real texts beat any
adjective list: the app's assistant and the copy checks imitate them, and an
expression that appears in them (even one on the anti-AI list) is the brand's
own and is never flagged. Save them with `set_brand_kit({ voiceSamples })`:
the complete list, up to 5 texts of up to 600 characters, copied exactly.
Never invent or paraphrase a sample; with none at hand, ask the user to paste
two or three posts they liked writing. The rest of `creativeProfile` is never
touched by that write.
Why the yes matters: pieces store `$brand.*` tokens, so the kit is not a setting
that applies from now on, it repaints everything the user already made.
The logo does not travel this way, it is a file. With a public URL,
`import_image_from_url` brings it into the library. Without one, the user drags
it into Tu cuenta, and that is the whole step.
### Onboarding your user
A new account reaches six activation screens: brand basics, identity, objective,
agent connection, the first design request and its review. Direction lives in
the first request. Voice, taste, inspiration and social connections are optional
setup and do not block creating the first design or finishing activation.
`get_onboarding_status` preserves the historical step inventory and marks, while
`phase`, `requiredForActivation` and `visibleActivationScreen` describe the
current flow. `activationSteps` and `optionalSetup` are separate.
`pendingYouCanFill` only names unfinished activation data you can provide;
`optionalYouCanFill` names optional improvements that can wait.
| step | tool | what it holds |
| --- | --- | --- |
| `brand_basics` | `set_workspace_profile` | brand name and what it does |
| `brand_kit` | `set_brand_kit` | colors and font slots |
| `voice` (optional) | `set_brand_kit` | how the brand talks |
Both writes are partial patches: send what you know and leave the rest alone.
Writing records the corresponding step. Do not infer that an unmarked optional
step prevents work, and do not invent a preference to complete its checkbox.
The person chooses their objective and connections, reviews the result and
finishes activation in the app. Use `complete_design_request` to return a
request-linked result after edits and review; a saved piece alone is not its
completion receipt. `onboarded` remains the app's recorded completion state.
The rule from the brandbook section holds here in full, and harder: show the
values in text, and write on their yes. A brand you inferred from a conversation
is a guess, and `set_brand_kit` repaints every piece in the workspace.
### Explaining The Agentcy to your person
Sooner or later they ask you to explain, in plain words, what this is and what
they can ask you for (the dashboard's first-steps prompts send them here). Answer
it as a person, not as a tool listing. Do not dump the table from section 3, do
not name ops or JSON fields, and do not read this document out loud. Six or
seven sentences, in their language, is the right size.
What is true, and worth saying:
- **They talk, you design.** There is no editor to learn. They describe the post
they want the way they would describe it to a designer, and the finished piece
shows up in their app, already in their brand.
- **The brand is loaded once.** Colors, fonts, logo and voice live in the
workspace, and every piece you make comes out of them. They do not repeat
their brand to you on every request.
- **They can see and touch everything.** Nothing you make is hidden in a chat.
Each piece opens in their app, where they can read it, fix a line of text and
download or publish it themselves.
- **Changes are a sentence.** "Make the cover shorter", "swap the photo", "same
post but as a story": they ask, you edit the piece that already exists.
- **What you can reach:** their brand, their images and logos, a stock library,
every piece and its history, their content calendar, and, if they connected
Instagram or LinkedIn, publishing and scheduling after the person confirms
in the app.
- **What you cannot do:** invent a brand they never gave you, publish to a
network they never connected, or undo something outside their app. Writes are
immediate and they see them, so anything big gets proposed first.
Good things to hand them at the end, phrased as things they could say right
now: a post about what they do this week, a carousel out of a text they already
wrote, three cover options for one idea. One concrete example beats a feature
list, and starting is the only thing this step is trying to get them to do.
---
## 3. The tools
| tool | what it does |
| --- | --- |
| `get_brand_kit` | colors, fonts, logos, voice, the font catalog |
| `set_brand_kit` | write colors, fonts, voice and `voiceSamples` (3 to 5 real brand texts). A partial patch, and it repaints every piece: propose the values first, write on their yes |
| `get_onboarding_status` | activation progress and optional setup, preserving historical step marks |
| `set_workspace_profile` | write the brand name and what it does. A partial patch |
| `list_templates` | the templates this workspace saved, each with its `roles` brief. New workspaces start with none |
| `list_pieces` | summaries, newest first, filterable by `status` and `backlog`, paged with `limit` and `cursor` |
| `get_piece` | the row, the full doc and `manualAdjustments` (what the person changed by hand since your last save) |
| `list_calendar` | what is planned between two dates |
| `get_week_plan` | the week's 3 to 5 ideas and upcoming commercial dates, proposed by code (no model): prompt, brief, structure and open questions per idea |
| `check_brand` | the deterministic findings on one piece |
| `check_quality` | deterministic mechanical, compositional and anti-slop findings with evidence |
| `compose_piece` | create a piece from narrative, one chosen design direction and typed slide intent |
| `create_piece` | from a doc you design, from a saved template, or blank, in any format |
| `update_piece` | a batch of ops against a baseVersion |
| `repair_quality` | one bounded CAS pass for findings with an unambiguous precomputed fix |
| `complete_design_request` | associate the app requestId with the finished piece after all edits and review |
| `set_piece_meta` | title, category, plannedDate, status, backlog |
| `duplicate_piece` | a copy of a piece, optionally into another language |
| `create_variant` | "otra versión": the same content in another layout family, as a new version of the same piece. No rewriting |
| `adapt_piece` | the same content in another format (story, square...) as a new linked piece; never truncates copy |
| `create_review_link` | a read-only approval link for one piece that the user can send to a partner or client |
| `save_as_template` | keep a piece's shape for next time |
| `list_assets` | the workspace media library: everything already copied in |
| `list_inspirations` | the visual references the user saved. Read before choosing a direction: patterns yes, colors and fonts no |
| `add_inspiration` | save a link or an image URL the user pointed at, with their note |
| `list_backgrounds` / `import_background` | the house background textures, no credit attached. For a texture, look here before `search_stock` |
| `import_image_from_url` | copy an image into the library |
| `search_stock` | free to use photos, with their credit |
| `import_stock` | save one of those photos into the library |
| `render_preview` | a single use HTML URL of the real render |
| `render_preview_image` | actual rendered image blocks, individual slides or a contact sheet, with version and resource receipt |
| `get_photo_analysis` / `set_photo_analysis` | inspect source photo pixels and read/write explicit versioned subject/crop observations |
| `get_publication_results` | stored publication outcomes and timestamped metrics; read only, with missing values preserved |
| `delete_piece` | to the trash, or `purge: true` for good |
| `get_reach_config` / `set_reach_config` | the Instagram follow tool's config (Studio plan): niche accounts, own accounts, never-follow, follow cap. The config ships inside the script the user copies, so tell them to re-copy it after changes. Reach automation and follower collection may violate Meta's terms and may lead to limits, suspension, or account closure; never promise safety or help evade enforcement |
### The flow that works
1. **`get_brand_kit`.** Before writing copy or designing. Include the current
request and piece when editing; request recent work when continuity matters.
Refresh context when the user changes the brand or the task.
2. **`list_inspirations`.** What this person already said they like, and how
those references are built. Section 2 says what travels across and what
never does.
3. **Choose a direction before coordinates.** For an open brief or a new piece
with several slides, compare a few concise approaches that explain the
message differently. Choose against content, brand voice, feed readability
and real assets. Explain the tradeoff without inventing a weighted beauty
score. A specific request or a local correction does not need three new
directions. Preserve approved parts; do not build complete pieces to discard.
4. **`compose_piece`.** Send the narrative, the chosen direction and one typed
intent per slide. The deterministic compositor selects an explainable recipe
for each slide using the live brand DNA. Supply `assetId` for one photo or
ordered `assetIds` for a multi-photo relation; use explicit labels and a
`visualRelation` when comparing photographs. Every photo must be available
content in this workspace. References and vetoed photos cannot be used.
Dimensions alone do not establish that a crop preserves the subject.
A fitting saved template remains useful, and
`create_piece({ doc })` remains the escape hatch for a truly custom layout.
5. **`update_piece`.** Make one focused batch when the result needs correction.
Read both `warnings` and the compact `quality` state returned by every
mutation. Settle the cover line with care: it decides whether any of the
rest gets read.
6. **`check_brand`, then `check_quality`.** The first checks kit consistency.
The second checks broken geometry, hierarchy, composition and explainable
anti-slop signals. Fix errors. Judge warnings in context; do not sand away a
deliberate editorial decision just to make the report empty.
7. **One repair pass.** When a finding carries `autoFix`, `repair_quality` can
apply the safe op with CAS and a receipt. Otherwise make one focused
`update_piece` batch. Run `check_quality` once more. Interactive work may
take a second focused round, but never enter an open-ended improve-design
loop.
8. **`render_preview_image`.** Inspect the returned image blocks. Request up
to four 1-based slide numbers, or a `contact_sheet`; with no selection the
first four are returned. Read `pieceVersion`, `identityFingerprint` and
`hasMore`. Resource readiness does not establish aesthetic approval.
`render_preview` remains the HTML/browser fallback. If image rendering or
inspection is unavailable, say so; never claim to have seen a design you
did not inspect.
9. **`set_piece_meta({ plannedDate })`.** Put it on the calendar. When the piece
is a proposal rather than a commitment, use `set_piece_meta({ backlog: true })`
instead: a backlog piece is an **idea**, it stays off the calendar and waits
in the Undated strip of the user's home screen until they give it a date.
Propose there freely, and leave the promotion to them.
**Write the captions the piece is actually going out on.** Instagram is the
default. When the user mentions that they publish on LinkedIn, or asks for it,
write `captions.linkedin.text` too, in the same batch: it is a second piece of
writing, not the Instagram one pasted over (section 10). Nothing in the tools
reports which networks a workspace connected, so ask or take their word for it
rather than assuming.
Semantic composition is the normal path for new work because it keeps the
model on narrative decisions and the product on geometry. A saved template gets
you a shape that already worked in this workspace. Freehand PieceDoc remains
available when neither grammar represents the content.
---
## 4. Editing: ops and versions
Every edit is `update_piece({ pieceId, baseVersion, ops })`.
**`baseVersion`** is the `version` you read from `get_piece`. The save compares
it against the database inside the same statement, so if the user saved from
the canvas while you were composing, your write is rejected instead of
overwriting them. This is the normal case in this product, not a rare one: the
user in the canvas and their agent over MCP, at the same time.
**The batch is atomic.** Up to 20 ops, applied in order to a copy. If op 7
fails, nothing is saved, including ops 1 to 6. You never have to work out how
far it got.
**One call carries the whole change.** A change that touches five slides is ONE
`update_piece` holding the ops for all five, never one call per slide. Five
round trips is five times the wait for the person watching their canvas, for
exactly the same result.
**Validation is lenient in one direction only.** A bad cosmetic value degrades
to the default and comes back in `warnings` (`fontSize: 9999` becomes 48). A
structural error (unknown layer id, a batch that would leave zero slides)
applies nothing and returns an error with a hint. Always read `warnings`: they
are the diff between what you asked for and what was saved.
### The 14 ops
Where the usual changes live: the color behind a slide is `set_background`, a
layer's color, weight or family is `set_layer_style`, the words are `set_text`.
Each block below is the complete shape of its op, not one variant of it. Copy it
and fill it in. Nothing here needs a probe call to confirm.
**`set_text`** the workhorse. Replaces the content of a text layer.
```json
{ "op": "set_text", "layerId": "ly_a1", "content": "Line one\nLine two",
"fontSize": 72, "color": "$brand.ink", "align": "center" }
```
`content` is plain text with newlines. Never HTML: it is drawn as text, so
markup will appear literally. `fontSize`, `color` and `align` are optional
conveniences for the fields you most often change alongside the words.
**`set_layer_style`** patches any other field of a layer.
```json
{ "op": "set_layer_style", "layerId": "ly_a1",
"patch": { "fontWeight": 700, "letterSpacing": -2, "textTransform": "uppercase" } }
```
The patch is validated against the layer's real type: sending `content` to an
image layer is an error, not a silent no-op, because it means you think you
edited something you did not. The patch is partial per field but not inside a
field: sending `frame: { x: 10 }` replaces the whole frame and the rest reverts
to defaults. To nudge a layer, use `move_layer`.
Layers may share an optional `groupId` (1–64 characters) within one slide.
This is a flat selection group in the manual editor, not a parent transform:
frames remain absolute and drawing order is unchanged. Use a single batch of
`set_layer_style` patches to assign the same group ID to related layers; use
`{ "groupId": null }` to remove membership. Preserve existing groups when
editing words or style. Give duplicated groups new IDs within the same slide.
Two more editor flags live on every layer. `hidden: true` keeps the layer in
the document but it never renders or exports; the person toggles it from the
layer stack, so do not delete a hidden layer to "clean up" and do not count it
when judging the visible composition. `locked: true` only means the editor's
canvas will not grab it with the mouse; you may still edit a locked layer with
ops. Both are set with `set_layer_style` and default to visible and unlocked.
**`move_layer`** merges into the frame, which is what you want 90% of the time.
```json
{ "op": "move_layer", "layerId": "ly_a1", "frame": { "y": 520 }, "rotation": -4 }
```
**`reorder_layer`** changes the z order inside its slide.
```json
{ "op": "reorder_layer", "layerId": "ly_photo", "to": "back" }
```
`to` is `"front"`, `"back"` or a 0 based index. An index out of range is
clamped with a warning rather than refused.
**`add_layer`** adds one to a slide. Max 20 per slide.
```json
{ "op": "add_layer", "slideId": "sl_2", "layer": {
"type": "text", "role": "kicker",
"frame": { "x": 90, "y": 180, "w": 900, "h": 80 },
"content": "CASE STUDY", "fontFamily": "$brand.mono", "fontSize": 28,
"letterSpacing": 6, "textTransform": "uppercase", "color": "$brand.secondary" } }
```
You can omit `id`: one is generated and appears in the `outline` of the result.
The new layer goes on top of the stack.
**`remove_layer`**
```json
{ "op": "remove_layer", "layerId": "ly_a1" }
```
**`set_background`** replaces a slide's background.
```json
{ "op": "set_background", "slideId": "sl_1",
"background": { "type": "color", "color": "$brand.bg" } }
{ "op": "set_background", "slideId": "sl_1", "background": {
"type": "gradient",
"gradient": { "type": "linear", "angle": 160,
"stops": [ { "color": "$brand.primary", "at": 0 },
{ "color": "$brand.ink", "at": 1 } ] } } }
{ "op": "set_background", "slideId": "sl_1", "background": {
"type": "image", "assetId": "<uuid>", "blur": 0,
"focalPoint": { "x": 0.5, "y": 0.35 },
"overlay": { "color": "$brand.ink", "opacity": 0.45 } } }
```
The `overlay` is how a light headline stays readable over any photograph.
Gradients are linear only, 2 to 4 stops, `at` from 0 to 1.
**A flat background is never a bare hex.** Add a procedural texture on top of
the brand color: `texture` is `fine`, `coarse`, `paper`, `fabric` or `film`,
and `grain` is its intensity from 0 to 1 (0.35 to 0.6 reads as material, above
0.8 reads as noise). It is drawn by code, so it costs nothing and belongs to
nobody. A flat background without texture looks cheap next to one with it.
```json
{ "op": "set_background", "slideId": "sl_2", "background": {
"type": "color", "color": "$brand.bg", "texture": "paper", "grain": 0.45 } }
```
**A photo gets a treatment, not just a blur.** Four optional fields sit a
photograph in the piece:
- `grade`: `none`, `editorial` (contrast up, brightness down, a little
saturation: the default for a photo with text on it) or `immersive` (darker
and much more saturated: for a cover where the image is the argument). Use
the same grade on every photo of a piece, including stock and `og:image`
imports, so they read as one set.
- `grain` 0 to 1 and `vignette` 0 to 1, film grain and darkened edges.
- `overlay.veil`: how the overlay is distributed. `flat` (or absent) is the
even veil. `low` opens at the top and closes at the bottom, for text that
sits low; `high` is the reverse; `window` keeps the middle clear for a
subject; `card` darkens the middle band for a text block there. The veil
is drawn with ten stops so no seam shows. Use it when there is text on the
photo and the subject lives in one half; skip it on a photo without text.
- `scrim`: a local radial shadow behind ONE text block, in canvas pixels, so
the rest of the photo stays clear: `{ "x", "y", "w", "h", "opacity" }`.
```json
{ "op": "set_background", "slideId": "sl_1", "background": {
"type": "image", "assetId": "<uuid>", "blur": 0,
"focalPoint": { "x": 0.62, "y": 0.4 },
"grade": "editorial", "grain": 0.3, "vignette": 0.35,
"overlay": { "color": "$brand.ink", "opacity": 0.6, "veil": "low" },
"scrim": { "x": 60, "y": 880, "w": 720, "h": 380, "opacity": 0.5 } } }
```
**`set_image`** points an image layer at an asset.
```json
{ "op": "set_image", "layerId": "ly_photo", "assetId": "<uuid>",
"focalPoint": { "x": 0.5, "y": 0.3 } }
```
`assetId` must be a real uuid from the workspace media library: `list_assets`
shows what is there, and `import_image_from_url`, `import_stock` or
`import_background` put something new in it. `focalPoint` is the point kept in
view when the frame crops: `{ x: 0.5, y: 0.3 }` keeps a face near the top whole.
**`add_slide`** appends, inserts, or duplicates. Max 20 slides.
```json
{ "op": "add_slide" }
{ "op": "add_slide", "after": "sl_2" }
{ "op": "add_slide", "after": "sl_2", "from": "duplicate:sl_2" }
```
Duplicating is the cheapest way to extend a carousel: the layout comes back with
fresh ids and you only rewrite the text.
**`remove_slide`** fails on the last remaining slide (a piece needs at least
one).
```json
{ "op": "remove_slide", "slideId": "sl_3" }
```
**`reorder_slides`** takes an exact permutation: every current id, once each.
```json
{ "op": "reorder_slides", "order": ["sl_1", "sl_3", "sl_2"] }
```
**`set_captions`** writes the copy per network. Merges per network; `null`
clears one.
```json
{ "op": "set_captions", "captions": {
"instagram": { "text": "...", "firstComment": "Link in bio" },
"linkedin": { "text": "..." },
"x": { "thread": ["First tweet", "Second tweet"],
"imageMap": ["slide:1", "none"] },
"tiktok": null } }
```
Limits: Instagram 2200 characters, TikTok photo descriptions 4000, LinkedIn 3000, one tweet 280, a
thread 25 tweets. `imageMap` is positional: which slide rides with each tweet,
or `"none"`.
**`set_format`** moves the whole piece to another canvas and reframes it.
```json
{ "op": "set_format", "format": "9:16" }
```
Every layer of every slide is scaled by ONE factor and centred inside the safe
area of the new format, and a text block that ended up outside is pulled back
in. Ids do not change, so the ops you were about to send still address the right
layers. Sending the format the piece already has does nothing.
A reframe moves a design, it does not redesign it. Taking a 4:5 carousel to 16:9
leaves room on the sides, and taking it to 9:16 leaves room above and below:
that space is yours to fill, and filling it is the difference between a piece
made for the format and one converted to it.
**`set_meta`** title, category and private notes.
```json
{ "op": "set_meta", "title": "Why retention beats reach",
"category": "playbook", "notes": "Angle came from the user's Q3 numbers" }
```
`notes` is never published. It is the right place to record why a piece is the
way it is, for whoever (you, next week) picks it up again.
### Field ranges worth knowing
Values outside these degrade to the default with a warning, they do not fail.
| field | range | default |
| --- | --- | --- |
| `fontSize` | 8 to 400 | 48 |
| `fontWeight` | 400, 500, 600, 700, 800 | 400 |
| `lineHeight` | 0.8 to 2.5 | 1.2 |
| `letterSpacing` | -5 to 40 | 0 |
| `opacity` | 0 to 1 | 1 |
| `rotation` | -360 to 360 | 0 |
| `hidden` | `true` or `false`; hidden layers stay in the doc but never render | absent (visible) |
| `locked` | `true` or `false`; the editor canvas cannot grab a locked layer | `false` |
| `borderRadius`, `radius` | 0 to 540 | 0 |
| text `content` | 1000 characters, truncated | "" |
| frame `w`, `h` | 1 to 4000 | 1080 x 200 |
| text `scale` | `cover`, `title`, `closer`, `hero`, `intro`, `body`, `label`, `cue` | absent |
| shape `material` | `flat`, `glass` | `flat` |
| shape `bleed` | `left`, `right`, `top`, `bottom` | absent |
| background `texture` / `grain` | 5 textures / 0 to 1 | absent |
| photo `grade` / `vignette` / `overlay.veil` | 3 grades / 0 to 1 / 5 veils | absent |
**`scale` is the type scale by role and format.** When a text layer carries
`scale`, the renderer ignores `fontSize` and uses the size the format was drawn
for. At 1080 x 1350: cover hook 98, title 80, closer 92, hero number 190 with
line height 0.86, intro 34, body 40, label 26, cue 30; display line height
never below 1.12. Other formats scale from the width (9:16 a little larger,
16:9 smaller). Prefer `scale` over guessing a number; deviate only when one
short line owns the slide, and then by writing `fontSize` without `scale`,
+6 to +14 at most.
**`material: "glass"` is the liquid glass recipe**, one recipe for the whole
product: tint from the `fill`, backdrop blur, a top sheen, a 1px rim, radius 24
and a deep shadow. Over a photo the tint is dark; over a flat background it
inverts to a faint light glass, because there is nothing to blur. It is the
material for a live product over a photograph and for one chip or one card
that has to float; it is not a way to make every box look designed. One glass
surface per slide, and only where it earns the place.
**`bleed` says which edge a shape runs off.** The renderer drops
the radius on that side, and the frame has to cross that edge for real: a
bleeding component whose corner is still visible reads as a cut, and
`check_quality` reports it as `visible_bleed_corner`. Push the content inside
the component about 108px away from the bleeding edge.
Shapes are `rect`, `pill`, `ellipse` or `line`, with a `fill` (a color ref or a
gradient) and an optional `stroke`. Logos take a `variant`
(`primary`, `icon`, `wordmark`) and a `tint` (`"original"` or a color ref, for
placing a logo over a dark photo). A logo has no `assetId`: it resolves against
the brand kit, which is why a doc or a saved template can ship with the logo
already placed.
---
## 5. Images: nothing renders a URL
A piece can only draw an image from the workspace library, by its `assetId`. No
layer takes a URL: an external one goes dead and the piece loses its photo.
**Look before you import**: `list_assets` is cheap, the user usually has their
own photos in there, and a second copy is clutter they have to clean up.
```
list_assets what the workspace already has
-> list_backgrounds the house textures, then import_background
-> import_image_from_url a specific image you have a URL for
-> search_stock find candidates, free to use commercially
-> import_stock save the one you picked
-> set_image / background place it in the piece
```
**`import_image_from_url({ url, kind })`** stores the file: jpeg, png, webp and
svg, up to 20 MB. Internal and private addresses are refused on every redirect,
because you read that URL somewhere. `kind: "logo"` lands it in the logo picker.
**`list_backgrounds` / `import_background({ slug })`** are the house collection:
neutral textures made for this product, with no credit to carry. They are files,
not assets, so they do not appear in `list_assets` until you copy one in. A
`textura` is opaque and covers the frame, a `trama` is nearly transparent and
needs a color background under it. The same slug twice returns the same asset.
**For a background texture, the house collection comes before stock.** Going to
a photo bank for a texture puts a stranger's photo, credit and all, on a
piece where the user had the texture of their own brand one call away.
**`search_stock({ query, page })`** searches the photo banks (Pexels, then
Unsplash, then Openverse; the first with results answers, and a bank that is
down is skipped) for photos free to use commercially and to modify. Nothing is
saved yet: the results are candidates with a preview, a `bank` and a credit.
Search in the subject's language, not the user's: the banks index English
metadata, so `boxing gym` beats `gimnasio de boxeo`.
**`import_stock({ id })`** saves one of those into the library. Send the id and
nothing else: the file URL and the credit come from the bank, which keeps a
photo from being stored under the wrong author. The credit comes back in
`list_assets` for the piece to carry. Import the one you chose, not three.
**A stock photo is the last resort, not the first.** A generic image of a
stranger in an office says nothing and looks like every other post in the feed.
The user's own photo, a texture, a shape or type on a color field all beat
it. Never invent what a photo shows: place it, then look at it.
**Unless the person asked for one.** Feedback that names photos or a photo
background ("quiero fotos", "no tiene foto de fondo", "no solid backgrounds")
outranks the rule above: the revision leaves with a photo on it, or with a
house texture and one line saying why. When `search_stock` answers
`UPSTREAM_ERROR` or `RATE_LIMITED`, do not loop on it: fall back to
`list_backgrounds` and `import_background`, or ask for one concrete photo and
place it with `import_image_from_url`. Never close a request with a cosmetic
change (nudging text, resizing a layer) and report it as done; say what
blocked you instead. The person sees every version, and a "new version" that
looks identical costs more trust than an honest "the photo bank was down".
### Designing with few resources
Most workspaces have one usable photo or none. That is a composition problem
with known answers, not a reason to stop or to fill the gap with stock:
- **No photo**: type carries the piece. A strong hook on `$brand.bg`, one
number or one line as the visual, shapes and `$brand.bgAlt` blocks to build
rhythm, the logo small. Choose a `type` or `data` dominant mode; do not
pretend an image exists.
- **One photo**: it is the cover, cropped with `fit: "cover"` and a focal
point, or a full-bleed background with a veil under the text. The inner
slides go typographic; reusing the same photo on every slide reads as a
template.
- **A product cutout or a logo only**: give it air. A cutout on a flat color
with one line beats a fake scene around it.
- **Inspirations are not material**: `kind: "inspiration"` assets never go
into a piece; they tell you what the person likes.
When one concrete photo would change the piece, ask for exactly that one and
say how to take it ("una foto del local con la persiana abierta, de día,
horizontal"), then design without it in the meantime. Do not ask for "some
photos".
---
## 6. Beyond one piece
**`duplicate_piece({ pieceId, language })`** copies the design into another
language: same layout, same photos, fresh ids, title suffixed. The copy comes
back with the ORIGINAL words still in it, because translating is your job and
not the server's. Read the outline it returns, then rewrite the text layers and
the captions. Leave the layout alone, it already fits.
**`create_variant({ pieceId, baseVersion, variant? })`** recomposes the same
content with another eligible layout family, without touching a word, and saves
it as a new version of the same piece (the previous layout is one restore away).
It works on pieces whose intent was recorded: everything `compose_piece` makes
and everything the mobile assistant makes. **`adapt_piece({ pieceId, format })`**
makes the story, square or landscape version as a new piece linked to the
source; if a text does not fit the new canvas it creates nothing and tells you
which one, so you shorten it with the user instead of the server truncating it.
**`get_week_plan()`** answers "¿qué publico esta semana?" without a model: ideas
built from the objective, confirmed knowledge, pillars, the commercial calendar
of the country and what was already published, plus the dates coming up. Show
the ideas, ask the open `questions` of the one the user picks, and design only
what they approve. **`create_review_link({ pieceId })`** gives the user a link to
send for approval; create it only when they ask, and hand them the URL.
When you use it to offer variants of the same piece, each round changes ONE
thing: the hook, or the photo, or the background mode, never two at once. The
user decides by looking, and two variants that differ in three ways cannot be
compared. Freeze the structure, change one dimension, show both.
### Coherence across pieces
Pass `includeRecent: true` to `get_brand_kit` before a new piece: the summaries
show what the brand already said and how (hooks, categories, planned dates).
A series repeats a structure on purpose and says so in the title or category;
a launch may ask for a different direction. What you avoid is the accident:
the same hook shape three times in a row, the same photo treatment on every
piece, or a piece that contradicts last week's. When several pieces are asked
together, plan them as a set (one angle each, a shared thread) and compose
them one by one. Read a recent piece with `get_piece` when you need its actual
composition; the summaries are not render inspection.
**`save_as_template({ pieceId, name, description })`** keeps the shape of a
piece that came out well, so later pieces can start from it with
`create_piece({ templateSlug })`. The words are kept too: a template of your own
is `I want to make this piece again`, not a blank layout.
**`check_brand({ pieceId })`** runs the deterministic check: a color or a font
that is not in the kit, a text block that does not fit its frame, type below the
readable floor, an empty layer, an image pointing at an asset that no longer
exists, text the exact same color as whatever sits behind it (sameness, not
contrast: dark grey on black passes). `error` will render wrong for sure;
`warning` is often a decision somebody made on purpose, so a literal the user
asked for lands here and stays exactly as it is. It says nothing about whether
the piece is good, only whether it is consistent: the last pass before you hand
a piece over, never an approval.
**`render_preview_image({ pieceId, expectedVersion?, slides?, layout? })`**
returns a JSON receipt followed by actual MCP image blocks from the existing
export worker. `layout` is `individual` (default) or `contact_sheet`; each call
renders at most four slides. The strict resource receipt requires the complete
manifest and successful loading of its declared fonts and images. An older
worker returns `PREVIEW_UNVERIFIED` instead of claiming this was checked.
A version/identity conflict requires rereading the document and kit.
This tool never publishes, consumes a download or creates a release.
**Photo observations.** `get_photo_analysis({ assetId, includeImage? })` returns
the source image by default, together with `version`, `assetFingerprint`,
`sourceDimensions` and existing metadata. Inspect the pixels. Coordinates use
`coordinateSpace: "displayed_image"`: the complete source, auto-oriented as the
browser displays it, before any crop. `set_photo_analysis` takes that version as
`baseVersion`, the unchanged `expectedAssetFingerprint`, and `analysis` with
`schemaVersion: 1`, the returned dimensions, `analysisComplete`, normalized
`protectedRegions`, optional `focalPoint`/`cropSafe`, and `provenance`.
Each region has `{x,y,w,h,kind}` with kind face, hand, subject, text or logo.
`agent_visual` provenance names the agent, ISO `observedAt` and concrete visual
`evidence`; `reviewed_override` additionally records the user's actual
`userConfirmation`. Never invent a confirmation. An empty region list means
you inspected an empty scene; dimensions alone are not an analysis. Partial,
stale, revoked or unavailable metadata retains the safe fallback. Send
`analysis: null` with CAS to revoke an observation. The server never calls an
image-analysis model. Saved current observations feed `compose_piece` without
changing existing PieceDocs.
**`get_publication_results({ pieceId?, postId?, limit? })`** reads already stored
outcomes. It never refreshes a provider or publishes. Compare snapshots at
similar `ageHours` and account context; null metrics are unknown, not zero.
Engagement is not aesthetic approval or permission to change durable taste.
**`check_quality({ pieceId, displayWidthPx? })`** is a separate deterministic
pass for design quality. `displayWidthPx` is the intended displayed width in
CSS pixels, not the export resolution; omitting it explicitly assumes 360px.
The report returns stable codes and reproducible evidence. Read `assessment`
coverage with its status: `pass` means no selected rule found a problem, not
that the render, brand fit, editorial usefulness or taste has been approved.
Text wrapping and box intersections are estimates and return warnings. Inspect
the shared render with fonts loaded before shortening copy or moving a layer.
Contrast is calculated only for known uniform colors, including alpha and cue
opacity, against the 4.5:1 normal / 3:1 large-text reference at delivered size.
Photo regions, glass, gradients, partial or later overlays and unresolved tokens
are listed as unmeasured. No browser glyph metrics or pixels are inspected by
this pass. A missing measurement is never a contrast pass.
Warnings are review signals and never block a human save or export. The mode
remains `observe`: repair an observed cause once when the fix is clear, and keep
a deliberate decision when it serves the argument.
The stable codes are grouped by subject, not by measurement certainty:
- Mechanical: `layer_out_of_bounds`, `text_overflow`, `critical_overlap`,
`unreadable_contrast`, `illegible_text_size`, `missing_asset`.
- Composition and coherence: `broken_proximity`, `weak_dominant`, `dead_space`,
`top_stack`, `headline_orphan`, `alignment_drift`, `accent_mass`,
`surface_overload`, `material_drift`, `background_mode_drift`.
- Anti-slop and specificity: `orphan_divider`, `false_button`,
`decorative_container`, `repeated_chrome`, `template_rhythm`,
`missing_content_visual`, `grammatical_triplet`, `generic_closer`,
`pseudo_quote`, `decoration_without_job`, `cue_outside_cover`,
`generic_cue`, `visible_bleed_corner`.
- Copy (the same rules the app's assistant enforces, read against the brand's
own texts in `voice`, its language and its treatment):
`copy_art_direction`, `copy_repeated_sentence`, `copy_repeated_phrase`,
`copy_support_repeats_headline`, `copy_ai_phrase`, `copy_brand_repeated`,
`copy_dash_emoji_markdown`, `copy_empty_cta`, `copy_address_mismatch`,
`copy_filler_hashtags`. They cover slide text and captions. `repair_quality`
never rewrites copy: you do.
**`complete_design_request({ requestId, pieceId, baseVersion })`** returns work
to a waiting screen in the app. Use the requestId supplied by the user's copied
request; finish all edits, render inspection and focused repairs first. The tool
writes a completion receipt through CAS and does not approve or publish. The
server captures that delivery and its identity separately, so later edits or
another request cannot replace it. A prepared request may name a specific piece;
finish that piece rather than silently substituting another.
On conflict, read the current document and review it before retrying. Replaying a
completed receipt is idempotent; `completedVersion` is the version delivered,
while `version` may include later changes. Do not complete a different request
because its piece happened to be the newest. For ordinary work without a requestId,
continue to return the pieceId normally.
**`repair_quality({ pieceId, baseVersion, codes, maxFixes })`** only acts on a
finding that already carries a safe `autoFix`: remove an orphan divider, move a
layer that is only slightly outside bounds, or reduce one isolated oversized
accent shape. It uses CAS, writes normal version history and analyzes the saved
result again. It never rewrites copy or makes a taste decision. Call it once in
normal generation; if it says no safe repair exists, use the suggested fix or
keep the deliberate warning.
**`delete_piece({ pieceId })`** sends the piece to the trash, where the user can
restore it from Tu cuenta. `purge: true` deletes it for real, version history
included. Ask before either one, every time, even when they told you to clean
up: they cannot see which piece your description resolved to.
---
## 7. Errors, and what to do about each
Every error is `{ "error": CODE, "message": ..., "hint": ... }`. The `hint` is
written for you and usually contains the exact data you need to retry, such as
the list of layer ids that do exist.
| code | meaning | recovery |
| --- | --- | --- |
| `VERSION_CONFLICT` | someone saved while you worked, almost always the user watching their canvas | `get_piece`, look at what changed, rebase your ops and resend. Never resend the same `baseVersion`, and if their change conflicts with what you were about to do, say so instead of quietly winning |
| `LAYER_NOT_FOUND` | no such layer id | the hint lists every layer of the doc. Pick the right one |
| `SLIDE_NOT_FOUND` | no such slide id | the hint lists the slide ids |
| `INVALID_OP` | an op is malformed, or aimed at the wrong layer type | the hint says which fields that layer type accepts |
| `LIMIT_EXCEEDED` | 20 slides, 20 layers per slide, or 20 ops | split the batch, or remove before you add |
| `LAST_SLIDE` | you tried to delete the only slide | add one first, or delete the piece |
| `NOT_FOUND` | no such piece in this workspace | `list_pieces`. A piece in someone else's workspace answers identically |
| `INVALID_DOC` | a doc that cannot be recovered | usually zero slides or a missing `schemaVersion` |
| `TEMPLATE_NOT_FOUND` | bad slug | `list_templates` for the slugs this workspace saved |
| `EMPTY_PATCH` | `set_piece_meta` with nothing in it | send at least one field |
| `INVALID_IMAGE` | the URL did not answer with an image we accept | jpeg, png, webp or svg, public address. Do not retr
[…] pełny plik w paczce .zip
Wersje
W bazie nie ma innych skilli o nazwie theagentcy.
Migawka bazy z 13.11.2026 · wersja paczki 323ba2b29afe (skrót SHA-256 całej paczki)
Pobrania w ostatnich 30 dniach: 0 · ranking
Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.
Podobne skille
- 95social-content
Tworzy posty w mediach społecznościowych, kalendarze treści i wersje dopasowane do poszczególnych platform. - 100blowhorn
Pomaga szkicować, planować i sprawdzać posty w mediach społecznościowych przez narzędzia MCP Blowhorn, zawsze z podglądem i zgodą. - 100agentreacher-social-publishing
Planuje, pisze, zaplanowuje i publikuje kampanie w mediach społecznościowych przez AgentReacher, na wielu platformach naraz. - 90schedule-social-posts
Pisze, zatwierdza i planuje posty w mediach społecznościowych przez serwer MCP TimeToPost, także wątki i kolejkę na tydzień. - 100content-creator
Pisze treści marketingowe pod SEO, analizuje głos marki i planuje kalendarz treści w mediach społecznościowych. - 90social-content
Pomaga w tworzeniu i planowaniu treści w mediach społecznościowych: wątki, kalendarze i strategie dla każdej platformy.