@felipeubidots/clickup-shortcut-migrator
v1.0.0
Published
Migrate tasks from ClickUp to Shortcut with full data preservation. Preserves descriptions, comments, subtasks, custom fields, and more.
Maintainers
Readme
ClickUp → Shortcut Task Migration Tool
A comprehensive task migration tool that transfers tasks from ClickUp to Shortcut while preserving all relevant data including descriptions, comments, subtasks, and custom fields.
Features
✅ Complete Data Migration
- Task names and descriptions (with inline images/videos)
- Story points (Sprint Points custom field)
- Status mapping (Open → Ready for Development, In Progress → In Development, Done → Done)
- Assignees with email/username mapping
- Tags → Labels (with auto-creation of missing labels)
- Comments with author attribution
- Subtasks as nested Shortcut stories
- External link back-reference for traceability
✅ Safety & Reliability
- Duplicate detection (checks if task already migrated)
- User ID mapping with fallback handling
- Error handling per task (failures don't stop batch migrations)
- Detailed reporting with migration status
✅ Flexible Batch Operations
- Migrate single tasks:
node migrate.js abc123 - Migrate multiple tasks:
node migrate.js abc123 def456 ghi789 - Automatic workflow state mapping
- Label deduplication and creation on-demand
Quick Start
Prerequisites
- Node.js v16+
- Access to both ClickUp and Shortcut workspaces via Claude Code MCP tools
Installation
cd /path/to/task-migrator
npm installBasic Usage
Migrate a single ClickUp task:
node migrate.js <clickup_task_id>Migrate multiple tasks:
node migrate.js task_id_1 task_id_2 task_id_3Example:
node migrate.js abc123def456 ghi789jkl012How It Works
Phase 0: Setup (automatic, one-time per session)
The tool automatically initializes the Shortcut environment:
- Fetches the default workflow and available states
- Loads all Shortcut users and builds an email/username → ID map
- Loads existing labels to avoid duplicates
📋 Phase 0: Initializing Shortcut environment...
→ Fetching default workflow...
✓ Workflow ID: 123456
✓ Available states: Ready for Development, In Development, Done
→ Fetching Shortcut users...
✓ 12 users loaded
→ Fetching Shortcut labels...
✓ 25 labels found
✅ Shortcut environment initializedPhase 1: Read from ClickUp (per task)
Fetches complete task data:
- Task name, description, status, assignees, tags
- Sprint Points custom field (if present)
- All attachments (images, videos, files)
- All comments with author info
- Subtasks
- Original task URL (for back-reference)
Phase 2: Transform Data
Converts ClickUp data to Shortcut format:
Description: Converts to Markdown with embedded image/video links
- Images:
 - Videos:
[▶ See video](url) - Files:
[📎 filename](url) - Migration footer:
---\n*Migrated from ClickUp*
- Images:
Status Mapping:
open→ "Ready for Development"in progress→ "In Development"done,closed→ "Done"
Estimate: Extracts "Sprint Points" custom field → story
estimateAssignees: Maps ClickUp assignees to Shortcut users by email/username
Tags → Labels:
- Reuses existing labels (case-insensitive)
- Creates missing labels automatically with random colors
Phase 3: Write to Shortcut (per task)
- Duplicate Check: Verifies task hasn't been migrated already (by external link)
- Create Story: Creates main story in Shortcut with all metadata
- Add External Link: Links back to original ClickUp task
- Migrate Comments: Adds all comments with
[ClickUp - Author]attribution - Migrate Subtasks: Creates subtasks as nested Shortcut stories and links them
Phase 4: Report
Generates a summary table showing:
- ClickUp ID
- Task name
- Shortcut story ID (if migrated)
- Status (✅ Migrated, ⚠️ Skipped, ❌ Failed)
Example output:
📊 MIGRATION REPORT
==============================================================================
| ClickUp ID | Name | Shortcut ID | Status |
|---|---|---|---|
| abc123 | Fix login bug | sc-4521 | ✅ Migrated |
| def456 | Update docs | sc-4522 | ✅ Migrated |
| ghi789 | Old task | — | ⚠️ Already exists |
📈 Summary:
• Total: 3
• ✅ Migrated: 2
• ⚠️ Skipped: 1
• ❌ Failed: 0Field Mapping Reference
| ClickUp | Shortcut | Notes |
|---------|----------|-------|
| name | name | Direct copy |
| description + attachments | description | Markdown formatted with embedded links |
| custom_fields (Sprint Points) | estimate | Parsed as integer for story points |
| status | workflow_state_id | Status mapping applied (see Phase 2) |
| assignees | owner_ids | Mapped by email/username |
| tags | labels | Reused or created as needed |
| comments | Story comments | Formatted as **[ClickUp - Author]:** text |
| subtasks | Nested stories | Created as subtasks via stories-add-subtask |
| url | External link | Added for back-reference |
Advanced Usage
Environment Variables
# Optional: Specify custom workflow (defaults to workspace default)
export SHORTCUT_WORKFLOW_ID=12345
# Optional: Specify team (defaults to workspace)
export SHORTCUT_TEAM_ID=abc-def-ghi
node migrate.js task_id_1 task_id_2Dry Run (Planned Feature)
node migrate.js task_id --dry-run
# Shows what would be migrated without actually creating storiesBatch Migration from File
Create tasks.txt:
abc123def456
ghi789jkl012
mno345pqr678Then:
node migrate.js $(cat tasks.txt)Error Handling
The tool is designed to be resilient:
- Per-task isolation: If one task fails, migration continues with others
- Graceful user mapping: If a ClickUp assignee can't be mapped, the story is created without that owner
- Label creation fallback: If label creation fails, the story is created without that label
- Comment/subtask failures: Individual comment/subtask failures don't stop story creation
Each result is reported in the final summary table with specific error messages.
Troubleshooting
"Story already migrated"
This means the tool detected an external link pointing to the ClickUp task. The story already exists in Shortcut. If you need to re-migrate, delete the Shortcut story first.
"Failed to map user: [email protected]"
The Shortcut workspace doesn't have a user with this email. Check:
- User exists in Shortcut workspace
- Email matches exactly in Shortcut
- Or add the user to Shortcut and re-run
"Failed to create label"
This usually happens if a label with the same name already exists but wasn't found (case sensitivity). The story is created without that label. You can manually add the label afterward.
Verification Checklist
After migration, verify each story:
- [ ] Story visible in Shortcut with correct name
- [ ] Description contains all content from ClickUp (text + embedded images/videos)
- [ ] Estimate matches Sprint Points (if set)
- [ ] Status matches ClickUp status (via workflow state)
- [ ] Assignees/owners correct
- [ ] Labels present
- [ ] External link points to original ClickUp task
- [ ] All comments migrated with author attribution
- [ ] Subtasks created and linked correctly
Technical Details
Architecture
migrate.js
├─ Phase 0: Initialize Shortcut Environment
│ ├─ mcp__shortcut__workflows-get-default
│ ├─ mcp__shortcut__users-list
│ └─ mcp__shortcut__labels-list
│
├─ Phase 1-3: For each task
│ ├─ Read ClickUp
│ │ ├─ mcp__clickup__clickup_get_task
│ │ └─ mcp__clickup__clickup_get_task_comments
│ │
│ ├─ Transform
│ │ ├─ markdownify description
│ │ ├─ map status
│ │ ├─ parse estimate
│ │ ├─ map users
│ │ └─ map/create labels
│ │
│ └─ Write Shortcut
│ ├─ Check for duplicates (mcp__shortcut__stories-get-by-external-link)
│ ├─ Create story (mcp__shortcut__stories-create)
│ ├─ Add external link (mcp__shortcut__stories-add-external-link)
│ ├─ Migrate comments (mcp__shortcut__stories-create-comment)
│ └─ Migrate subtasks (recursively)
│
└─ Phase 4: Generate ReportMCP Tools Used
ClickUp (Reading):
mcp__clickup__clickup_get_task- Get task with subtasksmcp__clickup__clickup_get_task_comments- Get all comments
Shortcut (Writing):
mcp__shortcut__workflows-get-default- Get available workflow statesmcp__shortcut__users-list- Get user ID mappingsmcp__shortcut__labels-list- Get existing labelsmcp__shortcut__stories-create- Create main storymcp__shortcut__stories-add-external-link- Add back-referencemcp__shortcut__stories-create-comment- Migrate commentsmcp__shortcut__stories-create-subtaskormcp__shortcut__stories-add-subtask- Link subtasksmcp__shortcut__labels-create- Create missing labelsmcp__shortcut__stories-get-by-external-link- Check for duplicates
Limitations
- Image/Video URLs: URLs remain as links; images aren't re-uploaded to Shortcut
- Custom Fields: Only "Sprint Points" is migrated. Other ClickUp custom fields don't have equivalents
- Time Tracking: ClickUp time entries aren't migrated (no equivalent in Shortcut)
- Change History: ClickUp activity history isn't preserved
- Permissions: Migrated stories inherit workspace defaults; ClickUp-specific permissions aren't replicated
- Attachments: Embedded as links in description; not re-hosted
Performance
Typical migration times (per task):
- Single task: ~2-5 seconds
- Task + 5 comments: ~3-7 seconds
- Task + 3 subtasks: ~8-15 seconds
- Batch of 10 tasks: ~30-60 seconds
Times depend on ClickUp/Shortcut API latency.
Support
For issues or feature requests:
- Check the Troubleshooting section above
- Review error messages in the final report
- Verify MCP tools are accessible:
/helpin Claude Code
License
MIT
