Skip to main content

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 ID populated in their client profile at 09-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_KEY env var (for symphony-flow runs).

3. Field Mapping

ClickUp fieldSource in markdownConversion rule
list_idClient profile ClickUp List IDCopy literally
name# H1 of markdown bodyPrefer H1 over frontmatter title; H1 is the user-visible task title
markdown_descriptionFull body (from first ## Section onwards)Append a footer: **Source file:** <absolute path> and **Source call/context:** <frontmatter.source>
prioritypriority frontmatterMap: urgent -> urgent, high -> high, medium/normal -> normal, low -> low. Uses string values (not 1-4 integer)
assigneesassignee frontmatterPass as array. Resolve via clickup_resolve_assignees. For the authenticated user, "me" works; named users may need email.
statusstatus frontmatterMap: 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_datedue_date frontmatter (if present)Format YYYY-MM-DD
tagsDerived: <client-slug> plus any domain tags implied by contentTags 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.

  1. 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.
  2. 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>.mdhttps://team.symphonycore.com/operations/sops/<name>; 08-reference/standards/<name>.mdhttps://team.symphonycore.com/reference/standards/<name>; 06-team-training/platform-training/<name>.mdhttps://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 in Client_Delivery/<slug>/client-reference/ if one exists.
  3. 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?

  4. 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.

  1. Resolve prerequisites. Open the client profile. Confirm ClickUp List ID is populated. If *(TBD)*, stop and do Section 7 first.

  2. Read the task file. Note the frontmatter and H1.

  3. Resolve assignee. Call mcp__claude_ai_ClickUp__clickup_resolve_assignees with the assignee name/email. If the assignee is the authenticated user, "me" resolves faster than a name lookup.

  4. Create the task. Call mcp__claude_ai_ClickUp__clickup_create_task with the fields from Section 3. Use markdown_description (not description) to preserve formatting.

  5. 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>
  6. Tags. Call clickup_add_tag_to_task for 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.

  7. 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_task using task_id = frontmatter.clickup_task_id and markdown_description = new body.
  • Completing the task: mark the checkbox list done in ClickUp. Do not overwrite the markdown status: open field 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)*.

  1. Open ClickUp, navigate to Client Delivery space.

  2. 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 an active-work list. Use this pattern for consistency.

  3. 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>.

  4. Edit the client profile:

    - **ClickUp List URL:** <full URL>
    - **ClickUp List ID:** <numeric list ID>
    - **ClickUp Space:** Client Delivery > active-work

    Replace the old ClickUp Folder URL: *(TBD)* line. Bump version and last_updated in the profile frontmatter.

8. Reference

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_path as input (optional list_id override)
  • 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_task action
  • Write clickup_task_id back 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):

ToolWhen to use
clickup_create_taskCreate a new task. Required: list_id, name.
clickup_update_taskUpdate an existing task. Required: task_id.
clickup_get_taskRead a task by ID. Good for verification after create.
clickup_resolve_assigneesConvert name/email/"me" to ClickUp user IDs.
clickup_get_listLook up a list by ID or name; confirms space/folder path.
clickup_add_tag_to_taskAdd a tag. Tag must pre-exist in the space.
clickup_get_workspace_hierarchyPull the full spaces/folders/lists tree. Useful for audits.
clickup_create_folderCreate a folder in a space.
clickup_create_list_in_folderCreate a list inside a folder (4x to replicate the standard client layout).
clickup_searchFind tasks by keyword across the workspace.

A2. Invocation gotchas (observed in real runs)

  • Use markdown_description (not description) when the description contains markdown. description treats 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_task fails 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 returns null for team members. Retry with their email, or use "me" for the authenticated user.
  • workspace_id is 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_date format is YYYY-MM-DD or YYYY-MM-DD HH:MM. No timezone suffix.
  • Creating many lists back-to-back: expect occasional transient 502 Bad Gateway from the MCP proxy. One retry has been sufficient.
  • §4 Content hygiene is not optional for agents. Copy-pasting a markdown body into markdown_description without running the hygiene checks has already produced one ClickUp task with unreachable Windows paths and a dead team.symphonycore.com link (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 calling create_task — do not hard-code list IDs.
  • SC-internal work folder (inside Client Delivery): Symphony-Core, active-work list 901320525397. 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":

  1. Read the task file. Extract H1 (for name), frontmatter (for priority, assignee, due_date, status), body (for description).
  2. Read 09-clients/<slug>/<slug>-client-profile.md. Extract ClickUp List ID.
  3. clickup_resolve_assignees(["<assignee name or email>"]). If null and you have no email, ask the user.
  4. clickup_create_task(list_id=..., name=..., markdown_description=..., priority=..., due_date=..., assignees=[...]). Capture task_id and task_url from the response.
  5. Edit the task markdown file to append clickup_task_id and clickup_url to the frontmatter.
  6. Optional: clickup_add_tag_to_task per tag (expect failures if tags not seeded).
  7. git add/commit the client profile or markdown file edits if they live in the repo. Task markdown files in Google Drive are not committed.