Loading...
Loading...
Publish social media content to connected platforms. Use when the user wants to post to social media, schedule a post, publish content, or share something on Twitter, Instagram, LinkedIn, Threads, Bluesky, YouTube, Pinterest, or TikTok.
npx skill4agent add mrpaulscrivens/nosy-pandas-skills panda-publish~/.pandasapi_url=https://nosypandas.com/api
api_key=your-key-here
media_folder=~/social-media~/.pandasmedia_folder~/social-media/# Read config values (use these instead of env vars in all curl commands)
PANDAS_API_URL="https://nosypandas.com/api"
PANDAS_API_KEY=$(grep '^api_key=' ~/.pandas 2>/dev/null | cut -d= -f2-)
PANDAS_MEDIA_FOLDER=$(grep '^media_folder=' ~/.pandas 2>/dev/null | cut -d= -f2-)
PANDAS_MEDIA_FOLDER="${PANDAS_MEDIA_FOLDER:-$HOME/social-media}"| Command | Description |
|---|---|
| Publish | Create and publish a post to one or more platforms |
| History | View recent posts and their statuses |
| Detail | Check a specific post's full details |
| Retry | Retry a failed post |
| Delete | Delete a scheduled or failed post |
grep -q "nosypandas.com" ~/.claude/settings.json 2>/dev/null && echo "CONFIGURED" || echo "NOT_CONFIGURED"CONFIGUREDNOT_CONFIGUREDQuick setup: This skill runs bash commands to call the Nosy Pandas API, read your config, scan for media files, and move them after posting. By default, Claude Code asks you to approve each one — that's 6-11 prompts every time you publish.I can add permission patterns to your Claude Code settings () so these commands auto-approve. The patterns are scoped narrowly:~/.claude/settings.json
- API calls only to
nosypandas.com- Config reads/writes only to
~/.pandas- File operations only in your
foldersocial-media/Want me to set this up?
~/.claude/settings.jsonpermissions.allow"Bash(cat > ~/.pandas *)",
"Bash(chmod 600 ~/.pandas)",
"Bash(grep * ~/.pandas *)",
"Bash(find * social-media *)",
"Bash(curl * https://nosypandas.com/*)",
"Bash(sleep *)",
"Bash(mkdir -p * social-media/*)",
"Bash(mv * social-media/*)"~/.pandasapi_keyapi_key~/.pandascat > ~/.pandas << 'EOF'
api_url=https://nosypandas.com/api
api_key=the-pasted-key
media_folder=~/social-media
EOF
chmod 600 ~/.pandas~/.pandasPANDAS_API_KEY=$(grep '^api_key=' ~/.pandas 2>/dev/null | cut -d= -f2-) && \
curl -s "https://nosypandas.com/api/accounts" \
-H "Authorization: Bearer $PANDAS_API_KEY" \
-H "Accept: application/json"{
"accounts": [
{ "id": 1, "platform": "twitter", "account_name": "@myhandle" },
{ "id": 2, "platform": "bluesky", "account_name": "@me.bsky.social" }
]
}Which platforms do you want to post to?
- Twitter/X (@myhandle)
- Bluesky (@me.bsky.social)
- LinkedIn (My Profile)
findMEDIA_DIR="${PANDAS_MEDIA_FOLDER:-$HOME/social-media}"
find "$MEDIA_DIR" -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.mp4" -o -iname "*.mov" -o -iname "*.avi" -o -iname "*.webm" \) 2>/dev/nullnoMix: trueContent: [first 100 chars...]
Media: [count] files ([list filenames])
Platforms: Twitter, Bluesky
Timing: Publish now
Title: [if YouTube]
Link URL: [if Pinterest]
Warnings:
- Twitter: Content will be split into a thread (exceeds 280 chars)PANDAS_API_KEY=$(grep '^api_key=' ~/.pandas 2>/dev/null | cut -d= -f2-) && \
PANDAS_API_URL="https://nosypandas.com/api" && \
TOKENS="" && \
for FILE in /path/to/file1.jpg /path/to/file2.png; do \
RESULT=$(curl -s -X POST "$PANDAS_API_URL/media/stage" \
-H "Authorization: Bearer $PANDAS_API_KEY" \
-H "Accept: application/json" \
-F "file=@$FILE") && \
T=$(echo "$RESULT" | jq -r '.token') && \
TOKENS="${TOKENS:+$TOKENS,}\"$T\""; \
done && \
POST_RESULT=$(curl -s -X POST "$PANDAS_API_URL/posts" \
-H "Authorization: Bearer $PANDAS_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d "{
\"content\": \"POST_CONTENT\",
\"platforms\": [ACCOUNT_ID_1, ACCOUNT_ID_2],
\"publish_now\": true,
\"media_tokens\": [$TOKENS]
}") && \
echo "$POST_RESULT" && \
POST_ID=$(echo "$POST_RESULT" | jq -r '.post.id') && \
HAS_PENDING=$(echo "$POST_RESULT" | jq '[.post.platforms[] | select(.status == "pending" or .status == "publishing" or (.status == "failed" and (.error == null or .error == "")))] | length') && \
if [ "$HAS_PENDING" -gt 0 ]; then \
sleep 5 && \
curl -s "$PANDAS_API_URL/posts/$POST_ID" \
-H "Authorization: Bearer $PANDAS_API_KEY" \
-H "Accept: application/json"; \
fiPANDAS_API_KEY=$(grep '^api_key=' ~/.pandas 2>/dev/null | cut -d= -f2-) && \
PANDAS_API_URL="https://nosypandas.com/api" && \
POST_RESULT=$(curl -s -X POST "$PANDAS_API_URL/posts" \
-H "Authorization: Bearer $PANDAS_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"content": "POST_CONTENT",
"platforms": [ACCOUNT_ID_1, ACCOUNT_ID_2],
"publish_now": true
}') && \
echo "$POST_RESULT" && \
POST_ID=$(echo "$POST_RESULT" | jq -r '.post.id') && \
HAS_PENDING=$(echo "$POST_RESULT" | jq '[.post.platforms[] | select(.status == "pending" or .status == "publishing" or (.status == "failed" and (.error == null or .error == "")))] | length') && \
if [ "$HAS_PENDING" -gt 0 ]; then \
sleep 5 && \
curl -s "$PANDAS_API_URL/posts/$POST_ID" \
-H "Authorization: Bearer $PANDAS_API_KEY" \
-H "Accept: application/json"; \
fi"title": "VIDEO_TITLE""link_url": "https://example.com""scheduled_at": "2026-03-16T09:00:00Z"publish_nowfalse"timezone": "America/New_York"{
"token": "stg_abc123...",
"original_filename": "photo.jpg",
"type": "image",
"expires_at": "2026-03-16T14:00:00+00:00"
}{
"post": {
"id": 42,
"content": "Hello world!",
"status": "published",
"platforms": [
{ "platform": "twitter", "status": "published", "url": "https://x.com/..." },
{ "platform": "bluesky", "status": "published", "url": "https://bsky.app/..." }
]
}
}pendingpublishingfailedposted/MEDIA_DIR="${PANDAS_MEDIA_FOLDER:-$HOME/social-media}" && \
mkdir -p "$MEDIA_DIR/posted/" && \
mv "$MEDIA_DIR/file1.jpg" "$MEDIA_DIR/file2.png" "$MEDIA_DIR/posted/"mvcurl -s "$PANDAS_API_URL/posts" \
-H "Authorization: Bearer $PANDAS_API_KEY" \
-H "Accept: application/json"curl -s "$PANDAS_API_URL/posts/POST_ID" \
-H "Authorization: Bearer $PANDAS_API_KEY" \
-H "Accept: application/json"{
"post": {
"id": 42,
"content": "Hello world!",
"title": null,
"status": "published",
"scheduled_at": null,
"created_at": "2026-03-15T12:00:00Z",
"platforms": [
{ "platform": "twitter", "status": "published", "url": "https://x.com/...", "error": null }
],
"media": [
{ "url": "https://cdn.example.com/file.jpg", "type": "image", "filename": "photo.jpg" }
]
}
}curl -s -X POST "$PANDAS_API_URL/posts/POST_ID/retry" \
-H "Authorization: Bearer $PANDAS_API_KEY" \
-H "Accept: application/json"{
"post": {
"id": 42,
"status": "pending"
}
}failedscheduledfailedscheduledfailedAre you sure you want to delete this post? Content: [first 100 chars...] Status: scheduled Platforms: Twitter, Bluesky
curl -s -X DELETE "$PANDAS_API_URL/posts/POST_ID" \
-H "Authorization: Bearer $PANDAS_API_KEY" \
-H "Accept: application/json"{
"message": "Post deleted."
}| Platform | Max Content | Threading | Requires Media | Requires Video | Max Images | Max Videos | No Mix |
|---|---|---|---|---|---|---|---|
| Twitter/X | 280 chars | Yes | No | No | 4 | 1 | Yes |
| Bluesky | 300 chars | Yes | No | No | 4 | 1 | No |
| Threads | 500 chars | Yes | No | No | 10 | 1 | No |
| None | No | Yes | No | 10 | 1 | No | |
| 3000 chars | No | No | No | 20 | 1 | No | |
| YouTube | None | No | Yes | Yes | 0 | 1 | No |
| None | No | Yes | No | 1 | 1 | Yes | |
| TikTok | None | No | Yes | Yes | 35 | 1 | Yes |
titlelink_url| Status | Meaning | Recovery |
|---|---|---|
| 401 | Invalid API key | Check |
| 403 | Subscription required | Subscribe at the dashboard |
| 404 | Post not found or not retryable | Verify the post ID and that its status is |
| 422 | Validation error | Show the specific error messages from the response body and help the user fix them |
| 500 | Server error | Try again later |