| name | media-publish |
| description | Publish content to all configured platforms. Reads the content manifest,
validates files, and invokes each platform's publish.sh with credential
isolation. Supports --dry-run. Handles partial failures gracefully.
Works independently — you can write markdown by hand and just use this skill.
|
| allowed-tools | ["Bash","Read","Write","Edit","AskUserQuestion","Grep","Glob"] |
/media-publish — Multi-Platform Publishing
Publish your content to all configured platforms in one go.
Prerequisites
Before starting, read these shared library files:
- Read
lib/adapter-discovery.md for adapter invocation patterns
- Read
lib/manifest-ops.md for manifest format and validation
Step 1: Locate the Post
If the user specifies a post path, use it. Otherwise, find the most recent post:
ls -dt content/posts/*/ 2>/dev/null | head -1
Verify the post directory contains:
source.md (canonical content)
manifest.yaml (content manifest)
variants/ directory with at least one variant file
If any are missing, report what's missing and stop.
Step 2: Pre-Publish Validation
Read manifest.yaml and validate:
-
Source exists and is non-empty:
[ -s "<post_dir>/source.md" ] || echo "ERROR: source.md is empty or missing"
-
Each variant file exists and is non-empty:
For each variant in the manifest, check the file exists:
[ -s "<post_dir>/<variant_file>" ] || echo "ERROR: <variant_file> missing"
-
Asset files exist (if referenced in manifest):
[ -f "<post_dir>/<asset>" ] || echo "WARN: asset <asset> missing"
-
Filter publishable variants:
Only attempt platforms with status: draft, pending, or failed.
Skip: published, skipped.
If no platforms are publishable, tell the user: "All platforms are already published or skipped. Nothing to do."
Step 3: Check Platform Configuration
For each publishable platform, verify:
- The adapter directory exists:
adapters/<name>/
- The adapter's
publish.sh is executable
- The required env var is set in
.env (for API-based adapters)
- For git-push adapters, the configured repo path exists
Report any missing configuration and offer to run /media-setup.
Step 4: Confirm with User
Show what will be published:
Ready to publish "<title>":
[PUBLISH] Dev.to — variants/devto.md (draft)
[PUBLISH] Hashnode — variants/hashnode.md (draft)
[SKIP] GitHub Pages — already published
Use AskUserQuestion to confirm. Options:
- A) Publish all
- B) Dry run first (preview without publishing)
- C) Select specific platforms
- D) Cancel
Step 5: Publish
For each platform, invoke the adapter's publish.sh with credential isolation.
Read the adapter's auth_env_var from adapter.yaml, then invoke:
AUTH_VAR=$(python3 -c "import yaml; print(yaml.safe_load(open('adapters/<name>/adapter.yaml')).get('auth_env_var', ''))")
AUTH_VAL=$(grep "^${AUTH_VAR}=" .env | cut -d= -f2-)
env -i PATH="$PATH" HOME="$HOME" \
"${AUTH_VAR}=${AUTH_VAL}" \
./adapters/<name>/publish.sh "<post_dir>/variants/<name>.md" "<post_dir>/assets" [--dry-run]
For git-push adapters (no auth_env_var):
env -i PATH="$PATH" HOME="$HOME" GIT_DIR="$(git rev-parse --git-dir)" \
./adapters/<name>/publish.sh "<post_dir>/variants/<name>.md" "<post_dir>/assets" [--dry-run]
Step 6: Update Manifest
After each platform publish attempt, update the manifest atomically:
On success (exit 0):
Parse the JSON stdout to get url and id. Update the variant:
status: published
published_at: <current ISO timestamp>
url: <url from stdout>
id: <id from stdout>
error: null
On failure (exit 1-4):
status: failed
error: "<stderr output>"
Use the atomic write pattern from lib/manifest-ops.md:
- Write to
.manifest.yaml.tmp
- Validate YAML
- Backup original, then
mv temp to manifest.yaml
Step 7: Report Results
After all platforms are attempted, report:
Published "<title>":
[OK] Dev.to → https://dev.to/user/post-slug
[OK] Hashnode → https://hashnode.com/post/xyz
[FAIL] GitHub Pages — git push failed (exit 1)
2/3 platforms succeeded. Run /media-publish again to retry failed platforms.
If all succeeded:
All platforms published successfully!
If --dry-run was used:
Dry run complete. No content was actually published.
Run /media-publish again without --dry-run to publish for real.