MCP
Tool reference
Every tool the Reblog MCP server exposes, grouped by the permission that unlocks it, with arguments, credit cost and the project roles allowed to call it.
This page is generated from the running server, so it cannot drift: a tool that is added, renamed or re-scoped appears here and nowhere else has to be edited. Groups are ordered from least to most powerful.
How to read a tool
Permission is the scope a connection must have been granted. Roles are the project roles allowed to run it -- your own role caps the connection, so both have to allow the call. Credits marks the tools that bill AI usage when they run.
account.projects.read
read3 toolsSee which projects and workspaces this app can access
Answer "which of my projects needs an article right now?" across every project this connection can access. Each project is analysed against its own publishing rhythm (or its automation routine) and ranked by urgency: how long since its last article, how late that makes it, what is still in its pipeline, and what to do next. Returns a compact ranked list plus a summary of how many projects are overdue, due, covered or on track. Call get_publishing_cadence with one project_id for the full detail of a single project.
| Argument | Type | Description |
|---|---|---|
| min_urgency | integer | Only return projects at or above this urgency score. Pass 50 for "only what actually needs writing".0-100 - default 0 |
| status | string | "needs_attention" keeps overdue, due_now and never-published projects.any | needs_attention | overdue | due_now | due_soon | covered | on_track | no_history - default "any" |
| include_translations | boolean | Count translated versions as separate publications. |
| limit | integer | Maximum projects returned (the ranking is computed first, so this keeps the most urgent).1-50 - default 20 |
Report exactly what this connection can and cannot do: the app it is acting as, its granted permissions, the projects it reaches and your role on each, which tools are usable (and why the others are not), and where the account owner can review every call made through it. Call this when a tool was refused, before attempting anything destructive, or when the user asks what you are allowed to do here.
No arguments.
List the projects this connection can access. Use the returned project_id to target other tools when more than one project is available. project_url is the live published site; dashboard_url is the editor.
No arguments.
agents.read
read4 toolsSee your AI agents and their job queue
Fetch one background job (worker-request) by id, with its status, recent logs and final result or error. Use the job_id returned by list_jobs, translate_article or translate_missing.
| Argument | Type | Description |
|---|---|---|
| job_id* | string | MongoDB ObjectId of the job (worker-request) |
| log_limit | integer | How many of the most recent log entries to return1-100 - default 20 |
List the AI agents configured for a project (translation, article-idea, recommendations, article-writer, image, cover, tweet-to-article, emphasis) with their status. For the translation agent, languages lists the target languages it can translate into. For an image agent, model is what draws article covers - pass its agent_id to generate_image, or to generate_article to choose which one illustrates the piece. For a tweet-to-article agent, thread_rules is how it reads an X thread and what it asks the article to be - pass its agent_id to tweet_to_article, scrape_tweet or analyze_tweet_discussion to read with those rules. For a cover agent, cover_rules is what the picture at the top of an article looks like and where it comes from - pass its agent_id to create_cover. A project can hold more than one of a type, so several cover agents can come back: the one a thread article is illustrated by is named in the tweet-to-article agent thread_rules as cover_agent_id, and configure_agent with create_new adds another. For an emphasis agent, emphasis_rules is how much italic the articles carry; a project with no such agent still gets the built-in light touch, so the absence of one here is a default and not an off switch. The same is true of the cover agent: articles are illustrated with the built-in defaults when there is none. Use this before launching work with translate_article, translate_missing or generate_image. To create or change a writer, image, cover or tweet-to-article agent, use configure_agent.
| Argument | Type | Description |
|---|---|---|
| agent_type | string | Optional filter by agent type: "translation", "article-writer", "article-idea", "recommendations", "image", "cover", "tweet-to-article" or "emphasis" |
| include_inactive | boolean | Include agents whose status is not active |
List the image models this account can generate with, to pass as `model` to generate_image. Includes every OpenRouter slug the model library carries (Gemini, GPT-image, FLUX, Seedream, Grok Imagine and the rest of the gateway) alongside the direct-provider models. Badges tell them apart: recommended is the product default, fast is cheap and quick, premium is the expensive high-detail tier. Filter with provider or search when the list is long.
| Argument | Type | Description |
|---|---|---|
| provider | string | Only models from this provider, e.g. "openrouter" or "openai"max 40 chars |
| search | string | Substring match on the model id or its display name, e.g. "flux" or "gemini"max 80 chars |
| limit | integer | How many models to return (default 60)1-200 - default 60 |
List background jobs (worker-requests) for a project, newest first, with their status (pending, processing, completed, failed, cancelled). Filter by type or status to follow work launched with translate_article, translate_missing or generate_recommendations. Use get_job for the full detail of one job.
| Argument | Type | Description |
|---|---|---|
| request_type | string | Filter by job typetranslation | article-generation | article-idea | recommendations | generation | other |
| status | string | Filter by statuspending | processing | completed | failed | cancelled |
| page | integer | min 1 - default 1 |
| page_size | integer | 1-100 - default 20 |
articles.read
read14 toolsView your articles
Get a single-call overview of a project: its languages, article counts (total, by status, by language), idea backlog, and - when allowed - its active AI agents, its in-flight job queue and a setup block saying whether the writer and image agents are configured and whether X threads have house rules. Call this first to orient before using more specific tools.
No arguments.
List the published articles most worth updating rather than replacing: the oldest untouched ones, scored up by thin content, missing meta title or description, missing cover and missing internal links. Each candidate comes with a refresh score out of 100 and the reasons behind it. Word counts are approximated from the stored body length.
| Argument | Type | Description |
|---|---|---|
| older_than_days | integer | Only consider articles untouched for at least this long.7-2000 - default 180 |
| lang | string | Optional language filter, e.g. "EN".max 10 chars |
| limit | integer | How many candidates to return, highest score first.1-50 - default 10 |
Fetch one article by id or by handle. Returns the full document including markdown body. The article must belong to the targeted project.
| Argument | Type | Description |
|---|---|---|
| article_id | string | MongoDB ObjectId of the article |
| handle | string | URL handle of the article |
List the change history for one article, newest first. Each entry is a recorded mutation (create, update, edit, delete) with its source and a size delta. Use the returned history_id with rollback_article to restore a previous version. Set include_content to also return the before/after markdown of each version (heavier).
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article |
| limit | integer | Maximum number of history entries to return1-100 - default 20 |
| include_content | boolean | Include the full before/after markdown of each version |
Show the editorial calendar of a project around today: articles published in the recent window, everything booked ahead (scheduled articles and drafts with a future date), upcoming automation routine runs, and the days in the horizon with nothing planned. Flags booked slots whose article is still missing a cover or a meta description, because those cannot publish as-is. Dates are given both as instants and as local days in the project timezone.
| Argument | Type | Description |
|---|---|---|
| days_ahead | integer | How far forward to look.1-180 - default 30 |
| days_back | integer | How far back to include already published articles.0-180 - default 30 |
| include_translations | boolean | Include translated versions as separate calendar entries. |
Find what a project is NOT covering: languages that lag behind the main one, categories declared in the project but never used (or untouched for months), published articles with no category at all, categories used on articles but missing from the project settings, and the share of the catalogue that has not been touched in a long time. Returns per-language and per-category coverage plus a prioritised list of gaps, each naming the tool that closes it. Pair with get_publishing_cadence: that one answers when to publish, this one answers about what.
| Argument | Type | Description |
|---|---|---|
| stale_after_days | integer | How long an article (or a category) can go untouched before it counts as stale.30-1000 - default 180 |
Answer "when should I publish the next article here?" for one project. Returns the real publishing rhythm (median gap between articles, articles per week/month, trend, usual weekday and hour), how long ago the last article went out, what is still in the pipeline (drafts, scheduled, review queue, ideas), and a verdict: on_track / due_soon / due_now / overdue / covered / no_history, with a due date, an urgency score out of 100 and the concrete next actions to take. Use find_projects_needing_articles instead when the question spans several projects.
| Argument | Type | Description |
|---|---|---|
| include_translations | boolean | Count translated versions as separate publications. Off by default: a 3-language project would otherwise look 3x faster than it writes. |
| sample_size | integer | How many recent published articles feed the rhythm math.10-500 - default 200 |
Check whether cache purges are reaching the customer's site: whether revalidation is configured for the project, the recent delivery attempts with the site's HTTP answer, how many are waiting to be retried, and - when article_id is given - whether that article still owes a purge (its body changed more recently than the last purge we delivered, so the next automation tick will send one). Start here when someone reports that the live site shows an old title, an old body or a deleted article. Read-only: it never calls the site, revalidate_article does that.
| Argument | Type | Description |
|---|---|---|
| article_id | string | MongoDB ObjectId of one article, to narrow the log to it and report whether a purge is still owed for it. |
| limit | number | How many delivery attempts to return, newest first.1-50 - default 10 |
List AI-generated article ideas for the targeted project. Optionally filter by status (new, approved, dismissed, promoted). Returns ideas plus per-status counts.
| Argument | Type | Description |
|---|---|---|
| status | string | Filter by idea statusnew | approved | dismissed | promoted |
| limit | integer | 1-200 - default 50 |
List every picture in one article: its cover, plus each image in the body with a position number, its alt text, caption, and which section it sits in. The position numbers are what add_article_image, replace_article_image, remove_article_image and move_article_image take, so call this first when the user says "the second photo" or "the image in the pricing section". Also flags images that are still hosted outside the project, which break when the other host does.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the articlemax 40 chars |
List articles in a project. Supports pagination, search by title/handle, optional language and category filters, and date range.
| Argument | Type | Description |
|---|---|---|
| page | integer | 1-indexed page numbermin 1 - default 1 |
| page_size | integer | 1-100 - default 20 |
| search | string | Case-insensitive substring match on title or handle |
| lang | string | ISO language code (e.g. "en", "fr") |
| category | string | Filter by category slug |
| status | string | Filter by article statusdraft | published |
| date_from | string | |
| date_to | string | |
| sort_by | string | default "created_at" |
| sort_order | string | asc | desc - default "desc" |
List the categories declared for a project, with how many articles each holds. These are the values create_article and update_article expect in `categories` and list_articles in `category`: pass one of these rather than inventing a label, because an undeclared category still saves but the dashboard filters never offer it. Also returns the categories found on articles that the project never declared, which is what get_content_gaps flags as a taxonomy gap.
No arguments.
Read an X (Twitter) post, the posts it is built on, and the discussion under each of them, ranked. Returns the post, the author's own follow-ups, and the replies that are actually worth reading - scored on engagement, substance, whether they push back with numbers or first-hand experience, and whether the author stopped to answer them. Promoted posts injected into the reply timeline are removed, so what comes back is the real conversation. By default the read goes one hop back: when the post quotes another post, answers one, or links to one, that post is read too and comes back in `sources` with its own replies, because a post commenting on another one usually leaves the numbers and the original claim in the post underneath. Also returns `dossier`: the whole thing compiled into one readable brief, which is exactly what analyze_tweet_discussion and tweet_to_article feed to the model. Also reports the picture the post carries (`cover_candidate`), every picture in the thread that would go inside the article (`images`), the video inside it (`video`), and the pages the posts link to (`links`), so what the article will be built from can be shown to the user before anything is spent. Free (no AI credits, no article created). Use it to decide whether a thread is worth writing about, or to quote what people said.
| Argument | Type | Description |
|---|---|---|
| tweet_url* | string | The post: a link like https://x.com/user/status/123, a twitter.com link, or just the numeric idmax 500 chars |
| limit | integer | How many top replies to return. Omit it to use the project's tweet-to-article agent (15 when it has none).1-60 |
| pages | integer | Reply pages to walk, ~20-40 replies each (1-5). More pages means more of the thread and more API calls. Omit it to use the project's tweet-to-article agent (2 when it has none).1-5 |
| ranking_mode | string | How X orders the replies before they are re-scored: 'Relevance' (what the site shows), 'Likes', or 'Recency'. Omit it to use the project's tweet-to-article agent.Relevance | Likes | Recency |
| depth | integer | How far back to read (1-3). 1 reads only the post you passed. 2 also reads what it is built on - the post it quotes, the post it answers, an X link in its text - each with its own ranked reply section, because a post that comments on another one usually leaves the numbers and the original claim in the post underneath. 3 goes one hop further. Omit it to use the project's tweet-to-article agent (2 when it has none).1-3 |
| max_sources | integer | How many other posts the read may follow in total (0-6). Omit it to use the project's tweet-to-article agent (3 when it has none).0-6 |
| include_noise | boolean | Keep the replies normally dropped as noise (one-word praise, bare mentions, promotional spam) |
| tweet_agent_id | string | Read with the rules of one specific tweet-to-article agent (see list_agents). Omit to use the project's main one, or the built-in defaults when it has none.max 120 chars |
| refresh | boolean | Read the thread again from X instead of reusing the read from a few minutes ago. Only worth it when you are watching a discussion that is still moving. |
Propose the concrete dates for the next articles of a project, ready to pass to schedule_article. Slots follow the project's real rhythm (or its automation routine), reuse the weekday and hour it usually publishes at, are expressed in the project timezone, and skip any day that already has an article published or booked. Returns the slots plus the cadence verdict they were derived from.
| Argument | Type | Description |
|---|---|---|
| count | integer | How many upcoming slots to propose.1-12 - default 3 |
| start_from | string | Only propose slots after this instant. Defaults to now (or to the moment the next article is due when the project is ahead of schedule). |
| include_translations | boolean | Count translated versions as separate publications when measuring the rhythm. |
assets.read
read1 toolSee the images and files in your projects
List the files in a project's asset library: everything uploaded from the dashboard plus every image generated for this project (article covers, in-article images, anything drawn over MCP). Each one comes back with a durable public URL you can embed in markdown or set as an article cover - check here before generating a new image, the picture may already exist. Filter with search (matches the file name and the prompt an image was generated from), source, or article_id.
| Argument | Type | Description |
|---|---|---|
| search | string | Match on the file name, the URL, or the prompt a generated image came frommax 200 chars |
| source | string | "generated" for AI images only, "uploaded" for files a human added, "all" (default) for bothall | generated | uploaded - default "all" |
| article_id | string | Only the images generated for this articlemax 40 chars |
| limit | integer | How many assets to return (default 50)1-200 - default 50 |
| offset | integer | Skip this many assets, to page through a large librarymin 0 - default 0 |
agents.run
writecredits10 toolsLaunch agent runs and change how the agents are configured: write articles, translate them, generate images (spends AI credits)
Read an X thread, and the posts it is built on, and say what is actually going on. Returns the claim the post made, the disagreements and how each was answered, the quotes worth lifting with their handles, the observations that only become visible once the whole thread is read, the questions nobody settled, and a suggested headline, angle, keywords and cover prompt. When the post quotes or answers another one, that post and its own reply section are read too, and the analysis adds `source_chain`: what the original actually said, and whether the post on top represents it fairly. That gap is usually the article. Use it to judge whether a thread is worth publishing and to agree an angle with the user BEFORE writing. Spends AI credits (one model call). Writes nothing: call tweet_to_article when you want the article.
| Argument | Type | Description |
|---|---|---|
| tweet_url* | string | The post: a link like https://x.com/user/status/123, or the numeric idmax 500 chars |
| lang | string | Language for the analysis (defaults to the project main language)max 10 chars |
| limit | integer | How many top replies to compile. Omit it to use the project's tweet-to-article agent (15 when it has none).1-60 |
| pages | integer | Reply pages to walk (1-5). Omit it to use the project's tweet-to-article agent (2 when it has none).1-5 |
| ranking_mode | string | How X orders replies before they are re-scored. Omit it to use the project's tweet-to-article agent.Relevance | Likes | Recency |
| depth | integer | How far back to read (1-3). 1 reads only the post you passed. 2 also reads what it is built on - the post it quotes, the post it answers, an X link in its text - each with its own ranked reply section, because a post that comments on another one usually leaves the numbers and the original claim in the post underneath. 3 goes one hop further. Omit it to use the project's tweet-to-article agent (2 when it has none).1-3 |
| max_sources | integer | How many other posts the read may follow in total (0-6). Omit it to use the project's tweet-to-article agent (3 when it has none).0-6 |
| custom_instructions | string | Editorial direction for this call: an angle to favour, an audience, something to focus on. It is added to the agent's standing angle, not a replacement for it.max 2000 chars |
| tweet_agent_id | string | Read with the rules of one specific tweet-to-article agent (see list_agents). Omit to use the project's main one.max 120 chars |
| refresh | boolean | Read and analyse the thread again instead of reusing the answer given for it a few minutes ago. Costs a model call; only worth it when the discussion has moved or you changed your mind about the angle. |
Cancel a background job that is still queued (status pending), for example a translation launched by mistake. Jobs already processing, completed or failed cannot be cancelled. Get the job_id from list_jobs.
| Argument | Type | Description |
|---|---|---|
| job_id* | string | MongoDB ObjectId of the job (worker-request) to cancel |
Set up or update a project AI agent - the article writer (its audience, tone and house rules), the image agent (its art direction), the cover agent (what the picture at the top of every article looks like and where it comes from), the tweet-to-article agent (how an X thread is read, whether its pictures and the pages it links to go into the article, and what the piece should be), or the emphasis agent (how much italic the articles carry). Call it with only agent_type to GET the questions to ask the user, together with what the project already says about itself so you can propose answers instead of interrogating. Call it again with the answers as fields to save them. A preset can be applied instead with template. A project can hold SEVERAL agents of a type: create_new adds another one and returns its agent_id, which is how a blog gets a second cover style for the articles it makes from X threads (point the tweet-to-article agent at it with cover_agent_id) without changing the covers of everything else. This is what generate_article points you to when a project has no configured writer yet, where create_cover gets the look of a cover from, and where tweet_to_article gets its reading depth and editorial rules from.
| Argument | Type | Description |
|---|---|---|
| agent_type* | string | "article-writer" for the agent that writes the articles, "image" for the art direction of every image, "cover" for the picture at the top of an article specifically (its look, its subject, and whether it is drawn at all), "tweet-to-article" for the rules that turn an X thread into an article, "emphasis" for how much italic emphasis every article carries.article-writer | image | cover | tweet-to-article | emphasis |
| agent_id | string | Update one specific agent (see list_agents). Omit to configure the project's main agent of this type, creating it if there is none.max 120 chars |
| create_new | boolean | Add ANOTHER agent of this type instead of updating the project's existing one, and return its agent_id. Needs a name. This is how a blog ends up with two cover agents - the house look and a newsroom one for its X pieces - or two writers; point something at the new one afterwards (cover_agent_id on the tweet-to-article agent, or agent_id on create_cover). Leave it out to change the agent already there. |
| template | string | Apply a ready-made preset instead of writing every field (the presets are listed in the questions response). Explicit fields still override it.max 60 chars |
| name | string | Display name for the agent, e.g. "Main writer".max 120 chars |
| target_audience | string | article-writer: who reads the blog - job, expertise level, what they are trying to do.max 2000 chars |
| tone_and_style | string | article-writer: the voice the articles should have.max 2000 chars |
| writing_instructions | string | article-writer: house rules - length, structure, what to always or never do. tweet-to-article: the same, but only for articles made from a thread (how much to quote, whether to name the accounts, how to open).max 4000 chars |
| seo_instructions | string | article-writer: how keywords, titles and meta descriptions should be handled.max 4000 chars |
| prompt_instructions | string | image: the art direction prepended to every image prompt (medium, palette, composition).max 4000 chars |
| negative_prompt | string | image: what must never appear in the images.max 1000 chars |
| size | string | image: output size, e.g. "1536x1024" for a landscape cover.max 20 chars |
| quality | string | image: "low", "medium" or "high" for the models that support it.max 20 chars |
| images_per_article | integer | image: how many images one article run may produce.1-4 |
| body_images | integer | image: how many illustrations go INSIDE the article, on top of the cover (default 2, one drawn per section from what that section says). 0 means cover only.0-4 |
| generate_cover | boolean | image: attach the first image as the article cover (usually true). tweet-to-article: false to leave these articles without a cover; covers are drawn by default, since publish_article refuses an article that has none. |
| depth | integer | tweet-to-article: how far back to read (1 the pasted post alone, 2 also the post it quotes or answers, 3 one hop further). 2 is the sensible default: a post that comments on another one leaves the numbers in the post underneath.1-3 |
| max_sources | integer | tweet-to-article: how many other posts one read may follow in total. 0 turns the chain off whatever depth says.0-6 |
| reply_pages | integer | tweet-to-article: reply pages to walk under the pasted post, ~20-40 replies each (default 2).1-5 |
| source_reply_pages | integer | tweet-to-article: reply pages to walk under each post found behind it (default 1: the source is context, not the subject).1-5 |
| ranking_mode | string | tweet-to-article: how X orders replies before they are re-scored.Relevance | Likes | Recency |
| comments_used | integer | tweet-to-article: how many top replies are compiled and handed to the writer (default 15).1-60 |
| include_noise | boolean | tweet-to-article: keep the replies normally dropped as noise (one-word praise, bare mentions, spam). Usually false. |
| min_replies | integer | tweet-to-article: refuse to write below this much discussion (default 1). Raise it on a blog that should only cover threads people actually argued in; 0 lets any post through.0-200 |
| angle_instructions | string | tweet-to-article: what the article should be about, applied to every thread. This steers the reading of the discussion, not just the writing.max 4000 chars |
| cover_instructions | string | tweet-to-article: a standing note added to the cover prompt written from the thread.max 2000 chars |
| content_type | string | tweet-to-article: what kind of piece these become, e.g. "news analysis", "opinion roundup".max 60 chars |
| fact_check_chain | boolean | tweet-to-article: when the post is built on another one, tell the writer to check it against its source and say when it misrepresents it. On by default; that gap is usually the article. |
| keep_disagreement | boolean | tweet-to-article: forbid smoothing the pushback into "reactions were mixed". On by default. |
| writer_agent_id | string | tweet-to-article: which article writer finishes these pieces (see list_agents). Empty means the project writer.max 120 chars |
| image_agent_id | string | tweet-to-article: which image agent draws their covers. Empty means the project image agent. cover: which image agent supplies the model and the base art direction this cover style sits on top of.max 120 chars |
| cover_agent_id | string | tweet-to-article: which COVER agent illustrates the articles made from a thread (see list_agents with agent_type "cover"). Empty means the project one, so they look like every other article. This is the way to give X pieces their own covers - a newsroom look, or the screenshot straight from the post - without restating the art direction here: create a second cover agent with configure_agent + create_new, then point this at its agent_id.max 120 chars |
| cover_source | string | tweet-to-article: where the cover of these articles comes from. "ai" draws one for the piece (default). "tweet" uses the picture in the post itself - its photo, or the frame X shows before its video plays. "auto" uses the post's picture when it has one and draws one otherwise; it is the right setting for a news blog, where the chart or the screenshot in the post IS the picture of the story. "none" leaves these articles without a cover. A thread with no picture always falls back to a drawn cover, whatever this says.ai | tweet | auto | none |
| video_frames | boolean | tweet-to-article: when the post carries a video, open it and put stills from INSIDE it in the article, described by a vision model. Off by default, because most threads are text and this costs a download and a vision call per article. Turn it on for a blog whose material is demos, screen recordings and product videos, where the post text is a caption and the video is the whole story. It can still be asked for one link at a time with video_frames on tweet_to_article. |
| video_frame_count | integer | tweet-to-article: how many stills to take out of a video (1-8). Leave it out for one per 20 seconds, up to 4.1-8 |
| thread_images | boolean | tweet-to-article: put the pictures the posts already carry inside the article - the charts, the benchmark tables, the screenshots, including the ones posted in the replies. ON by default, because they are the evidence the discussion is about and they cost no image generation. Turn it off for a blog that wants its X pieces to be text with one cover. |
| thread_image_count | integer | tweet-to-article: how many pictures from the thread one article may use (1-12). Leave it out for as many as the thread carries, up to 6.1-12 |
| read_links | boolean | tweet-to-article: open the pages the posts link to and write from what they actually say. ON by default. A post that is one sentence and a URL is the common case, and without this the article is a summary of how people reacted to a page nobody read. Links to X itself are not read here: those are the thread chain, which depth already follows. |
| link_count | integer | tweet-to-article: how many linked pages to open per article (1-4). Leave it out for 2.1-4 |
| lang | string | tweet-to-article: language these articles are written in. Empty means the project main language.max 10 chars |
| intensity | string | emphasis: how much italic the articles carry. "light" (the default everywhere) is about three italicised terms per thousand words, so a normal article gets three or four. "off" leaves articles exactly as written.off | light | medium | strong |
| max_spans | integer | emphasis: ceiling on italics per article whatever its length (default 6).0-40 |
| min_words | integer | emphasis: articles shorter than this are left alone (default 120).0-5000 |
| apply_on_generation | boolean | emphasis: italicise every article as it is written (default true). False means it only happens when emphasize_article is called. |
| style_instructions | string | emphasis: what this blog italicises - product names, titles of works, jargon being defined. The built-in rule is "the term at the moment it is introduced".max 2000 chars |
| enabled | boolean | cover: draw a cover for every article (default true). false is the only way to have a blog with no automatic covers - and publish_article refuses an article without one, so those have to be set by hand. |
| source | string | cover: where a cover comes from when the material the article was built on already carries a picture. "ai" always draws one (default). "tweet" uses the picture in the source post - its photo, or the frame X shows before its video plays. "auto" uses it when there is one and draws otherwise, which is the right setting for a news blog. Material with no picture always falls back to a drawn cover.ai | tweet | auto | none |
| art_direction | string | cover: what the covers look like - medium, palette, composition, whether people appear. Added to the image agent art direction rather than replacing it.max 4000 chars |
| avoid_text | boolean | cover: forbid rendered text, letters and watermarks in the picture (default true). Rendered text is still the tell. |
| subject_from | string | cover: "article" (default) reads the piece and picks what should be in the frame, which is the difference between a cover about the article and one about its title. "title" uses the title and its keywords only, and costs nothing extra.article | title |
| subject_instructions | string | cover: what that pass should favour or never show ("prefer the object being discussed; never a handshake, never a lightbulb").max 4000 chars |
| subject_model | string | cover: the small text model that reads the article to pick the subject. Empty means the product default.max 120 chars |
| title_overlay | string | cover: whether the article title is printed on a cover taken from the source material. "source" (default) turns the picture in the post into the illustration of a card that carries the headline and credits the handle it came from - it is drawn locally, costs nothing, and it is what stops an article about a leak going out under a banner that says nothing about it. "never" uses the picture exactly as the post shipped it. Drawn covers are never written on, whatever this says: avoid_text governs those.source | never |
| overlay_accent | string | cover: the accent colour of that card, as a hex value like "#ff6a3d". Empty means the built-in one.max 20 chars |
| provider | string | AI provider to run this agent on. Defaults to a configured one. For a cover agent this is the IMAGE provider, like the image agent.max 40 chars |
| model | string | Model id. For an image or cover agent see list_image_models.max 120 chars |
| activate | boolean | Switch the agent on (default) or off. Sending it alone reactivates a configured agent that was paused. |
Write a brand-new article from a topic you provide. Creates the draft immediately and queues the AI writer to fill it in, so the article appears in the dashboard right away with a "writing" state. The same job also draws the cover and links it to the article, so no second call is needed and no article comes out unpublishable for want of one; the project image agent supplies the style when it has one. Set generate_cover false to skip it, or image_agent_id to pick which image agent draws it. Bring your own photos with images: a list of public URLs, which are copied into the project CDN, placed in the body by the writer where they fit the text, and used as the cover (the first one, unless you flag another) instead of drawing one. Returns article_id + job_id - poll get_job until it succeeds, then read the result with get_article. Spends AI credits. IMPORTANT: when the project has no configured writer yet, this writes NOTHING and returns status "setup_required" with questions to put to the user - ask them, save the answers with configure_agent, then call this again (or pass skip_setup true to write with a generic default). To review the topic first instead, use create_idea + promote_idea.
| Argument | Type | Description |
|---|---|---|
| topic* | string | What the article should be about. A full brief works better than a bare title: audience, key points to cover, what to avoid.max 4000 chars |
| title | string | Working title (defaults to the first line of the topic; the writer may refine it)max 200 chars |
| angle | string | The specific take or point of view for this piecemax 480 chars |
| target_keyword | string | Primary SEO keyword to rank formax 120 chars |
| secondary_keywords | array | Supporting keywords (max 10)of string |
| categories | array | Article categories (max 10)of string |
| content_type | string | e.g. "how-to guide", "comparison", "case study"max 60 chars |
| custom_instructions | string | Extra writing instructions for this article only (structure, tone, things to include)max 1000 chars |
| lang | string | Language code (defaults to the project main language)max 10 chars |
| agent_id | string | Writer agent to use (defaults to the project writer)max 120 chars |
| generate_cover | boolean | Draw a cover image in the same job and attach it to the article. On by default, because publish_article refuses an article with no cover; false leaves it for set_article_cover or a later generate_image. |
| body_images | integer | How many illustrations to draw INSIDE the article, on top of the cover, each from what its own section says. Leave it out for the project rule (two by default); 0 for a cover and nothing else.0-4 |
| image_agent_id | string | Image agent that draws the cover (defaults to the project image agent). See list_agents with agent_type "image".max 120 chars |
| cover_agent_id | string | Cover agent whose art direction the cover is drawn with, when the project keeps more than one. See list_agents with agent_type "cover". Omit for the project one, which is what makes every article on a blog look like the same publication.max 120 chars |
| image_prompt | string | Your own cover prompt, used verbatim instead of the one the image agent builds from the article.max 4000 chars |
| skip_setup | boolean | Write even though the project has no configured writer, using a generic default. Use it when the user is not available to answer the setup questions; the project is not asked again afterwards. |
| images | array | Photos to use in this article, as public URLs (max 8). They are copied into the project CDN, handed to the writer so it places them where they illustrate the text, and any it leaves out are placed automatically. The first one becomes the cover unless another is flagged use_as_cover.of object |
| use_first_image_as_cover | boolean | When images are supplied and none is flagged use_as_cover, take the first as the cover (default true). False keeps every supplied photo in the body.default true |
| rehost_images | boolean | Copy the supplied images into the project CDN first (default true). False links the URLs exactly as given.default true |
Generate an AI image for one project and get back a durable URL you can use as an article cover or embed in markdown. The image is filed in that project's asset library, so it also shows up on the Assets page of the dashboard and can be reused or removed later (list_assets / delete_asset). An image therefore belongs to a project: when this connection reaches more than one, ASK the user which project it is for and pass project_id - never pick one yourself, because it spends that project's credits and lands in its library. Runs through the project image agent by default: its model and art direction are applied, so the result matches the rest of the blog. Pass agent_id to pick a specific image agent, or override provider/model/size/quality yourself - with provider "openrouter" the model is any OpenRouter image slug ("google/gemini-3-pro-image", "black-forest-labs/flux.2-pro"); call list_image_models to see what is available. Pass article_id + set_as_cover to attach the result to an article in one call (also needs the "Edit articles" permission). Spends AI credits.
| Argument | Type | Description |
|---|---|---|
| prompt* | string | What to draw. Be specific: subject, composition, style, mood.max 4000 chars |
| article_id | string | MongoDB ObjectId of the article this image illustrates (used as context, and required for set_as_cover) |
| set_as_cover | boolean | Store the generated image as the cover of article_id. Requires the "Edit articles" permission. |
| agent_id | string | Image agent whose model and art direction to use (defaults to the project image agent). See list_agents with agent_type "image".max 120 chars |
| apply_art_direction | boolean | Wrap your prompt in the image agent style instructions so it matches the rest of the blog. Set false to send the prompt exactly as written.default true |
| provider | string | Image provider. "openrouter" reaches every model on the gateway (defaults to the image agent, then the project setting)openai | openrouter | stability |
| model | string | Image model id, or an OpenRouter slug like "google/gemini-3-pro-image" (defaults to the image agent, then the project setting)max 120 chars |
| size | string | e.g. "1024x1024", "1536x1024" (defaults to the image agent, then the project setting)max 20 chars |
| quality | string | Provider quality tier, e.g. "high" (defaults to the image agent, then the project setting)max 20 chars |
| style | string | Provider style hint, e.g. "vivid" (defaults to the image agent, then the project setting)max 20 chars |
| count | integer | How many variations to generate (each one costs credits)1-4 - default 1 |
Queue a recommendations run (related-articles suggestions) for every published article in the project. Articles already queued are skipped. Spends AI credits per article when the worker runs. Requires an active recommendations agent.
| Argument | Type | Description |
|---|---|---|
| priority | integer | Queue priority (0-10, higher runs sooner)0-10 - default 5 |
Promote an article idea into a draft article and queue its AI generation (the same "Accept & write" action as the dashboard). Returns the created article id and the generation job id (track it with get_job). Spends AI credits when the writer runs. Idempotent: promoting an already-promoted idea returns the existing job. When the project has no configured writer yet, this promotes nothing and returns status "setup_required" with questions to ask the user - see configure_agent, or pass skip_setup true.
| Argument | Type | Description |
|---|---|---|
| idea_id* | string | MongoDB ObjectId of the idea (see list_article_ideas) |
| lang | string | Override the article language (defaults to the idea language) |
| agent_id | string | Writer agent to use (defaults to the project writer) |
| skip_setup | boolean | Promote even though the project has no configured writer, using a generic default. The project is not asked again afterwards. |
Queue a translation of one article into one or more target languages. Returns immediately with queued job ids (track them with list_jobs / get_job). Each translation lands as a DRAFT unless publish is true, in which case it goes live by itself as soon as it is done. Target languages must be languages the project is configured for (see describe_project); languages already translated or already queued are skipped. Each queued language spends AI credits when the worker runs it. Requires an active translation agent in the project (see list_agents).
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article to translate |
| target_langs* | array | Target language codes the project is configured for, e.g. ["FR", "ES"]. Case-insensitive.of string |
| translate_images | boolean | Also localize text baked into images |
| publish | boolean | Publish each translation as soon as its job finishes, instead of leaving it as a draft to publish one by one. A translation is never published ahead of its source, so this does nothing while the source article is a draft; a translation with no cover or no meta description is left as a draft too. Needs the "Edit articles" permission on top of the one this tool already takes. |
| priority | integer | Queue priority (0-10, higher runs sooner)0-10 - default 5 |
Queue translations for every missing (article, language) pair in the project. Skips pairs already translated or already queued. Each translation lands as a DRAFT unless publish is true, in which case every translation of an already-published article goes live by itself as soon as it is done. Set dry_run to see how many translations would be created (and which languages) without queuing anything. Each queued translation spends AI credits when it runs. Requires an active translation agent.
| Argument | Type | Description |
|---|---|---|
| target_langs | array | Optional subset of target language codes to limit to, e.g. ["FR"]. Defaults to all project languages.of string |
| translate_images | boolean | Also localize text baked into imagesdefault true |
| publish | boolean | Publish each translation as soon as its job finishes, instead of leaving a draft per language to publish one by one. A translation is never published ahead of its source, so translations of articles that are still drafts stay drafts (the answer counts them as will_stay_draft); so does one with no cover or no meta description. Needs the "Edit articles" permission on top of the one this tool already takes. |
| priority | integer | Queue priority (0-10, higher runs sooner)0-10 - default 5 |
| dry_run | boolean | Report what would be queued without creating any jobs |
Turn an X (Twitter) thread into an article. Reads the post, the post it is built on when it quotes or answers one, and the discussion under each, ranks the replies that matter (the ones with numbers, first-hand experience, real pushback, and the ones the author answered), works out what the whole chain adds up to, and hands all of it to the project writer as source material with the instruction to quote real people by handle and to say what the original post claimed before what the post on top made of it. Creates the draft immediately and queues the writer, so it appears in the dashboard right away in a "writing" state, and it always comes out with a cover: the same job draws one from a prompt written for this thread, so nothing else is needed before publishing. The pictures the posts carry - the charts, the benchmark tables, the screenshots, including the ones posted in the replies - go INSIDE the article by default: each one is copied into the project CDN, described by a vision model and placed by the writer where it belongs, because they are the evidence the discussion is about (pass thread_images false for a text-only piece). The pages the posts link to are opened and read the same way, so the article is written from the paper, the announcement or the benchmark itself rather than from the sentence somebody wrote above the link (read_links false skips them). When the post carries a picture worth showing - a chart, a screenshot, a demo video - pass cover_source "tweet" and the cover becomes that photo, or the frame from the video, instead of a drawing. When the post IS a video and the user wants the article to show it, pass video_frames: stills are cut from inside the video, read by a vision model and placed in the body by the writer, and what happens in the video goes to it as source material. Returns article_id + job_id - poll get_job, then get_article. Spends AI credits. Use analyze_tweet_discussion first when the user should approve the angle: this call reuses that read and that analysis instead of paying for them twice. Refuses a thread this project has already turned into an article in the same language, and names the existing one, so the same link pasted twice never quietly becomes two pieces (pass allow_duplicate to write a second take anyway). IMPORTANT: when the project has no configured writer this writes NOTHING and returns status "setup_required".
| Argument | Type | Description |
|---|---|---|
| tweet_url* | string | The post to write about: a link like https://x.com/user/status/123, or the numeric idmax 500 chars |
| lang | string | Language code (defaults to the project main language)max 10 chars |
| custom_instructions | string | Editorial direction for this article only: an angle to take, an audience, a section to insist onmax 2000 chars |
| content_type | string | e.g. "analysis", "explainer", "opinion piece" (defaults to what the agent asks for, or an analysis of the thread)max 60 chars |
| tweet_agent_id | string | Write with the rules of one specific tweet-to-article agent (see list_agents) - useful when a project keeps one for news briefs and one for long analyses. Omit to use the project's main one.max 120 chars |
| limit | integer | How many top replies to give the writer. Omit it to use the project's tweet-to-article agent (15 when it has none).1-60 |
| pages | integer | Reply pages to walk (1-5). Raise it for a thread with hundreds of replies. Omit it to use the project's tweet-to-article agent (2 when it has none).1-5 |
| ranking_mode | string | How X orders replies before they are re-scored. Omit it to use the project's tweet-to-article agent.Relevance | Likes | Recency |
| depth | integer | How far back to read (1-3). 1 reads only the post you passed. 2 also reads what it is built on - the post it quotes, the post it answers, an X link in its text - each with its own ranked reply section, because a post that comments on another one usually leaves the numbers and the original claim in the post underneath. 3 goes one hop further. Omit it to use the project's tweet-to-article agent (2 when it has none).1-3 |
| max_sources | integer | How many other posts the read may follow in total (0-6). Omit it to use the project's tweet-to-article agent (3 when it has none).0-6 |
| agent_id | string | Writer agent to use (defaults to the project writer)max 120 chars |
| cover_source | string | Where the cover comes from. "ai" draws one from a prompt written for this thread (the usual answer). "tweet" uses the post's OWN picture instead - the photo it carries, or, when it carries a video, the frame X shows before the video plays, which is the screenshot of it; the file is copied into the project CDN and nothing is paid to draw an image. "auto" takes the post's picture when it has one and draws one otherwise. "none" leaves the article without a cover, which publish_article then refuses. Pass "tweet" when the user says to use the image, the screenshot or the video from the post. A post with no picture falls back to a drawn cover, so the article is never left without one. Omit it to use the project's tweet-to-article agent.ai | tweet | auto | none |
| generate_cover | boolean | Draw the cover in the same job. On by default, because an article with no cover cannot be published; false skips it and leaves the article for set_article_cover or generate_image. |
| image_agent_id | string | Image agent that draws the cover (defaults to the project image agent)max 120 chars |
| cover_agent_id | string | Cover agent whose art direction the cover is drawn with (see list_agents with agent_type 'cover'). Omit to use the one the tweet-to-article agent names, then the project's own - which is what keeps a thread article looking like the rest of the blog.max 120 chars |
| image_prompt | string | Your own cover prompt, used instead of the one written from the threadmax 4000 chars |
| body_images | integer | How many illustrations to DRAW inside the article, on top of the cover, each from what its own section says. Omit it for the project rule (two by default), except when the thread supplied two or more real pictures of its own, where nothing is drawn: four charts out of the discussion with two generic drawings between them is a worse article than four charts. 0 is a cover and nothing else, and a number here always wins.0-4 |
| video_frames | boolean | Open the video in the post and put stills from INSIDE it in the article. Off by default. When the whole content of a post is a screen recording or a demo, the text is a caption and the article has nothing to show: this cuts a few stills spread across the video, has a vision model say what each one shows and what happens across them, files them in the project CDN, and hands them to the writer to place where they illustrate its own text. The reading of the video also goes to the writer as source material, so the article describes what happened instead of "the video reportedly shows". Pass it when the user asks for screenshots, frames or images from the video. Costs a download, an ffmpeg run per still and one vision call. A post with no video, or a host with no ffmpeg, still produces the article and says why it has no stills. |
| video_frame_count | integer | How many stills to take (1-8). Omit it for one per 20 seconds of video, up to 4. Only used when video_frames is on.1-8 |
| thread_images | boolean | Put the pictures the posts already carry INSIDE the article. ON by default, and worth leaving on: a thread argues with charts, benchmark tables and screenshots, and an article that describes them without showing them is strictly worse than one that shows them. Every photo in the chain is taken - the post, the author's own follow-ups, the post it quotes, the posts behind it, and the replies - copied into the project CDN, read by a vision model for its alt text and caption, and handed to the writer to place where it illustrates its own text. The cover is never repeated in the body. It costs no image generation, since the pictures already exist; the only cost is one vision call on a thread that has any. Pass false for a deliberately text-only piece, or when the user says not to use the images from the post. |
| thread_image_count | integer | How many pictures from the thread to use (1-12). Omit it for as many as the thread carries, up to 6. Only used when thread_images is on.1-12 |
| read_links | boolean | Open the pages the posts link to and write from what they say. ON by default. A large share of the posts worth covering are one sentence and a URL - a paper, a release, a benchmark, a news story - and without this the article is a summary of how people reacted to something nobody read. The pages are fetched, reduced to their text and read in one pass that reports what each one argues, the figures worth citing and the lines worth quoting, all of which goes to the writer as primary source material. Links to X itself are not read here: those are the thread chain and depth already follows them. Pass false to write from the discussion alone. |
| link_count | integer | How many linked pages to open (1-4). Omit it for 2. Only used when read_links is on.1-4 |
| skip_setup | boolean | Write even though the project has no configured writer, using a generic default. |
| allow_duplicate | boolean | Write a second article about a thread this project has already covered in this language. Without it the call is refused and tells you which article already exists, so the same link pasted twice does not quietly produce two pieces about one discussion. |
| refresh | boolean | Read the thread again from X and pay for a fresh analysis, instead of reusing what analyze_tweet_discussion or scrape_tweet just read. Only worth it when the discussion has moved since. |
articles.create
write2 toolsCreate articles and add ideas to the backlog
Create an article from content you wrote yourself (no AI credits spent). The handle, slug and URL section are derived from the title and the project's URL structure unless you pass an explicit handle. Publishing straight away requires a cover and a meta description, exactly like publish_article - otherwise it is created as a draft.
| Argument | Type | Description |
|---|---|---|
| title | string | max 255 chars |
| handle | string | URL path, unique within the project. Leave empty to derive it from the title as "<url-segment>/<slug>".max 300 chars |
| lang | string | Language code (defaults to the project main language)max 10 chars |
| md | string | Markdown body of the article |
| cover | string | Cover image URL (generate_image can produce one) |
| meta_title | string | max 150 chars |
| meta_description | string | max 500 chars |
| categories | array | of string |
| status | string | draft | published - default "draft" |
| date | string | Publish date, defaults to now |
Add an article idea to the project backlog. Use it to bring your own topic into Reblog: the idea shows up in the Ideas board for review, and promote_idea turns it into a written article. Free (no AI credits). Duplicate titles are not inserted twice - the existing idea is returned instead.
| Argument | Type | Description |
|---|---|---|
| title* | string | The article title / headline this idea proposesmax 200 chars |
| angle | string | The specific take or point of view for this piecemax 2000 chars |
| summary | string | What the article should cover, in a few sentencesmax 2000 chars |
| target_keyword | string | Primary SEO keyword to rank formax 120 chars |
| secondary_keywords | array | Supporting keywords (max 10)of string |
| content_type | string | e.g. "how-to guide", "comparison", "case study"max 60 chars |
| categories | array | Article categories (max 10)of string |
| audience | string | Who this article is formax 120 chars |
| search_intent | string | e.g. "informational", "commercial"max 120 chars |
| rationale | string | Why this idea is worth writingmax 2000 chars |
| lang | string | Language code (defaults to the project main language)max 10 chars |
| score | integer | Priority score, higher sorts first0-100 |
| status | string | "new" queues it for human review, "approved" marks it ready to writenew | approved - default "new" |
articles.edit
write16 toolsEdit articles, and publish, schedule or unpublish them
Insert one photo into the body of an article from a public URL (or an asset_id from list_assets), at the position you choose: at the end, under a section heading, after a numbered paragraph, after a sentence you quote, or next to an existing image. The file is copied into the project CDN first, so the article never points at someone else's host - pass rehost false to link the original URL as-is. Give it alt text (good for SEO and accessibility) and an optional caption. Use dry_run to see where it would land before saving. To place several photos at once, use attach_article_images; for the cover, set_article_cover.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the articlemax 40 chars |
| url | string | Public http(s) URL of the imagemax 2000 chars |
| asset_id | string | Use a file already in the project asset library instead of a URL (see list_assets)max 60 chars |
| alt | string | Alt text describing the image. Write one: it is what search engines and screen readers read.max 300 chars |
| caption | string | Caption rendered in italics under the imagemax 300 chars |
| position | string | "end" (default), "top" (under the title), "after_heading" (+ heading), "after_paragraph" (+ paragraph), "after_text" (+ after_text), "before_image"/"after_image" (+ image_index)end | top | after_heading | after_paragraph | after_text | before_image | after_image - default "end" |
| heading | string | For position "after_heading": the section title to place it under (partial match is fine)max 200 chars |
| paragraph | integer | For position "after_paragraph": which paragraph to place it after (1 = the first)min 1 |
| after_text | string | For position "after_text": a unique sentence from the article; the image goes right after itmax 500 chars |
| image_index | integer | For position "before_image"/"after_image": the position of the existing image, as given by list_article_imagesmin 1 |
| rehost | boolean | Copy the file into the project CDN first (default true). False keeps the URL exactly as given.default true |
| filename | string | Name to store the copy under (defaults to the name in the URL)max 200 chars |
| dry_run | boolean | Show where the image would land, and the markdown that would be inserted, without saving |
Make targeted edits to an article body by exact find-and-replace, without resending the whole markdown. Read it first with get_article, then pass one or more { old_string, new_string } edits. Each old_string must appear exactly once unless replace_all is set. Set dry_run to validate and preview the result without saving. Each applied edit returns a context snippet plus a preview_url to view the result.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article to edit |
| dry_run | boolean | Validate and compute the result without saving. Returns the same per-edit context as a real run so you can confirm before committing. |
| edits* | array | Ordered list of edits applied to the markdown bodyof object |
Decide on an article awaiting approval in the review queue. decision "approve" publishes it immediately (internal + configured CMS, fails without cover/meta description); "reject" returns it to draft and cancels any auto-publish deadline. Only works on articles with status awaiting_approval.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article (see the review queue) |
| decision* | string | approve | reject |
Put several photos into an article at once, from public URLs (or asset_ids). They are copied into the project CDN and spread through the body - one under the opening paragraph of each section that has no picture yet, in the order given - and the first one becomes the cover when the article does not have one. Use it when someone hands over a batch of photos for an article. placement "end" instead puts them all at the bottom in order; set_cover_from controls the cover. Use dry_run to see the plan first, and add_article_image when one photo must land in one exact spot.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the articlemax 40 chars |
| images* | array | The photos to add, in the order they should appear (max 12)of object |
| placement | string | "auto" (default) spreads them across the sections; "end" appends them all at the bottom in orderauto | end - default "auto" |
| set_cover_from | string | "first_if_missing" (default) uses the first photo as cover only when the article has none, "first" always, "none" neverfirst_if_missing | first | none - default "first_if_missing" |
| rehost | boolean | Copy the files into the project CDN first (default true)default true |
| dry_run | boolean | Show where each photo would land, without uploading or saving |
Draw the cover image of an article and attach it, in one call. The picture is about the article, not about its title: a short pass reads the piece and picks what should be in the frame, then the project's cover agent decides what it looks like (list_agents shows it as cover_rules), so every cover on a blog comes out of the same art direction. This is what to call when publish_article says an article has no cover, or when someone asks to add or replace one. Pass subject to say what the picture should show, art_direction for a one-off look, or prompt to send an exact prompt of your own and skip both. When the article was made from an X thread and the rules say the cover comes from the source material, the picture in the post is used instead of a drawn one - the chart, the screenshot, the frame from its video - which costs nothing at all; source overrides that for one article. A picture taken that way goes out on a card carrying the article title and crediting the handle it came from, because a screenshot on its own says nothing about the piece (the cover agent's title_overlay turns that off). Use preview to see the rules, the model and what it would do for free before spending anything. An article that already has a cover is left alone unless replace is true. Spends AI credits when it draws.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article to illustrate (from list_articles).max 40 chars |
| subject | string | What the picture should show, in concrete things ("a folded paper map on a workbench"). Omit to let the cover agent read the article and choose.max 1000 chars |
| art_direction | string | A one-off note about the look of THIS cover, added to the project's standing art direction rather than replacing it.max 2000 chars |
| prompt | string | An exact prompt to draw, used verbatim. This skips both the subject pass and the art direction, so only pass it when you mean to ignore the house style.max 4000 chars |
| subject_from | string | "article" reads the piece to choose the subject (the default). "title" uses the title and its keywords only, and calls no extra model.article | title |
| source | string | Where the picture comes from for THIS article, beating the project rule. "ai" draws one. "tweet" takes the picture from the X post the article was built on - its photo, or the frame X shows before its video plays - which costs no credits at all; a post with nothing usable falls back to a drawing. "auto" takes the post's picture when there is one and draws otherwise. Only meaningful on an article that carries a source post; everything else is drawn whatever this says.ai | tweet | auto |
| size | string | Output size, e.g. "1536x1024" for a landscape cover. Omit to use the project rule.max 20 chars |
| quality | string | Provider quality tier, e.g. "high". Omit to use the project rule.max 20 chars |
| agent_id | string | Use a specific cover agent (see list_agents with agent_type "cover"). Omit for the project one.max 120 chars |
| image_agent_id | string | Which image agent supplies the model and the art direction. Omit for the one the cover agent names, then the project image agent.max 120 chars |
| replace | boolean | Draw a new cover even though this article already has one. Off by default, so a cover somebody chose is never overwritten by accident. |
| preview | boolean | Report the rules, the model and the prompt that would be used, WITHOUT drawing anything or spending anything. Free. |
Add a light touch of italic emphasis to an article that reads flat, or strip the italics it already has. The typographer picks a few terms - the concept a sentence introduces, the two or three words it turns on - and italicises those and nothing else: it may only add asterisks, never change a word, so a bad suggestion is dropped rather than written. How much is the project's own house style, held by its emphasis agent (list_agents shows it as emphasis_rules), so pass intensity only when this one article should differ. Articles written from now on already come out formatted this way; this is for the ones written before. Use preview to see what would change without touching the article or spending anything, and mode "clear" to remove every italic instead.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article to format (from list_articles). |
| mode | string | "add" (default) puts a few italics in. "clear" takes every italic back out, which is free, instant and the way back from a pass somebody found too heavy.add | clear |
| intensity | string | How much emphasis this one article should carry. "light" is about three italics per thousand words. Omit to use the project rule, which is what keeps a library looking like one publication.light | medium | strong |
| max_spans | integer | Ceiling on how many italics this run may add, whatever the length says. Omit to use the project rule.1-40 |
| style_instructions | string | What is worth italicising in this particular piece, on top of the project rule.max 2000 chars |
| agent_id | string | Use a specific emphasis agent (see list_agents). Omit for the project one.max 120 chars |
| preview | boolean | Report what the article carries now and how much the rules would add, WITHOUT calling a model or writing anything. Free. |
Move a photo that is already in an article to another place in the body, keeping its alt text and caption. Target it by index (from list_article_images) or URL, and give the new position the same way add_article_image does: end, top, after_heading, after_paragraph, after_text, or before_image / after_image. Note that before_image / after_image count the images as they are once this one is lifted out. Use dry_run to preview.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the articlemax 40 chars |
| index | integer | Position of the image to move, as given by list_article_imagesmin 1 |
| url | string | Alternative to index: the URL of the image to movemax 2000 chars |
| position | string | Where it goes: "end", "top", "after_heading" (+ heading), "after_paragraph" (+ paragraph), "after_text" (+ after_text), "before_image"/"after_image" (+ image_index)end | top | after_heading | after_paragraph | after_text | before_image | after_image - default "end" |
| heading | string | For position "after_heading": the section title to move it under (partial match is fine)max 200 chars |
| paragraph | integer | For position "after_paragraph": which paragraph it goes after (1 = the first)min 1 |
| after_text | string | For position "after_text": a unique sentence from the articlemax 500 chars |
| image_index | integer | For position "before_image"/"after_image": which remaining image to sit next tomin 1 |
| dry_run | boolean | Show where it would land without saving |
Publish an article (set its status to published). Fails if the article has no cover image or no meta description, exactly like the dashboard. Also refreshes the linked translations and the recommendation references that point to it. Idempotent: publishing an already-published article is a no-op.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article to publish |
Remove one photo from the body of an article, together with its caption line. Target it by index (from list_article_images) or by URL. The file stays in the project asset library so other articles and translations keep working - use delete_asset if it should be gone for good. Use dry_run to check which image would go.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the articlemax 40 chars |
| index | integer | Position of the image to remove, as given by list_article_imagesmin 1 |
| url | string | Alternative to index: the URL of the image to removemax 2000 chars |
| dry_run | boolean | Show which image would be removed without saving |
Swap one photo in an article for another, or fix its alt text or caption, without touching the rest of the body. Target it by index (from list_article_images) or by its current URL. Pass url (or asset_id) to change the picture, alt/caption to change the wording - any combination. A new URL is copied into the project CDN first unless rehost is false. Use dry_run to preview.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the articlemax 40 chars |
| index | integer | Position of the image to replace, as given by list_article_imagesmin 1 |
| current_url | string | Alternative to index: the URL the image currently points atmax 2000 chars |
| url | string | Public http(s) URL of the new imagemax 2000 chars |
| asset_id | string | Use a file already in the project asset library as the new image (see list_assets)max 60 chars |
| alt | string | New alt text. Pass an empty string to clear it.max 300 chars |
| caption | string | New caption (italic line under the image). Pass an empty string to remove it.max 300 chars |
| rehost | boolean | Copy the new file into the project CDN first (default true)default true |
| filename | string | Name to store the copy under (defaults to the name in the URL)max 200 chars |
| dry_run | boolean | Show the change without saving |
Force the customer's site to drop its cached copy of an article, now. Publishing, editing, renaming and deleting already do this on their own, so reach for it when a page on the live site is still showing something we changed - typically because the site was unreachable when the purge first fired. Call it with no article_id to send a test ping instead, which checks the endpoint and the secret without touching an article. Answers delivered true/false: false with a `reason` means revalidation is not configured for this project (nothing was sent, nothing is queued), false with an `error` means the site was reached and refused. Use get_revalidation_status to see the delivery history.
| Argument | Type | Description |
|---|---|---|
| article_id | string | MongoDB ObjectId of the article to purge. Omit to send a configuration test ping for the project instead. |
Restore an article body to a previous version recorded in its history. Get the history_id from get_article_history. By default this restores the "before" snapshot (undoing that change); set side to "after" to re-apply it. The rollback is itself recorded in history, so it can be undone too.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article to restore |
| history_id* | string | history_id of the version to restore (from get_article_history) |
| side | string | Which snapshot of the chosen history entry to restorebefore | after - default "before" |
Book an article to publish itself at a future date, or clear an existing booking. Sets the article to "scheduled" with a publish_at instant; when the slot comes due it publishes on its own, internally and to the configured CMS, with no further call. Pass publish_at null to unschedule (the article goes back to draft). Get the dates from suggest_publishing_slots rather than inventing them - it returns instants in the project timezone that avoid days already taken. Refuses an already-published article. Unlike publish_article this does NOT need a cover or a meta description yet, but the article must have both by the time the slot fires or it is parked in the review queue instead: the response says what is still missing.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article to schedule |
| publish_at* | string | null | ISO-8601 instant for the publication, e.g. "2026-09-15T10:00:00Z" (a bare "2026-09-15" is read as midnight UTC). Null unschedules the article and returns it to draft. |
Set an article's cover photo from a public URL, from a file in the asset library (asset_id), or by promoting one of the images already in the body (image_index, from list_article_images). The file is copied into the project CDN first unless rehost is false. Every article needs a cover before publish_article accepts it, so this is usually the last thing missing on a draft written from a topic with no image agent. Use generate_image instead when the picture has to be drawn.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the articlemax 40 chars |
| url | string | Public http(s) URL of the cover imagemax 2000 chars |
| asset_id | string | Use a file already in the project asset library (see list_assets)max 60 chars |
| image_index | integer | Promote an image already in the body to cover, by its position from list_article_imagesmin 1 |
| rehost | boolean | Copy the file into the project CDN first (default true)default true |
| filename | string | Name to store the copy under (defaults to the name in the URL)max 200 chars |
| dry_run | boolean | Show what the cover would become without saving |
Unpublish an article (set its status back to draft). Also refreshes the linked translations and the recommendation references that point to it. Idempotent: unpublishing a draft is a no-op.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article to unpublish |
Update core fields of an existing article in the targeted project (title, handle, md, cover, meta, categories, status, date). Only the fields you pass are changed. Renaming the handle and flipping the status also refresh the copies other articles hold, so translations and recommendations stay in sync; switching to "published" needs a cover and a meta description.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article to update |
| title | string | max 255 chars |
| handle | string | URL path, must stay unique within the projectmax 300 chars |
| md | string | Markdown body |
| cover | string | Cover image URL |
| meta_title | string | max 150 chars |
| meta_description | string | max 500 chars |
| categories | array | of string |
| status | string | draft | published |
| date | string | Publish date |
assets.create
write1 toolAdd images and files to your projects
Copy an image or video from a public URL into a project's asset library, so it is served from the project's own CDN and can be used as an article cover or embedded in markdown. Use this for any picture that does not come from generate_image - a screenshot, a logo, an image the user found - because an article must not point at a file hosted somewhere else. Returns the durable URL to use. Images and videos only, 15MB max; the file name must be free in this project (pass filename to rename it). To put a photo straight into an article instead, add_article_image and set_article_cover do this copy for you.
| Argument | Type | Description |
|---|---|---|
| url* | string | Public http(s) URL of the file to copymax 2000 chars |
| filename | string | Name to store it under, e.g. "team-photo.jpg". Defaults to the name in the URL. Lowercased and slugified.max 200 chars |
| article_id | string | Article this file illustrates, recorded on the asset so list_assets can filter on itmax 40 chars |
articles.delete
write1 toolDelete articles
Permanently delete an article from the targeted project. This cannot be undone.
| Argument | Type | Description |
|---|---|---|
| article_id* | string | MongoDB ObjectId of the article to delete |
assets.delete
write1 toolDelete images and files, including ones your published articles use
Permanently delete one file from a project's asset library: the record AND the stored file, so every article still pointing at its URL loses the image. Take the asset_id from list_assets (or from what generate_image / upload_asset returned). The call is refused when an article uses the file, and tells you which ones: read that list to the user and only pass force true if they confirm. This cannot be undone.
| Argument | Type | Description |
|---|---|---|
| asset_id* | string | Identifier of the asset to delete, as returned by list_assetsmax 300 chars |
| force | boolean | Delete even though articles still use this file. Only after the user has confirmed. |
automation.manage
writesensitivecredits3 toolsManage automation routines: list, run, pause (a routine can publish articles autonomously and spends credits)
List the automation routines of the targeted project: schedule, pipeline, output policy, guardrails, next/last run times, and each routine's latest run outcome. Optionally include recent run history.
| Argument | Type | Description |
|---|---|---|
| include_runs | boolean | Also return the last 10 runs per routine |
Pause an automation routine (it stops firing on schedule; manual runs stay possible). Pass resume: true to re-enable it instead -- the next occurrence is recomputed from its schedule in the project timezone.
| Argument | Type | Description |
|---|---|---|
| routine_id* | string | The routine to pause or resume (see list_routines) |
| resume | boolean | true = re-enable instead of pausing |
Run an automation routine immediately (out of schedule). The run obeys the routine's guardrails and output policy; it produces articles asynchronously (follow progress with list_routines include_runs, or list_jobs). Fails if a run of this routine is already in progress. Spends AI credits.
| Argument | Type | Description |
|---|---|---|
| routine_id* | string | The routine to fire (see list_routines) |
`project_id` is not in the schemas
Every project-scoped tool accepts it, but it is a routing argument handled by the dispatcher, not a tool parameter: it is stripped before the handler runs. Clients are offered it automatically when a connection reaches more than one project.
Which scopes a preset grants, and which roles confer them: permissions and scopes. How a call is dispatched and what a failure looks like: protocol.