Markdown Task File to ClickUp SOP
1. Purpose & Scope
Convert a task markdown file living in Client_Delivery/<client>/work-in-progress/YYYY-MM/ into a ClickUp task in that client's active-work list under the Client Delivery space.
In scope:
- Task files authored per the Google Drive Organization Standard naming pattern
YYYY-MM-task-[assignee]-[description].md - One-task-per-file creation and subsequent updates
Out of scope:
- SC-internal operations tasks -- use the SC Operations space per ClickUp SC Operations Space Setup SOP
- Bulk/batch conversion of an entire monthly folder -- reserved for the deferred symphony-flow workflow (Section 7)
2. Prerequisites
- Client has
ClickUp List IDpopulated in their client profile at09-clients/<client-slug>/<client-slug>-client-profile.md. If marked*(TBD)*, populate it before proceeding (see Section 7). - Task markdown file exists with YAML frontmatter containing at minimum
title,assignee,priority,status. - ClickUp MCP access (for interactive runs) OR
CLICKUP_API_KEYenv var (for symphony-flow runs).
3. Field Mapping
| ClickUp field | Source in markdown | Conversion rule |
|---|---|---|
list_id | Client profile ClickUp List ID | Copy literally |
name | # H1 of markdown body | Prefer H1 over frontmatter title; H1 is the user-visible task title |
markdown_description | Full body (from first ## Section onwards) | Append a footer: **Source file:** <absolute path> and **Source call/context:** <frontmatter.source> |
priority | priority frontmatter | Map: urgent -> urgent, high -> high, medium/normal -> normal, low -> low. Uses string values (not 1-4 integer) |
assignees | assignee frontmatter | Pass as array. Resolve via clickup_resolve_assignees. For the authenticated user, "me" works; named users may need email. |
status | status frontmatter | Map: open -> omit (ClickUp default TODO); in_progress -> IN PROGRESS; blocked -> BLOCKED; review -> REVIEW; complete -> COMPLETE. See SC Task Data Standard for the full status model. |
due_date | due_date frontmatter (if present) | Format YYYY-MM-DD |
tags | Derived: <client-slug> plus any domain tags implied by content | Tags must pre-exist in the space -- see Section 5 |
3a. Multi-doc handoffs -- doc precedence
When a task is supported by more than one document in the same work-in-progress/YYYY-MM/ folder (e.g., a build spec, a copy doc, and a strategy/brief doc), the contractor or assignee may not know which one is authoritative. Disagreements between docs default to:
spec > copy > strategy/brief
- Spec (build spec, technical spec, layout/block-mapping doc) is authoritative for how the work is done. If spec says "no custom code", and copy says "add a custom carousel", the spec wins -- copy must be adapted.
- Copy (the actual text/words to be used) is authoritative for what content goes where, within constraints set by the spec.
- Strategy / brief (engagement brief, project plan, strategy doc) is authoritative for why the work matters and what success looks like -- but it is the lowest-precedence source for execution details. Use it to resolve ambiguity, not to overrule the spec.
When creating the ClickUp task description for a multi-doc handoff, link to all supporting docs and explicitly state which is the spec. Example:
**Supporting docs (in precedence order):**
- Spec: <drive-url-of-block-mapping-doc>
- Copy: <drive-url-of-copy-doc>
- Strategy: <drive-url-of-engagement-brief>
**Spec wins.** If copy disagrees with spec, escalate before implementing.
This convention was added after the rotary-sports build (2026-05) where a contractor read the copy doc without seeing the spec and proposed custom code that the spec had explicitly forbidden.
3b. Thin-ticket archetype
A well-formed ticket is a pointer, not a copy of the spec. It should fit on one ClickUp screen (~1,200 characters / ~200 words) and contain only what the assignee needs that does NOT already live in a referenced doc.
Canonical skeleton — see ClickUp Thin Ticket Template:
## Summary
<one or two sentences — what is being done and why>
## Acceptance Criteria
- [ ] <verifiable bullet 1, maps to a phase / step of the linked SOP>
- [ ] <verifiable bullet 2>
- [ ] <up to ~6 bullets>
- [ ] Evidence: <screenshot / URL / log link the assignee will attach on completion — see [validation-evidence-rule](/reference/standards/sc-contractor-task-quality-pre-work-standard.md#validation-evidence-rule)>
## Reference docs
- Playbook: <SOP link — team.symphonycore.com URL preferred; Drive PDF fallback only if the doc hasn't published to the wiki yet>
- Validation: <checklist link, if applicable>
- Client context: <client profile PDF link in Drive — client-specific docs are NOT on the wiki>
## Inline values (only when not in any doc)
- <per-task one-off — invoice number, specific URL, decision input>
---
**Source:** <markdown task-file path or URL>
Target size when populated: 600-1,000 characters. If a draft is heading past 1,500, stop and ask: "Which paragraph belongs in the SOP I'm linking to?" Move it there; link to it; keep going.
4. Content hygiene checks (mandatory pre-flight)
Run these checks on the fully-composed name and markdown_description before calling clickup_create_task or clickup_update_task. The assignee reads the task in ClickUp — anything that doesn't work in that context is a defect.
-
No local filesystem paths. Scan the description for
C:\,H:\, `[LOCAL_PATH_REMOVED]). Get it by opening the file in Drive and clicking Share → Copy link.- If no shareable URL exists: inline the content the assignee actually needs (e.g., paste the color hex, the short SOP steps, the snippet of text) and drop the path entirely.
- Narrow exception: keep the local path in a clearly-labeled
Source:footer for provenance only, when it duplicates information that is already actionable elsewhere in the task.
-
No unverified URLs. For every non-Google, non-GHL URL in the description, confirm the page exists before pasting.
- Default: link to
team.symphonycore.com(the live internal wiki, served via Docusaurus + Cloudflare Access). It is the canonical reference surface for SOPs, standards, checklists, and templates. URL pattern: strip the leading numeric prefix from the repo path and drop.md. Examples:04-operations/sops/<name>.md→https://team.symphonycore.com/operations/sops/<name>;08-reference/standards/<name>.md→https://team.symphonycore.com/reference/standards/<name>;06-team-training/platform-training/<name>.md→https://team.symphonycore.com/team-training/platform-training/<name>. - Publishing pipeline can stall. If a recently-added doc isn't yet on the wiki, the team URL will 404 until the next publish cycle. Acceptable fallbacks: (a) link to the Drive PDF in
My Drive/symphony-core-documents-storage/...if one exists; (b) inline the smallest unit that lets the assignee execute the next step. A ticket is a pointer, not a copy. - GitHub blob URLs are NOT acceptable in tickets. They require repo access (contractors don't have it) and break the abstraction the wiki provides. Use them only as a private note to yourself, never in a description an assignee will read.
- Client-specific content (under
09-clients/<slug>/in the repo) is NOT published to the wiki per the client isolation rule. Reference it by name in the ticket, or link to the corresponding Drive PDF inClient_Delivery/<slug>/client-reference/if one exists.
- Default: link to
-
Assignee can execute without leaving ClickUp (or with only known-good links). After composing, re-read the description as the assignee: is every instruction actionable? Every link clickable? Every referenced value present?
-
Task title is the H1, not the frontmatter
title. The frontmatter title is often a filename-friendly slug; the H1 is the sentence form a human will read in the list view. Use the H1.
These checks apply identically to creation (§5) and updates (§6).
4.5. Anti-patterns (do NOT inline these)
The 2026-05-15 audit of 86ahg97mk found ~7,000 characters of inlined content that duplicated source-of-truth docs. These are the patterns to refuse:
- Full validation checklists. Link to the checklist (e.g.,
wordpress-post-go-live-validation-checklist.md) — never paste the 30+ checkbox lines into the description. - Attendees / contact tables. Use the client profile PDF link. One source of truth per client; updated once, every future ticket inherits.
- Rollback / escalation procedures that already live in the referenced SOP. Decision trees belong in SOPs; tickets surface state and acceptance criteria.
- Step-by-step instructions copied from a linked SOP. The whole point of linking the SOP is so the assignee opens it. If you copy the steps in, the link is decoration.
- Source-of-truth tables (DNS records, GHL location IDs, brand colors, plan IDs, NAICS codes). These live in client profile, SOPs, or PDFs. Reference them by where they live.
- Multi-paragraph background context that belongs in the engagement brief or a project memory.
The one allowed inline: per-task one-off values that exist nowhere else — an invoice number for this specific job, a customer-quoted price for this specific deal, a one-time URL like a meeting link. These have no canonical home, so the ticket is the home.
5. Steps - Creating a task
⚠️ Run the §4 Content hygiene checks on the composed name and description before step 4 below.
-
Resolve prerequisites. Open the client profile. Confirm
ClickUp List IDis populated. If*(TBD)*, stop and do Section 7 first. -
Read the task file. Note the frontmatter and H1.
-
Resolve assignee. Call
mcp__claude_ai_ClickUp__clickup_resolve_assigneeswith the assignee name/email. If the assignee is the authenticated user,"me"resolves faster than a name lookup. -
Create the task. Call
mcp__claude_ai_ClickUp__clickup_create_taskwith the fields from Section 3. Usemarkdown_description(notdescription) to preserve formatting. -
Write back the cross-reference. Edit the source markdown frontmatter to add:
clickup_task_id: <task_id from response>
clickup_url: <task_url from response> -
Tags. Call
clickup_add_tag_to_taskfor each tag. Tags MUST come from the SC ClickUp Tag Taxonomy. New tags require a PR amending that standard before being added to a task — do not create ad-hoc tags at space level. If a needed tag is missing from the taxonomy, either pick the closest canonical equivalent or pause to propose the addition. -
Commit. Include the frontmatter update in the next monthly task-folder commit.
6. Steps - Updating an existing task
⚠️ Run the §4 Content hygiene checks on any new or replacement description content before calling clickup_update_task. The same local-path and unverified-URL risks apply.
The task file's clickup_task_id is the pointer.
- Status/assignee changes made in the ClickUp UI are authoritative for operational state. Do not overwrite from the markdown.
- Description or step changes in the markdown sync to ClickUp via
clickup_update_taskusingtask_id = frontmatter.clickup_task_idandmarkdown_description = new body. - Completing the task: mark the checkbox list done in ClickUp. Do not overwrite the markdown
status: openfield unless the file is being archived out of the monthly folder.
7. Populating a missing ClickUp List ID
Only needed when the client profile shows *(TBD)*.
-
Open ClickUp, navigate to Client Delivery space.
-
Locate or create a folder for the client inside Client Delivery. Convention (observed 2026-04 from the Kraneworks list): each client has a folder named after the client slug (e.g.,
Kraneworks) containing anactive-worklist. Use this pattern for consistency. -
Copy the list URL from the ClickUp UI. The list ID is the trailing numeric segment:
https://app.clickup.com/<workspace>/v/l/li/<list_id>. -
Edit the client profile:
- **ClickUp List URL:** <full URL>
- **ClickUp List ID:** <numeric list ID>
- **ClickUp Space:** Client Delivery > active-workReplace the old
ClickUp Folder URL: *(TBD)*line. Bumpversionandlast_updatedin the profile frontmatter.
8. Reference
- SC Task Data Standard -- universal status and priority model
- Google Drive Organization Standard -- task file naming
- ClickUp SC Operations Space Setup SOP -- sibling SOP for the SC Operations space
symphony-flowClickUp adapter:src/adapters/clickup/index.ts(local path `[LOCAL_PATH_REMOVED]) -- reference for the deferred automated workflow
9. Deferred - symphony-flow automation
A workflow config/workflows/markdown_task_to_clickup.yaml can replace the manual steps in Section 4 when volume justifies it (roughly: processing a full month's task folder at once, or more than ~5 new task files per week). The workflow would:
- Accept
markdown_file_pathas input (optionallist_idoverride) - Read the file, parse frontmatter (reuse the pattern from
client_data_extraction.yaml) - Resolve the list ID from the client slug using the client profile
- Call the ClickUp adapter's
create_taskaction - Write
clickup_task_idback to the file
Triggered via npm run cli -- trigger markdown_task_to_clickup --input '{...}' or the HTTP API. Not built yet; the field mapping and frontmatter conventions in this SOP are the contract that workflow will implement.
Appendix A - Agent Quick Reference
For Claude Code / LLM agents executing this SOP. Humans can skim.
A1. Loading tools
ClickUp MCP tools are deferred. Load only what you need:
ToolSearch(query="select:mcp__claude_ai_ClickUp__clickup_create_task,mcp__claude_ai_ClickUp__clickup_resolve_assignees")
Tool reference (use the mcp__claude_ai_ClickUp__ prefix when calling):
| Tool | When to use |
|---|---|
clickup_create_task | Create a new task. Required: list_id, name. |
clickup_update_task | Update an existing task. Required: task_id. |
clickup_get_task | Read a task by ID. Good for verification after create. |
clickup_resolve_assignees | Convert name/email/"me" to ClickUp user IDs. |
clickup_get_list | Look up a list by ID or name; confirms space/folder path. |
clickup_add_tag_to_task | Add a tag. Tag must pre-exist in the space. |
clickup_get_workspace_hierarchy | Pull the full spaces/folders/lists tree. Useful for audits. |
clickup_create_folder | Create a folder in a space. |
clickup_create_list_in_folder | Create a list inside a folder (4x to replicate the standard client layout). |
clickup_search | Find tasks by keyword across the workspace. |
A2. Invocation gotchas (observed in real runs)
- Use
markdown_description(notdescription) when the description contains markdown.descriptiontreats the input as plain text. - Priority is a string:
'urgent' | 'high' | 'normal' | 'low'. Not the 1-4 integer from the ClickUp UI. - Tags must pre-exist at the space level.
clickup_add_tag_to_taskfails with"tag does not exist"otherwise. Either skip, or seed the standard tag set once in the ClickUp UI. clickup_resolve_assignees(["Full Name"])often returnsnullfor team members. Retry with their email, or use"me"for the authenticated user.workspace_idis auto-detected from the authenticated session. Only pass it to override.- Status: omit for
TODO(ClickUp default). Pass explicit status only for non-default states. due_dateformat isYYYY-MM-DDorYYYY-MM-DD HH:MM. No timezone suffix.- Creating many lists back-to-back: expect occasional transient
502 Bad Gatewayfrom the MCP proxy. One retry has been sufficient. - §4 Content hygiene is not optional for agents. Copy-pasting a markdown body into
markdown_descriptionwithout running the hygiene checks has already produced one ClickUp task with unreachable Windows paths and a deadteam.symphonycore.comlink (moots-law, 2026-04-20). Run the checks every time.
A3. Known workspace layout (as of 2026-04-20)
- Workspace:
9009191338 - Client Delivery space:
901310638175 - Each active client has its own folder with the 4-list structure:
active-work,completed-work,archive,reference. - Per-client list IDs are stored in
09-clients/<slug>/<slug>-client-profile.md. Read the profile before callingcreate_task— do not hard-code list IDs. - SC-internal work folder (inside Client Delivery):
Symphony-Core, active-work list901320525397. Under review for move to a dedicated SC Operations space.
A4. Standard execution for a new task file
Minimal tool sequence for the common case "markdown task file → ClickUp task":
Readthe task file. Extract H1 (for name), frontmatter (for priority, assignee, due_date, status), body (for description).Read09-clients/<slug>/<slug>-client-profile.md. ExtractClickUp List ID.clickup_resolve_assignees(["<assignee name or email>"]). If null and you have no email, ask the user.clickup_create_task(list_id=..., name=..., markdown_description=..., priority=..., due_date=..., assignees=[...]). Capturetask_idandtask_urlfrom the response.Editthe task markdown file to appendclickup_task_idandclickup_urlto the frontmatter.- Optional:
clickup_add_tag_to_taskper tag (expect failures if tags not seeded). git add/committhe client profile or markdown file edits if they live in the repo. Task markdown files in Google Drive are not committed.