frontmatter · SKILL.md+
name: posts-create
description: >
Create a post on Inklate in one call — a draft, a scheduled post, or a publish-now,
decided entirely by whether you pass a schedule time — with the server's per-channel
validation riding along in the same response instead of a separate check. Covers
LinkedIn, X (Twitter), Instagram, and Facebook today, with Mastodon, Threads, Bluesky,
TikTok, and YouTube in platform review. Use when the user says "draft this on Inklate",
"create a post", "get this ready to publish", or "post this now". Requires the Inklate
CLI (npm i -g inklate) or the Inklate MCP connection. Reads social-context.md when
present so drafts and autofixes stay on-voice. A draft with errors still saves — arming
it with a schedule or publish time is the only thing the server refuses, and that
refusal never leaves a partial write behind.
license: MIT
metadata:
version: 0.2.0
topics:
- drafting
- checking
examplePrompt: "Draft this announcement on Inklate for LinkedIn and X and tell me if it's ready"
pairsWith:
- social-post
- social-thread
- social-crosspost
mcpTools:
- posts_create
- posts_update
- files_upload
cliCommands:
- posts create
- posts update
- files uploadCreate a draft on real channels in one call and hand back the server's own verdict — the safe half of the loop, ending exactly where a human (or the posts-publish skill) takes over.
Transports
- CLI (preferred):
inklate(npm i -g inklate) — structured YAML on stdout (--jsonfor JSON), progress on stderr, and typed exit codes:3no credentials,4a deliberate refusal — arming a not-ready post, or a plan limit — with its machine-readable payload on stdout,5not found,6the resource changed underneath you,7rate limited but safe to re-run later. Pass--no-inputwhen running unattended so a missing flag fails loudly instead of prompting, and--yesto carry an approval the user has already given in chat. This skill never passes--scheduled-atonposts create— that turns the call into an arming attempt, which isposts-publish's job. - MCP (fallback): the Inklate MCP tools when the CLI is not installed.
Steps below name the MCP operation with the CLI form in parentheses; the fields are the same on both.
Connection check
- Run
inklate auth check(MCP:organizations_list) first. - On exit 3 (no credentials): interactively run
inklate auth login; headless, the key comes fromINKLATE_API_KEY=inklate_…in the environment orinklate auth set --token inklate_…. If neither transport is available at all, tell the user to install withnpm i -g inklate(or connect athttps://inklate.com/skills/connect?ref=skills-posts-create) and STOP. - If multiple organizations exist, ask which one (CLI:
--org <slug>).
Craft boundary
This skill owns create → read the verdict → fix judgment calls. The WRITING belongs to the paired craft skills: when social-post, social-thread, or social-crosspost is installed, get the draft from them first and feed their output in. Without them, use the user's text as given and make only the edits the server's response demands.
Context
Read social-context.md (project root, then .agents/social-context.md) if present. ## Voice and ## Never constrain any fix that rewrites text; ## Platforms resolves vague targets ("post this" → the user's primary channel). Proceed without it if absent.
Workflow
- Establish content and targets. Markdown is the input sugar: a
---line splits thread items on channels that thread. Confirm target channels; provider names ("x", "linkedin") resolve server-side when the organization has one channel per platform. - If the post needs media from local files, upload them first with
files_upload(CLI:inklate files upload ./photo.jpg— prints reusablefile_…ids; the CLI also accepts local paths directly on--mediaand uploads them in-line). Media already on the web passes as a public https URL. - Create the draft in one call.
inklate posts create --content … --channel … --media …(MCP:posts_createwith{content, channels, media};autofixdefaults totrue). Never pass--scheduled-athere. The response IS the verdict — no separate check to run: a top-levelready, and per channel acontent.text(the actual copy that channel will receive),errors[](code,field, a human message with the real numbers, and a machinefixwhere one exists), andwarnings[]. A draft with errors still saves fine — exit 0, the errors ride along on stdout; only arming a schedule or publish time is refused. Add--idempotency-key <key>when a create might be retried — a rerun replays instead of leaving two drafts of the same post behind. - Autofix already ran before you saw the response. Default on, it silently repairs what it can —
trim_to_fold,rebalance_thread,set_title— and reports every repair infixes_applied(channel + kind; no extra call needed). Read out every entry as "channel — kind (auto-applied)" so nothing rewrites the user's words without them knowing. Pass--no-autofix(autofix: false) when the user wants to see the raw violations before anything is touched. - For every error still remaining (autofix had nothing to offer, or was off), the message already names the real numbers — no code-to-English translation needed. If
errors[].fixesoffers a repair you want to apply, callinklate posts update <id> --per-channel '{"<channel>": {"content": "…"}}'(MCP:posts_update) with the corrected copy for just that channel; the response re-validates and returns the same shape, so there is no separate re-check step. When a fix would change meaning or trips## Never, treat it as a judgment call instead — 2–3 concrete options to the user, not a guess. - Stop once the draft matches the user's intent — ready or not.
readygates arming, never saving. Publishing and scheduling are theposts-publishskill's job (or the user's, in the dashboard): offer the next command (inklate posts publish post_abc123 --wait) but never run it from this skill. A stand-alone dry run against a stored post or inline text with nothing written is a handoff toinklate posts validate— mention it, don't run it here.
Quality bar
readyis the only publishability signal to trust — never infer it from the absence of one particular error code.- Every entry in
fixes_appliedis named to the user by channel and kind; a silent autofix is a bug. - The receipt's post ID is the contract: any later skill or command can pick the draft up from it.
- This skill never passes
--scheduled-at/ ascheduled_atvalue — arming isposts-publish's call, even when the draft is already green. - A draft with errors is not a failure to hide: report it plainly, exit 0, and move straight to the fixes.
- Judgment-call fixes are applied through
posts update, never invented ahead of what the response'sfixesarray actually offered. - This skill never publishes, schedules, or deletes — its output is a validated draft. Editing or cancelling an existing post is
posts-update's job.
Receipt
End with:
| Post ID | Channel | Ready | Autofix applied | Remaining error |
|---|---|---|---|---|
| post_abc123 | yes | — | — | |
| post_abc123 | X | yes | rebalance_thread | — |
| post_abc123 | no | — | media required (no image attached) |
Below the table: whether the draft as a whole is ready (or which channels are parked and why), the exact next command to ship it (inklate posts publish post_abc123 --wait or the posts-publish skill), and any media file ids attached.