| name | hashnode |
| description | Manage Hashnode blog posts via GraphQL API. Create, update, list, and delete posts. Use when user wants to manage their Hashnode blog from OpenClaw. |
| homepage | https://hashnode.com |
| metadata | {"openclaw":{"emoji":"✍️","requires":{"env":["HASHNODE_TOKEN","HASHNODE_PUBLICATION_ID"]},"primaryEnv":"HASHNODE_TOKEN"}} |
Hashnode Blog Skill
Manage Hashnode blog via the GraphQL API at https://gql.hashnode.com/graphql.
Setup
Both vars are injected via systemd environment (no files, no secrets on disk):
Environment=HASHNODE_TOKEN=...
Environment=HASHNODE_PUBLICATION_ID=... # e.g. 624c1b702b09bb392ea5cc94
Core Functions
me
curl -s -X POST "https://gql.hashnode.com/graphql" \
-H "Authorization: Bearer ${HASHNODE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query":"{ me { username publications(first:1) { edges { node { id title } } } } }"}'
list_posts (publication posts)
curl -s -X POST "https://gql.hashnode.com/graphql" \
-H "Authorization: Bearer ${HASHNODE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query":"{ publication(id: \"'"${HASHNODE_PUBLICATION_ID}"'\") { title posts(first: 10) { edges { node { title slug views publishedAt tags { name } } } } } }"}'
create_post
TITLE="$1"
CONTENT_MARKDOWN="$2"
TAGS="${3:-[]}"
curl -s -X POST "https://gql.hashnode.com/graphql" \
-H "Authorization: Bearer ${HASHNODE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query":"mutation { createStory(input: {title: \"'"${TITLE}"'\", contentMarkdown: \"'"${CONTENT_MARKDOWN}"'\", tags: '"${TAGS}"', publicationId: \"'"${HASHNODE_PUBLICATION_ID}"'\", isDraft: false}) { id slug } }"}'
get_post
SLUG="$1"
curl -s -X POST "https://gql.hashnode.com/graphql" \
-H "Authorization: Bearer ${HASHNODE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query":"{ publication(id: \"'"${HASHNODE_PUBLICATION_ID}"'\") { post(slug: \"'"${SLUG}"'\") { id title contentMarkdown views publishedAt tags { name } } } }"}'
delete_post
POST_ID="$1"
curl -s -X POST "https://gql.hashnode.com/graphql" \
-H "Authorization: Bearer ${HASHNODE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query":"mutation { deleteStory(postId: \"'"${POST_ID}"'\") { success } }"}'
get_stats
curl -s -X POST "https://gql.hashnode.com/graphql" \
-H "Authorization: Bearer ${HASHNODE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query":"{ publication(id: \"'"${HASHNODE_PUBLICATION_ID}"'\") { title posts(first: 100) { edges { node { views } } } } }"}' | \
python3 -c "import json,sys; d=json.load(sys.stdin); posts=d['data']['publication']['posts']['edges']; total=sum(p['node']['views'] for p in posts); print(f\"Posts: {len(posts)}, Total views: {total}\")"
Workflow: Post from Markdown File
FILE="$1"
shift || true
TAGS="${*:-[]}"
TITLE=$(head -1 "$FILE" | sed 's/^# //')
CONTENT=$(sed '1d' "$FILE" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))")
curl -s -X POST "https://gql.hashnode.com/graphql" \
-H "Authorization: Bearer ${HASHNODE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query":"mutation { createStory(input: {title: '"${TITLE}"', contentMarkdown: '"${CONTENT}"', tags: '"${TAGS}"', publicationId: \"'"${HASHNODE_PUBLICATION_ID}"'\", isDraft: false}) { id slug } }"}'
Workflow: Cross-post from open-mushaf blog
create_post "Article Title Here" "$(cat /path/to/article.md)" '["quran","react","mcp"]'
Notes
HASHNODE_PUBLICATION_ID is the numeric publication ID (e.g. 624c1b702b09bb392ea5cc94)
- Hashnode blog title: Let's code (@adelpro)
- All mutations require
publicationId
- Posts are queried through
publication(id:).posts(first: N)
- Post
views is a field on the Post type (not viewsCount)