frontmatter · SKILL.md+
name: files-upload
description: >
Get images and video into Inklate media storage and ready to attach: upload local files
(or reference public URLs), wait for processing, and hand back reusable file ids with
their readiness. Covers jpg, jpeg, png, gif, and webp images plus mp4 and mov video. Use when the user says
"upload these images", "get this video into Inklate", "attach this file to a post", or
asks "is my media ready". Requires the Inklate CLI (npm i -g inklate) or the Inklate
MCP connection — local files need the CLI or the local `inklate mcp` bridge; a remote
MCP connection takes public https URLs instead. Reads social-context.md when present
only to name the channels whose media rules matter. Upload once, reference the file id
on as many posts as needed.
license: MIT
metadata:
version: 0.1.1
topics:
- media
examplePrompt: "Upload these three product shots and give me ids I can attach"
pairsWith:
- social-carousel
mcpTools:
- files_upload
- files_get
- files_list
- files_delete
cliCommands:
- files upload
- files get
- files list
- files delete
- mcpMove media into Inklate once, verify it processed, and return the file ids everything else attaches.
Transports
- CLI (preferred):
inklate files upload <paths…>handles the whole handshake — presigned reservation, byte upload, and polling until each file leavesprocessing. YAML on stdout (--jsonfor JSON), progress on stderr, and typed exit codes:3no credentials,4a deliberate refusal with its machine-readable payload on stdout,6the resource changed underneath you,7rate limited but safe to re-run later. Pass--no-inputwhen running unattended, and--yesto carry an approval the user has already given in chat (deleting a file needs it). - Local MCP bridge:
inklate mcpexposesfiles_uploadtaking local file paths (same handshake, run by the bridge). - Remote MCP: cannot read local disks — pass a public
https://URL directly inposts_create'smedialist instead; the server fetches and stores it (pollfiles_getuntil ready).
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-files-upload) and STOP. - If multiple organizations exist, ask which one owns the media library (CLI:
--org <slug>).
Context
Read social-context.md (project root, then .agents/social-context.md) if present, and use it for one thing only: ## Platforms names the channels this media is headed for, which is what makes the handoff in step 5 specific ("these two are for the LinkedIn carousel") instead of generic. Uploading does not depend on it — proceed without it.
Workflow
- Sort the inputs: local paths versus URLs. Local files ride the upload; public https URLs skip it — they attach directly on a post and are ingested server-side.
- Check the files fit before sending: supported types are jpg/jpeg/png/gif/webp (images, ≤25 MB) and mp4/mov (video, ≤512 MB), at most 10 per batch. Oversized or unsupported files are reported up front, not discovered as server errors.
.webmis not accepted for upload — the server can store WebM but refuses it on ingest, because its prober can't extract the duration and dimension facts the per-provider gates need. Tell the user to transcode to mp4 rather than attempting the upload. - Upload with
inklate files upload <paths…>(bridge:files_uploadwithpaths). The command waits for processing by default and prints onefile_…id per file. Pass an--idempotency-keywhen retrying a batch so a rerun replays instead of duplicating. - Verify readiness in the output:
readyfiles are attachable;failedfiles carry a machine-readable reason (too_large,unsupported_type,content_mismatch, …) — report the reason verbatim and what would fix it.inklate files get <id> --urlfetches a signed preview URL when the user wants to eyeball the stored asset. - Hand off: list the file ids in attach order and the exact usage —
--media file_… --media file_…oninklate posts create, or themediaarray onposts_create. Channel media rules (counts, required media on Instagram) are enforced in that create (orposts validate) response's per-channelerrors/warningsnow, not a separate check — mention them only when the user names the target channels. - For library questions ("what have I uploaded?"), use
inklate files list(MCP:files_list) with its readiness/kind filters, newest first.
Quality bar
- Never invent a file id: every id in the receipt came from this session's upload or list output.
- Failed uploads are reported with the server's reason verbatim — no softening, no retry loops past two attempts.
- Local paths are echoed next to their file ids so the user can map files to ids at a glance.
- This skill stores and reports; attaching to posts is
posts-create's job. Deleting is permanent, soinklate files delete <id> --yesruns only on an explicit request — and it is refused outright while the file is attached to a post, which is a reason to report, not a lock to work around.
Receipt
End with:
| File | File ID | Kind | Readiness | Notes |
|---|---|---|---|---|
| ./hero.png | file_a1b2c3 | image | ready | — |
| ./demo.mov | file_d4e5f6 | video | ready | 42 MB |
| ./massive.mov | — | video | refused | too_large (>512) |
Below the table: the attach-order id list ready to paste (--media file_a1b2c3 --media file_d4e5f6), and any failed files with their fix.