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 SC Task Management Workspace Setup SOP §6
- 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 | Exactly one assignee per ticket — see §3d. Pass as a single-element 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 to do); in_progress → in progress; blocked → blocked; complete → complete; cancelled → cancelled. See SC Task Data Standard §1 for the canonical status model. |
due_date | due_date frontmatter (if present) | Format YYYY-MM-DD |
custom_fields → Client | Client slug (matches the 09-clients/<slug>/ directory and the client's folder name in ClickUp) | Client Delivery tasks only — required on every ticket. SC Operations tasks: skip (the field doesn't exist there; use the client/<slug> tag instead — see the tags row). First run: call clickup_get_custom_fields against the target list to discover the Client field's id and the option-value UUID for the client; cache thereafter (see Appendix A2). Set via the custom_fields parameter on clickup_create_task, or via clickup_update_task post-creation. |
tags | Derived: domain tags implied by content; client/<slug> only when the target list does not encode the client (see rule below) | Tags must pre-exist in the space -- see Section 5. For client/<slug> specifically: required on SC Operations tasks and Client Delivery shared lists (client-delivery-operations, reference); optional on per-client lists where the Client custom field is the canonical identifier. Tag–field correspondence: when both are populated on the same task, the tag slug must equal the Client field value. See SC ClickUp Tag Taxonomy §Client identity. |
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.
3c. Client-facing deliverables require a QA-Review subtask
For any ticket whose primary output is client-facing (published copy, brand assets, anything the client will see), the Creator adds a subtask named qa-review-<parent-slug> at ticket creation time. The subtask follows the standard flow (to do → in progress → complete). The QA Reviewer (default: the Account Manager — see ClickUp Ways of Working §Roles) is the assignee. The parent ticket cannot move to complete until the QA-Review subtask is closed.
This is a per-ticket pattern, decided manually by the Creator at creation. There is no automation that adds the subtask from a tag, frontmatter field, or other signal. Default = no QA-Review subtask; add it only when the output is client-facing.
Legacy compatibility: before 2026-06-14 this pattern was named am-review-<parent-slug> (assuming the Account Manager was the only QA Reviewer). Existing am-review-* subtasks remain valid as-is — do not rename them retroactively. New tickets use qa-review-*. Views that surface this queue must match BOTH patterns during the transition (see Views Guide §6.5).
Why: Replaces the workflow-wide review status (retired 2026-05). The synchronous review step had become a bottleneck — no dedicated reviewers meant tickets sat unreviewed for weeks. The QA-Review subtask localizes the QC step to the cases that genuinely need pre-release human checking (client-facing output), while internal/non-client work flows TODO → IN PROGRESS → COMPLETE on contractor self-attestation backed by the Evidence bullet (see validation-evidence-rule). Post-hoc sampling (see Review Standard §Post-hoc sampling) catches escaped defects across both paths.
What counts as client-facing: published website copy, brand assets, contracts/proposals, anything sent to the client by email, GHL workflows that touch the client's contacts, anything that lands in production where the client will see it. When in doubt, add the subtask.
What does NOT count: internal documentation, SOP edits, configuration tasks that don't change client-visible behavior, research spikes, prep work for a future ticket.
3d. One assignee per ticket (and per sub-task)
Every ClickUp ticket and every sub-task has exactly one assignee. No multi-assignee tickets, anywhere.
Why: Ownership and time-tracking accountability. When multiple people are on a ticket, it's not easy to see who logged what time, who's responsible for the next move, or who owns the close-out. The Timesheet Approval flow (see ClickUp Timesheet Approval SOP) gets ambiguous when entries on the same ticket come from two contributors without clear delineation.
How to apply:
- Markdown task file
assignee:frontmatter holds one name (not a list). - When creating via MCP, pass
assigneesas a single-element array. - When the work is genuinely shared (pair-work, two specialists on the same deliverable), split into either (a) sibling tickets, one per contributor, or (b) a parent + one sub-task per contributor. The parent ticket itself still has a single assignee — usually the AM or the primary owner.
- The QA-Review subtask pattern from §3c is consistent with this rule: the subtask is a separate ticket with the QA Reviewer (default: AM) as its single assignee.
- Visibility is solved by Watchers, not by multi-assignment. If other people need to follow the ticket without owning it, add them as Watchers.
Workspace-level enforcement (target state): the "Multiple Assignees" ClickApp should be disabled at the workspace level so multi-assignee tickets are mechanically prevented. Until that admin change lands, this rule is enforced by author discipline.
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. -
Set the
Clientcustom field (Client Delivery tasks only — skip for SC Operations). Resolve the field UUID and the client's option UUID viaclickup_get_custom_fieldsagainst the target list (cache after first call — see Appendix A2). Either include the field in step 4'sclickup_create_taskcustom_fieldsparameter, or set it post-creation viaclickup_update_taskwithcustom_fields=[{"id": "<field-uuid>", "value": "<option-uuid>"}]. SC Operations: use theclient/<slug>tag in step 7 instead. -
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. Forclient/<slug>specifically, see the field-vs-tag scoping rule in §3 and the Tag Taxonomy §Client identity. -
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
- SC Task Management Workspace Setup SOP -- canonical workspace setup spec covering both Client Delivery and SC Operations spaces
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
to do(ClickUp default). Pass explicit status only for non-default states. See SC Task Data Standard §1 for the canonical model. 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. - Custom field IDs are space-scoped and stable. After first lookup via
clickup_get_custom_fieldson a Client Delivery list, cache theClientfield's UUID and each client's option UUID — they don't change between task creations. Avoids re-fetching the schema on every call. Refresh the cache only when a new client is added (new option) or the field schema is intentionally changed.
A3. Known workspace layout (as of 2026-04-20)
- Workspace:
9009191338 - Client Delivery space:
901310638175 - Each active client has its own folder with the 2-list structure:
active-work(every task in every status — the Closed-group hide oncompletekeeps finished work out of default views) andreference(standing reference items only). Thecompleted-workandarchivelists were retired 2026-06-08 — see SC Task Management Workspace Setup SOP §5.2. Cold storage uses ClickUp's native task archive on a monthly UI sweep (§5.6 of the same SOP). - 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.