# Docs Collaborator

> |

- **Type:** Skill
- **Install:** `agentstack add skill-mondaycom-skills-docs-collaborator`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [mondaycom](https://agentstack.voostack.com/s/mondaycom)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [mondaycom](https://github.com/mondaycom)
- **Source:** https://github.com/mondaycom/skills/tree/main/skills/docs-collaborator
- **Website:** https://developer.monday.com

## Install

```sh
agentstack add skill-mondaycom-skills-docs-collaborator
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Docs Collaborator

Create, read, edit, and comment on monday.com docs. **The skill is a capability surface, not a template engine.** Every doc is a stream of typed blocks (headings, paragraphs, lists, tables, code, dividers, notice boxes, layouts, embedded boards / widgets / docs / images / videos / GIFs). The named shapes listed below are starting points - compose and extend freely. The differentiators (live column-value embeds, inline mentions, notice boxes, layouts) apply to any shape, named or invented.

The platform-native value over a raw markdown editor lives in three things most builders miss: inline mentions of users / docs / boards, **live column-value embeds** that reflect the current state of a board item, and a closed-loop edit pattern that prevents corrupting the doc's block graph.

## Core constraint - read this first

**Never edit a block you have not read.** monday's update_doc API is block-ID-based, and block IDs are only knowable through `read_docs` with `include_blocks: true`. Skipping the read leads to operations referencing IDs that do not exist (silent failure) or - worse - reusing an ID from another doc. The closed-loop pattern is non-negotiable:

1. `read_docs` with `include_blocks: true` to get block IDs, types, and positions.
2. Identify the target block(s) by type and position or by content.
3. `update_doc` with the operation that matches the target block's type (see the routing rule below).

## Block operation routing - the non-obvious part

Each block type has a different set of allowed mutations. Picking the wrong operation is the #1 cause of "the call succeeded but the doc looks wrong" bugs.

| Target block type | Use this operation | Why |
|---|---|---|
| text (any subtype: NORMAL_TEXT, LARGE_TITLE, MEDIUM_TITLE, SMALL_TITLE, QUOTE) | `update_block` for content edits; `replace_block` to change the subtype (e.g. promote a paragraph to H2) | Subtype is set on creation; `update_block` cannot change it |
| code | `update_block` | Content and language editable in place |
| list_item (BULLETED_LIST, NUMBERED_LIST, CHECK_LIST) | `update_block` for content edits; `replace_block` to switch between bulleted / numbered / check | List variant is set on creation |
| divider | `replace_block` only | No mutable properties |
| table | `replace_block` only | Row / column count and column widths immutable; table cell content not addressable via API after creation - see "Tables" below |
| image | `replace_block` to swap source | URL / asset_id immutable after creation |
| video | `replace_block` to swap source | raw_url immutable after creation |
| notice_box | `replace_block` to change theme | theme immutable; content lives in child blocks (see "Notice boxes" below) |
| layout | `replace_block` only | Cell content cannot be populated via API at all - see "Layouts" below |
| BOARD embed, WIDGET embed, DOC embed, GIPHY | `delete_block` only | No public API to create or modify these block types |

**Rendering quirk - list_item + mention via `update_block`.** When adding an inline mention to a list_item that previously contained only text, `update_block` may save the mention blot correctly (data confirms) but Cowork can fail to render the pill (text-prefix-before-mention case). Workaround: use `replace_block` with a fresh list_item containing the same delta. Same pattern in a `normal_text` block renders correctly; the quirk appears specific to list_item updates.

Full per-block-type detail with worked examples lives in `references/block-operations-matrix.md`. Read it before authoring any non-trivial structural edit.

## Workflow: Create a doc

### Step 1: Decide the location

monday docs live in one of two places:

- **Workspace** (most common). Requires `workspace_id`. Optional `doc_kind`: `public` (default), `private` (only the creator), `share` (specific people). Optional `folder_id` to nest under a folder.
- **Item-attached**. The doc lives in a doc-type column on a specific board item. Requires `item_id`. Optional `column_id` if the user picked a specific doc column; otherwise the tool auto-creates one.

**Cell-limit preflight for item-attached docs.** Doc-type cells hold one doc per cell - hard API limit. Before calling `create_doc location=item`, preflight the target column via `get_board_items_page` with `columnIds: []` to check whether the cell is already populated. If populated, do NOT attempt the create - it will fail with `CellLimitExceededException`. Fall back to **creating a workspace-level doc and adding a bi-directional DOC mention cross-link** between the new doc and the existing attached doc. Never auto-detach the existing doc.

If the user does not name a workspace, fall back to the user's primary workspace via `get_user_context`. Ask once if it's still ambiguous; do not guess across multiple workspaces.

### Step 2: Plan-tier guard before creating a 4th doc

**Free and Basic plans cap at 3 docs per account.** Before calling `create_doc` on a Free / Basic account, check whether this would be the 4th doc. There is no direct doc-count tool, so the practical guard is: if the user has hit this limit before or asks "can I create more than 3 docs?", warn them - upgrade to Standard+ removes the cap. Treat plan-tier as an open question rather than blocking the create call; the platform itself will reject if the cap is hit.

### Step 3: Compose the body - shapes are examples, not boundaries

`create_doc` takes a `markdown` parameter that is parsed into blocks on import. This is the most efficient way to scaffold a doc in one call. Reach for one of these common shapes as a starting point when the user names a use case, then extend freely:

- **Meeting notes:** title, date, attendees (with `@mentions`), agenda bullets, decisions, action items table, follow-ups.
- **Weekly update:** highlights, key metrics, risks, next-week plan.
- **RFC:** problem, proposed solution, alternatives considered, open questions, decision log.
- **Runbook:** trigger, prerequisites, numbered procedure, rollback steps, escalation path.
- **Postmortem:** incident summary, timeline, root cause, what went well, what did not, action items.

When the user invents a shape ("partner enablement page", "AI readiness snapshot", "Q3 onboarding context"), compose with judgment - sections, tables, notice boxes, embeds - rather than forcing a named template. The differentiators apply to any shape.

**Default mode: passive scaffold.** Reserve visible slots for embeds and mentions in the markdown body using machine-readable markers. Skill (and downstream agents) can later detect and fill these slots when the user names the underlying items / users.

| Slot type | Marker format | Example |
|---|---|---|
| Live column-value embed | `_[embed:  of ]_` | `_[embed: status of ]_` |
| User mention | `_[mention: ]_` | `_[mention: ]_` |
| Doc / board mention | `_[mention-doc: ]_` / `_[mention-board: ]_` | `_[mention-board: Project Tracker]_` |

Italic styling on slot markers gives visual signal that the content is dynamic. The bracket-keyword format is grep-able for downstream automation.

**Active mode: escalate when intent signals are present.** Switch from passive scaffold to wiring real embeds / mentions / cross-links when the user's prompt signals intent through name-based references. Never on item IDs - users speak in names.

Triggers that escalate to active mode:

- Item names ("the Q3 plan", "the launch milestone", "the blocker we discussed")
- Board names ("from the project tracker", "in the bug board")
- Owner names ("Daniel's tasks", "my items", "the design team's")
- Positional refs ("the top 3 priorities", "the most recent stuck items")
- Imperative wiring ("embed live status from", "show current status of", "pull from ", "wire up the embeds", "tag me as owner")

Resolution chain (name -> ID, never ask the user for IDs):
- Item name -> `get_board_items_page` with `searchTerm` scoped to the named board
- Board name -> `search` with `searchType: BOARD`
- Owner name -> `list_users_and_teams` with `name:` (scoped per cross-skill rule)
- Ambiguous match -> ask once with the top 3 candidates; do not silently pick

**Active mode communication contract.** When the skill picks items / users in active mode, always state the choice and the reasoning: "Picked items X, Y, Z because . Override by naming different items."

Markdown notes that matter:

- Markdown headings (`#`, `##`, `###`) map to LARGE_TITLE / MEDIUM_TITLE / SMALL_TITLE blocks.
- Markdown tables work and the cells will be populated with the values you put in. **This is the only way to get pre-filled table content.** Cell-level API population after creation is not supported.
- Markdown images and links work. For asset-based images (uploaded files in monday), use `update_doc` with `create_block` and `block_type: "image"` plus `asset_id` after creation - markdown cannot reference assets.
- Markdown does not have notice_box, layout, embed, divider-with-spacing, mention, or live column-value syntax. Add those via `update_doc` after the doc is created.

### Step 4: Call `create_doc`

```
create_doc({
  doc_name: "",
  location: "workspace",
  workspace_id: ,
  doc_kind: "public" | "private" | "share",  // optional
  folder_id: ,                            // optional
  markdown: ""
})
```

For item-attached (after preflight):

```
create_doc({
  doc_name: "",
  location: "item",
  item_id: ,
  column_id: "",  // optional
  markdown: ""
})
```

Capture the returned `doc_id`, `object_id`, and `doc_url`. The user wants the URL to share or open; the `doc_id` is the primary key for every subsequent edit.

### Step 5: Layer in the rich-content extras

Mentions, live column-value embeds, notice boxes, layouts, and asset images all need a follow-up `update_doc` call. In active mode, wire them now using the resolved IDs from Step 3. In passive mode, leave the slot markers in place - the user fills slots later by naming items. See "Common edit patterns" below.

### Step 6: Confirm and suggest next steps

Plain-language confirmation: name, workspace, doc URL. State the mode used (passive scaffold or active). Then 2-3 follow-ups appropriate to the shape:

- "Want me to tag the attendees with @mentions?"
- "Want me to embed live status from the project board?"
- "Should I add a notice box at the top with the meeting outcome?"
- "Want me to share the doc URL in a Slack channel?"

## Workflow: Read a doc

### Step 1: Resolve the doc identifier

Three ways the user might point at a doc:

- **doc_id** (e.g., `41302579`) - the API's primary key, returned by `create_doc` and `read_docs`.
- **object_id** (e.g., `18411484379`) - the numeric segment of the doc URL: `https://monday.monday.com/docs/{object_id}`.
- **doc name or fuzzy reference** ("the Q3 retro doc") - resolve via `read_docs` with `type: "workspace_ids"` to list docs in a workspace, then match by name.

`read_docs` is forgiving: if you call it with `type: "ids"` and the value is actually an `object_id`, it auto-retries as `object_ids`. Lean on this rather than guessing.

### Step 2: Decide what to read

Two modes:

- **content** (default) - returns the doc's blocks and / or markdown projection.
  - `include_blocks: true` is **mandatory** if any edit will follow. Do not omit it.
  - `include_comments: true` to fetch all comments and replies. Use `comments_limit` to cap (default 50).
- **version_history** - returns the doc's edit history (restoring points). Pass the `object_id`, not the `id`. Set `version_history_limit` for "last N changes" requests; set `include_diff: true` to see what changed (slower).

### Step 3: Render with resolved mentions and embeds, not placeholders

The API's `blocks_as_markdown` projection renders mentions as `@{USER-XXX}` placeholders and live column-value embeds as empty space. **This is not the right rendering for a "show me what's in this doc" prompt** - the user sees pills and live chips when they open the doc; the textual rendering should mirror that.

For read responses to "show me / what's in / read this doc" prompts:

- **Always resolve mentions.** Map every USER mention id to a display name (via cached `list_users_and_teams` or a scoped lookup). Map every DOC mention to its doc name. Map every BOARD mention to its board name. Render inline as `**@Alex Polonsky**` (or similar) rather than `@{USER-38288909}`.
- **Resolve embeds when data is cached or cheap to fetch.** If the doc references items / columns already touched in the conversation, use the cached value. If not, fetch with `get_board_items_page` scoped to the specific items + columns. Render as the resolved column value ("**Working on it**", "**No value**", "**2026-05-15**") inline. Skip resolution only if it would require many extra MCP calls for a long doc.
- **Always keep the structured enumeration table as a secondary affordance.** List every inline non-text element (mentions, embeds, notice_boxes, code blocks, tables) with block IDs and IDs. Useful for downstream edit operations and for users who want to target a specific element.

Do not use `show-table` for doc content - the doc itself is the UI. Render in chat with markdown.

## Workflow: Edit a doc

### Step 1: Read first

`read_docs` with `include_blocks: true`. This is the closed-loop precondition. Capture every block's `id`, `type`, and position.

### Step 2: Pick the right operation

Reach for the simplest one that does the job:

- **Add new content at the end:** `add_markdown_content` (no block IDs needed; supports text, lists, tables, code).
- **Add asset-based images:** `create_block` with `block_type: "image"` and `asset_id` (markdown does not support asset images).
- **Edit existing text / code / list_item content in place:** `update_block` with the matching `block_content_type` (`text`, `code`, or `list_item`).
- **Change a block's subtype** (paragraph -> H2, bulleted -> numbered, INFO notice -> WARNING notice): `replace_block`. Subtypes are set on creation only.
- **Insert a block at a precise position:** `create_block` with `after_block_id` set. There is no `before_block_id` operation - to insert at the very top of a doc, the only path is to insert after the doc's first block.
- **Delete:** `delete_block`. The only path for BOARD / WIDGET / DOC embed / GIPHY blocks.
- **Comment:** `add_comment` (see "Comments" below).
- **Rename the doc:** `set_name`.

The full type-to-operation routing lives in `references/block-operations-matrix.md`.

### Step 3: Compose the delta_format (for text / code / list_item)

`update_block` and `create_block` for content blocks take a `delta_format` array of insert ops. Three rules govern every delta:

1. The last op MUST be `{insert: {text: "\n"}}`. Always. No exceptions.
2. Plain text uses `{insert: {text: "..."}}` with optional `attributes` (bold, italic, underline, strike, code, link, color, background).
3. Two non-text inserts unlock the differentiators:
   - Mention: `{insert: {mention: {id: , type: "USER" | "DOC" | "BOARD"}}}`. Resolve user IDs via `list_users_and_teams` (always pass `name` to scope the call).
   - Live column-value embed: `{insert: {column_value: {item_id: , column_id: ""}}}`. Renders the current value of that column on that item, live, every time the doc is opened.

Worked examples and the full attribute table live in `references/delta-format-cheatsheet.md`.

### Step 4: Batch operations carefully

`update_doc` accepts up to 25 operations in one call, executed in order, stopping at the first failure. Four gotchas:

- **Notice box nesting requires two calls.** A notice_box created in the same call cannot be referenced by `parent_block_id` in a later operation in the same call. Create the notice_box, capture the returned ID, then make a second `update_doc` call to nest children.
- **Position dependencies.** If operation B references the position of a block created by operation A, prefer two calls. Failures partway through the array leave the doc in a partial state.
- **Same-block conflict detection.** When

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [mondaycom](https://github.com/mondaycom)
- **Source:** [mondaycom/skills](https://github.com/mondaycom/skills)
- **License:** MIT
- **Homepage:** https://developer.monday.com

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-mondaycom-skills-docs-collaborator
- Seller: https://agentstack.voostack.com/s/mondaycom
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
