
Clickup Comment Style
- Updated August 3, 2026
- TaricaTarica/clickup-rich-comments
clickup-comment-style is a Claude Code skill in the AI & Agent Building category. Upgrades ClickUp MCP comments from plain text to native rich formatting via a PostToolUse hook
Key points
- clickup-comment-style
- AI & Agent Building
- AI-coding skill
Clickup Comment Style by the numbers
- Data as of Aug 4, 2026 (Skillselion catalog sync)
/plugin marketplace add TaricaTarica/clickup-rich-comments/plugin install clickup-comment-style@clickup-rich-commentsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Last updated | August 3, 2026 |
|---|---|
| Repository | TaricaTarica/clickup-rich-comments ↗ |
What it does
Upgrades ClickUp MCP comments from plain text to native rich formatting via a PostToolUse hook
README.md
clickup-rich-comments
Your ClickUp MCP posts ## broken comments. This fixes them.
Auto-upgrades every agent comment to native rich text — headers, bold, lists, code.
Works with Claude Code and Cursor.
This repo ships a post-hook plus an optional skill/plugin named clickup-comment-style (the install id in /plugin install ...).

The problem
Your agent writes a nicely formatted comment:
## Deploy steps
1. Run `migrate`
2. Restart the worker
ClickUp shows your team this — raw, unrendered:
## Deploy steps
1. Run `migrate`
2. Restart the worker
Same text. The ## and 1. never render: the MCP only writes plain comment_text, and ClickUp doesn't parse Markdown there.
What renders / what doesn't
In comment_text |
Renders in ClickUp UI? |
|---|---|
Inline code `identifier` |
Yes |
Raw URL https://... |
Yes (auto-link) |
**bold**, *italic*, ~~strike~~ |
No — literal |
[text](url) |
No — literal |
## headers, - bullets, 1. lists |
No — literal |
> blockquote, ``` fences |
No — literal |
Quickstart
git clone https://github.com/TaricaTarica/clickup-rich-comments.git
cd clickup-rich-comments
./install.sh
The installer checks prerequisites, guides you through CLICKUP_API_TOKEN setup, and configures hooks for Cursor and Claude Code automatically. Takes about two minutes.
Requirements: python3 only (hooks parse the payload in Python — no jq, no pip packages).
Install
⚠️ Pick one install method. If you install a plugin, don't also run
./install.sh(or merge hooks manually) — you'd run the upgrade twice per comment.
Install as a Cursor plugin — recommended for Cursor users
Install the hook and style guide in one step via the Cursor plugin marketplace:
/plugin marketplace add TaricaTarica/clickup-rich-comments
Then in a Cursor session:
/plugin install clickup-comment-style@clickup-rich-comments
Or use /add-plugin and search for clickup-comment-style.
After install, restart Cursor or run Developer: Reload Window. Hook changes are not hot-reloaded; SKILL.md and rule updates may require a reload.
Requirements: python3 and CLICKUP_API_TOKEN (env var or ~/.clickup_rich_comments.env) (see token setup). The plugin installs the mechanism only — it never embeds or ships credentials.
What you get: an afterMCPExecution hook that upgrades clickup_create_task_comment output to native rich text, plus the comment style guide skill and rule.
ClickUp MCP: must already be configured separately. This plugin does not declare mcp.json — adding ClickUp MCP again would conflict with your existing setup.
Marketplace source: add the marketplace via Git shorthand (owner/repo) or a git URL. Do not add it via a direct URL to marketplace.json — relative plugin paths (./plugin-cursor) only resolve when the marketplace is fetched from a git repository.
Test locally before publishing:
ln -sf "$(pwd)/plugin-cursor" ~/.cursor/plugins/local/clickup-comment-style
# Developer: Reload Window → verify rules, skills, and hooks in Settings
If symlinks are missing after clone (common on Windows), run ./scripts/sync-plugins.sh.
Install as a Claude Code plugin — recommended for Claude Code users
For Claude Code, install the hook and style guide in one step via the plugin marketplace:
claude plugin marketplace add TaricaTarica/clickup-rich-comments
Then in a Claude Code session:
/plugin install clickup-comment-style@clickup-rich-comments
After install, restart the session or run /reload-plugins. Hook changes are not hot-reloaded; SKILL.md updates are.
Requirements: python3 and CLICKUP_API_TOKEN (env var or ~/.clickup_rich_comments.env) (see token setup). The plugin installs the mechanism only — it never embeds or ships credentials.
What you get: a PostToolUse hook that upgrades clickup_create_task_comment output to native rich text, plus the comment style guide skill.
ClickUp MCP: must already be configured separately (OAuth). This plugin does not declare .mcp.json — adding ClickUp MCP again would conflict with your existing setup.
Marketplace source: add the marketplace via Git shorthand (owner/repo) or a git URL. Do not add it via a direct URL to marketplace.json — relative plugin paths (./plugin) only resolve when the marketplace is fetched from a git repository.
Manual / install.sh — universal fallback
./install.sh is the universal fallback when you prefer not to use a marketplace plugin, or when you want hooks in both Cursor and Claude Code from one script.
Cursor (manual)
Merge into ~/.cursor/hooks.json (see config-examples/cursor-hooks.json):
{
"version": 1,
"hooks": {
"afterMCPExecution": [
{
"command": "/ABSOLUTE/PATH/to/clickup-comment-style/hooks/cursor.sh"
}
]
}
}
chmod +x hooks/*.sh scripts/*.sh
Restart Cursor or save hooks.json to reload hooks.
Claude Code (manual)
./install.sh merges the hook into ~/.claude/settings.json automatically (with confirmation). Matcher default: regex mcp__.*__clickup_create(_task)?_comment — works across MCP server naming (e.g. mcp__claude_ai_ClickUp__clickup_create_comment) without manual configuration.
Manual merge (see config-examples/claude-settings.json):
python3 scripts/merge_claude_hooks.py ~/.claude/settings.json "$(pwd)/hooks/claude-code.sh"
Or merge JSON by hand:
{
"hooks": {
"PostToolUse": [
{
"matcher": "mcp__.*__clickup_create(_task)?_comment",
"hooks": [
{
"type": "command",
"command": "/ABSOLUTE/PATH/to/clickup-comment-style/hooks/claude-code.sh",
"async": true
}
]
}
]
}
}
Restart your Claude Code session after install.
How it works
Agent calls clickup_create_task_comment (MCP)
→ comment_text posted (partial render: backticks + URLs only)
Post-hook fires automatically (claude-code.sh / cursor.sh)
→ clickup_rich_comment.py converts text → ClickUp ops
→ PUT /api/v2/comment/{comment_id} with {"comment": [...]}
ClickUp UI shows full rich text (headers, bold, lists, code blocks)
The MCP OAuth token is not accessible to local hooks. The upgrade uses a Personal API Token (pk_...) via CLICKUP_API_TOKEN.
Why this exists
The MCP only writes comment_text — a plain string with minimal inline rendering. Native formatting (headers, lists, code blocks) lives in the separate comment field as a Quill-delta ops array, which the MCP does not expose. This hook reads comment_text after the MCP call and rewrites the comment via the documented PUT endpoint. See ClickUp comment formatting. Screenshots are rendered inline as type:image ops built from REST attachment metadata.
Reference
Claude Code vs Cursor
| Claude Code plugin | Cursor plugin | |
|---|---|---|
| Hook event | PostToolUse |
afterMCPExecution |
| Config file | plugin/hooks/hooks.json or ~/.claude/settings.json |
plugin-cursor/hooks/hooks.json or ~/.cursor/hooks.json |
| Matcher | Regex in config: mcp__.*__clickup_create(_task)?_comment |
None — cursor.sh filters tool_name internally |
tool_name |
mcp__<server>__clickup_create_task_comment |
clickup_create_task_comment (no MCP prefix) |
tool_input |
JSON object | JSON string — both parsed in Python (--hook) |
| Comment ID | tool_response.comment_id |
tool_output.comment_id |
| Async | Supported ("async": true) |
Not documented (runs synchronously) |
Security
Hooks run without a sandbox — they execute with your user permissions, the same as any local shell script Cursor or Claude Code invokes.
What the hook does:
- Reads the MCP tool payload from stdin (tool name, comment text, comment ID).
- If the tool is
clickup_create_task_commentand the call succeeded, callsclickup_rich_comment.py. - The Python script sends one
PUTrequest tohttps://api.clickup.com/api/v2/comment/{id}usingCLICKUP_API_TOKENfrom your environment. - On any error (missing token, API failure), the hook logs to stderr and exits 0 — your agent session is never blocked.
The repo contains no credentials. Review hooks/cursor.sh, hooks/claude-code.sh, and hooks/clickup_rich_comment.py before installing.
Step-by-step: get your CLICKUP_API_TOKEN
The installer handles this interactively, but here is the full manual path:
1. Open ClickUp Settings
Click your avatar (bottom-left) → Settings.
2. Copy your Personal API Token
Go to the Apps tab. Under API Token, click Generate (or Copy if you already have one).
The token starts with pk_.
3. Export for the current session
export CLICKUP_API_TOKEN='pk_...'
4. Persist across sessions
Add to your shell profile so every terminal (and IDE hook process) has the token:
zsh (~/.zshrc):
echo 'export CLICKUP_API_TOKEN='"'"'pk_...'"'" >> ~/.zshrc
source ~/.zshrc
bash (~/.bashrc):
echo 'export CLICKUP_API_TOKEN='"'"'pk_...'"'" >> ~/.bashrc
source ~/.bashrc
5. Verify
echo $CLICKUP_API_TOKEN
# should print: pk_...
Never commit your token. Use environment variables or your shell profile — not a
.envfile in a repo.
Verify it works
Test the converter directly
export CLICKUP_API_TOKEN='pk_...'
python3 hooks/clickup_rich_comment.py '<existing_comment_id>' <<'EOF'
## Test Section
- `foo()` — does something
ref: https://example.com/docs
**IMPORTANTE**
One config record (`customrecord_acme_config`) per account.
EOF
Open the task in ClickUp — the comment should show a header, bullet list, inline code, and bold text.
End-to-end via agent
- Ask your agent to post a comment on a ClickUp task via MCP.
- Open the task in ClickUp.
- Confirm headers, lists, and code blocks render natively.
If formatting is still plain, check the Hooks output channel in Cursor or hook stderr logs.
Optional: agent style guide — teaches agents a comment dialect that converts cleanly with the hook
The hooks work with any comment_text the agent writes. For consistently well-structured technical comments, install the optional style guide:
| Environment | Install |
|---|---|
| Cursor (plugin) | Included when you install the Cursor plugin |
| Claude Code (plugin) | Included when you install the Claude Code plugin |
| Claude Code (manual) | cp SKILL.md ~/.claude/skills/clickup-comment-style/SKILL.md |
| Claude.ai | Upload folder as personal skill (Settings → Capabilities → Skills) |
| Cursor (project) | cp .cursor/rules/clickup-comment-style.mdc your-project/.cursor/rules/ |
| Cursor (user) | cp .cursor/rules/clickup-comment-style.mdc ~/.cursor/rules/ |
The style guide teaches a plain-text dialect (bullets •, dividers, backticks, raw URLs) that reads well without the hook and converts cleanly with it. See SKILL.md.
Troubleshooting
| Symptom | Fix |
|---|---|
python3 not found in hook logs |
Install Python 3 and ensure it is on PATH |
CLICKUP_API_TOKEN is not set |
Run export CLICKUP_API_TOKEN='pk_...' or re-run ./install.sh |
| Token set but hook still skips | IDE hooks may not inherit your shell profile. Add export to ~/.zshrc and restart the IDE |
| Comment still plain after hook | Check Hooks output channel; verify comment_id in hook payload |
| Claude Code hook not firing | Re-run python3 scripts/merge_claude_hooks.py ~/.claude/settings.json "$(pwd)/hooks/claude-code.sh" and restart session |
| Cursor adds latency | Hooks run synchronously; large comments may slow the agent turn slightly |
| Plugin symlinks missing | Run ./scripts/sync-plugins.sh after clone |
Discover the MCP tool name (optional)
The default regex matcher mcp__.*__clickup_create(_task)?_comment usually works without discovery. If you need an exact matcher:
python3 scripts/merge_claude_hooks.py --suggest-matcher— hints from local MCP config or debug log.- Or temporarily point Cursor
afterMCPExecutiontoscripts/detect-mcp-tool-name.sh, post a test comment, read~/.cursor/clickup-mcp-debug.log.
Repository layout
├── .claude-plugin/
│ └── marketplace.json # Claude Code marketplace catalog
├── .cursor-plugin/
│ └── marketplace.json # Cursor marketplace catalog
├── plugin/ # installable Claude Code plugin
│ ├── .claude-plugin/plugin.json
│ ├── hooks/hooks.json
│ ├── scripts/claude-code.sh
│ ├── scripts/clickup_rich_comment.py → symlink to hooks/
│ └── SKILL.md → symlink to repo root
├── plugin-cursor/ # installable Cursor plugin
│ ├── .cursor-plugin/plugin.json
│ ├── hooks/hooks.json
│ ├── scripts/cursor.sh → symlink to hooks/
│ ├── scripts/clickup_rich_comment.py → symlink to hooks/
│ ├── skills/clickup-comment-style/SKILL.md → symlink to repo root
│ └── rules/clickup-comment-style.mdc → symlink to ../../.cursor/rules/
├── install.sh # interactive setup (universal fallback)
├── README.md
├── LICENSE
├── .env.example
├── assets/
│ └── README.md # demo GIF recording spec
├── hooks/
│ ├── clickup_rich_comment.py # text → ops + PUT (source of truth)
│ ├── claude-code.sh
│ └── cursor.sh
├── config-examples/
│ ├── claude-settings.json
│ └── cursor-hooks.json
├── scripts/
│ ├── merge_claude_hooks.py
│ ├── detect-mcp-tool-name.sh
│ └── sync-plugins.sh # provision plugin symlinks
├── SKILL.md # optional agent style guide
├── .cursor/rules/clickup-comment-style.mdc
└── CONTRIBUTING.md
Limitations
- Preprocessor does not cover every edge case — see CONTRIBUTING.md.
- Inline
@mentionsare not converted (use MCPassigneeparameter). PUTwithcommentops is documented in comment formatting but not fully in the public OpenAPI spec.- Cursor hooks run synchronously.
- Re-running the hook overwrites the comment with ops derived from
comment_text(idempotent).
Contributing
See CONTRIBUTING.md.