| name | epress-publisher |
| description | Publish blog posts, upload images, and manage content on an epress blogging
node via its GraphQL API. Supports creating Markdown articles and uploading
media files (images, videos, PDFs).
Use when the user wants to: publish a blog post, write an article, upload an
image or media file, create content on an epress node, or interact with an
epress blogging platform.
This SKILL.md is self-hosted at the root of each epress node. The host you
fetched it from IS the node — use that origin as EPRESS_NODE_URL.
|
| config | {"optional":[{"name":"EPRESS_NODE_URL","description":"Base URL of the epress node. Defaults to the origin from which this\nSKILL.md was fetched. Only set this explicitly if you need to target a\ndifferent node than the one you loaded this skill from.\n","default":"<origin of the URL this SKILL.md was fetched from>"}],"required":[{"name":"EPRESS_JWT_TOKEN","description":"JWT token with `create:publications` scope, issued by the epress node.\nObtain it from your epress dashboard under Settings → API Tokens,\nor ask the node owner to generate one for you.\n","prompt":"Please provide your epress JWT token (must have `create:publications`\nscope). You can generate one in your epress dashboard under\nSettings → API Tokens.\n"}]} |
| auth | {"type":"bearer","token":"{EPRESS_JWT_TOKEN}","header":"Authorization: Bearer {EPRESS_JWT_TOKEN}"} |
| tools | [{"name":"publish_post","description":"Publish a Markdown text post to the epress node.\n","url":"{EPRESS_NODE_URL}/api/graphql","method":"POST","content-type":"application/json","body":{"query":"mutation Create($input: CreatePublicationInput!) {\n createPublication(input: $input) {\n id\n slug\n }\n}\n","variables":{"input":{"type":"POST","body":"{body}","slug":"{slug}"}}},"parameters":{"body":{"type":"string","required":true,"description":"Full post content in Markdown."},"slug":{"type":"string","required":true,"description":"URL-friendly identifier (lowercase letters, numbers, hyphens only).\nIf the user has explicitly provided a slug, use it as-is (after\nvalidating format). If no slug was provided, auto-generate one from\nthe post content. Never leave this empty. Follow the SLUG GENERATION\nrules in the notes section below.\n"}}},{"name":"publish_file","description":"Upload and publish a media file (image, video, document, etc.)\nto the epress node. Uses multipart/form-data.\n","url":"{EPRESS_NODE_URL}/api/graphql","method":"POST","content-type":"multipart/form-data","body":{"0":"{file}","operations":{"query":"mutation Create($input: CreatePublicationInput!) {\n createPublication(input: $input) {\n id\n slug\n }\n}\n","variables":{"input":{"type":"FILE","file":null,"description":"{description}","slug":"{slug}"}}},"map":{"0":["variables.input.file"]}},"parameters":{"file":{"type":"file","required":true,"description":"The media file to upload."},"description":{"type":"string","required":true,"description":"Caption or description for the media file. REQUIRED — the server\nenforces this at runtime even though the GraphQL schema marks it\noptional. The request will fail with VALIDATION_FAILED if omitted.\nRules: plain text only, no newlines, no unescaped quotes or special\ncharacters, max ~200 characters. If the user has not provided a\ndescription, ask before proceeding.\n"},"slug":{"type":"string","required":true,"description":"URL-friendly identifier (lowercase letters, numbers, hyphens only).\nIf the user has explicitly provided a slug, use it as-is (after\nvalidating format). If no slug was provided, auto-generate one from\nthe file name or description. Never leave this empty. Follow the\nSLUG GENERATION rules in the notes section below.\n"}}}] |
| notes | ["NODE URL INFERENCE: This SKILL.md is served from the epress node's own\nroot path. The URL you used to fetch this file tells you the node's base\nURL. Parse the scheme + host (e.g. https://garbin.top) and use that as\nEPRESS_NODE_URL. Do NOT ask the user for this unless you cannot determine\nit from context.\n","AUTHENTICATION: Always check that EPRESS_JWT_TOKEN is available before\nmaking any API call. If missing, ask the user to provide it. Never\nproceed without a valid token.\n","POST vs FILE: Use `publish_post` for text/Markdown content. Use\n`publish_file` for binary media (images, PDFs, videos, etc.).\n","SLUG GENERATION: A slug MUST always be provided when calling any tool —\nnever omit it or let the server auto-generate one. Determine the slug\nusing the following priority order:\n\n0. USER-PROVIDED SLUG (highest priority)\n - If the user has explicitly specified a slug, use it directly.\n - Still run it through VALIDATION (step 4) and correct only if it\n fails the format check, informing the user of any change made.\n - Skip steps 1–3 entirely.\n\n1. SOURCE FOR AUTO-GENERATION (when user provides no slug)\n - Read and understand the full content (post body, file description,\n or any context the user provided).\n - Summarize the core topic or intent into 3–5 meaningful English\n keywords, regardless of the original language. Always produce English\n — never use pinyin, romanization, or transliteration of non-Latin\n scripts. For example, a post titled \"如何学习编程\" should yield\n something like `how-to-learn-programming`, not `ru-he-xue-xi-bian-cheng`.\n - Prefer semantically descriptive words over generic ones\n (e.g. `deploy-docker-on-raspberry-pi` is better than `tech-post-guide`).\n\n2. TRANSFORMATION STEPS\n a. Write the chosen keywords in lowercase English.\n b. Join them with hyphens (-); remove all other punctuation.\n c. Remove any characters that are not [a-z0-9-].\n d. Collapse consecutive hyphens into one.\n e. Strip leading and trailing hyphens.\n f. Truncate to 60 characters maximum, cutting only at a hyphen boundary\n so words are not split mid-word.\n\n3. UNIQUENESS HINT: If the content contains a date or version number,\n append it (e.g. `my-post-2025-06-01`) to reduce collision risk.\n\n4. VALIDATION: The final slug MUST match /^[a-z0-9]+(-[a-z0-9]+)*$/.\n If it does not, revise until it does before calling the tool.\n\n5. TRANSPARENCY: Show the user the slug before publishing\n (e.g. \"Publishing with slug: `my-slug`\") so they can correct it if\n needed. Do not block on confirmation — proceed immediately unless\n the user objects.\n","SUCCESS RESPONSE: On success the API returns `{ id, slug }`.\nConstruct the public URL as follows:\n- If `slug` is present and non-empty: {EPRESS_NODE_URL}/publications/{slug}\n- Otherwise fall back to: {EPRESS_NODE_URL}/publications/{id}\nShare this link with the user after a successful publish.\n","ERROR HANDLING: If the API returns HTTP 401, the token is invalid or\nexpired — prompt the user to regenerate it. If HTTP 403, the token lacks\nthe required `create:publications` scope.\n"] |