Markdown Checklist Extractor
productivity.todo_extract
Overview
You send Markdown and we hand back its checklist as structured items: the state of each box, where it sits in the nesting, the exact characters it occupies in your document, and an identity derived from the item's own text so two extractions of the same list line up. The grammar we read is GitHub's task-list extension and only that — a space, an x or an X between the brackets. A bullet that is not a checkbox is counted for you but never adopted into the list, because a document that mixes prose bullets with tasks is normal rather than broken.
Agents keep their plans in Markdown, and re-reading that plan with a hand-rolled parser gives a different answer every time the indentation changes.
Reliability
Same document, same options, same bytes back, including every identity: an identity is your document prefix, the first sixteen hex characters of the SHA-256 of the item's normalised text, and its position, so inserting a line at the top changes positions and leaves the hashes alone. Failures, none worth retrying unchanged: TODO_TEXT_INVALID means text was missing, was not a string, or was empty, so send the document itself; TODO_TEXT_TOO_LARGE means the document went past 262,144 characters, so split it and extract each part; TODO_LINE_LIMIT_EXCEEDED means it went past 40,000 lines, which is the same remedy of splitting the document; TODO_MARKER_SET_INVALID means listMarkers held something outside the five supported markers or repeated one, so send a clean set; TODO_DEPTH_INVALID means maxDepth sat outside 1 to 6, so pick a level in range; TODO_DOCUMENT_ID_INVALID means documentId was too long or used a character outside the allowed set, so shorten it and stick to letters, digits, dot, underscore, colon and hyphen; TODO_EXTRACT_WORK_REFUSED means the document's size and line count together project past our work budget, and the response tells you both numbers so you know how far to trim; TODO_OUTPUT_TOO_LARGE means the extracted list would not fit in one inline response, so lower maxItems or extract a section at a time.
Context footprint
Returns one record per checkbox plus a counts block. Item text is echoed because a task without its wording is not a task, and it is capped at 2,000 characters per item. A successful call costs 1 execution credit.
When to use it
When you hold a Markdown document and want its checkboxes as data you can compare, update and store.
When the items you want are not checkboxes, or when you want us to change something in a tracker rather than read a document.
Scope
Non-goals
- Does not write to any task tracker, calendar or note store
- Does not accept a pattern, expression or selector of any kind
- Does not adopt a plain bullet as a task; it counts it instead
- Does not read anything inside a fenced code block
- Does not renumber an ordered list; the author's numbers come back as written
Properties
Capabilities
Cost & billing
Flat rate per invocation
File handling
How we handle your data
What this means
This skill may receive sensitive content and may return submitted, transformed, extracted, or reformatted content.
Squillify guarantees
- Runs inside Squillify
- This skill runs inside Squillify.
- Payloads are not sent to an external service by this skill.
- Squillify does not permanently store submitted payloads.
- Telemetry records metadata only, not submitted content.
- Submitted payloads are not used for training.
- Submitted payloads are not reviewed by humans.
- This skill does not target sensitive data.
- The response may contain submitted or transformed content.
Your responsibility
Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
| text | string | Yes | Markdown document to scan, 1 to 262144 characters over at most 40000 lines; fenced code is skipped. |
| documentId | string | No | Document prefix for derived identities, 1 to 64 letters, digits, dots, underscores, colons or hyphens; omit it so identities start with a bare colon. |
| listMarkers | array | No | Which markers open a list item, 1 to 5 of HYPHEN, ASTERISK, PLUS, ORDERED_DOT and ORDERED_PAREN; omit it to accept all five. |
| stateFilter | string | No | Keep every item with ALL, only ticked boxes with CHECKED, or only open ones with UNCHECKED; omit it for ALL. |
| maxDepth | integer | No | Deepest nesting level to report, 1 to 6; omit it for 6. |
| maxItems | integer | No | How many items to return, 1 to 5000; omit it for 5000. |
Output schema
| Field | Type | Required | Description |
|---|---|---|---|
| items | array | Yes | Checklist in document order, 0 through 5000 closed items each with id, nesting, state, marker, offsets and flags. |
| summary | object | Yes | Closed counts for the whole document: returned itemCount, checked and unchecked totals, non-task bullets, depth, truncation and clamp flags. |
API contract
POST /v1/executecurl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"productivity.todo_extract","input":{"text":"- [ ] Draft the changelog\n- [x] Tag the release","documentId":"release-notes"}}'import { Squillify } from "@squillify/sdk";
const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });
const { output } = await sq.execute("productivity.todo_extract", {"documentId":"release-notes","text":"# Release\n- [ ] Draft the changelog\n- [x] Tag the release\n"});Errors
| Code | HTTP | Retryable | Description |
|---|---|---|---|
| VALIDATION_ERROR | 400 | No | The request payload failed schema validation. |
| UNAUTHORIZED | 401 | No | Missing or invalid API key. |
| SKILL_NOT_ACCESSIBLE | 403 | No | The API key is not granted access to this skill. |
| SKILL_NOT_AVAILABLE_FOR_PLAN | 403 | No | This skill is not included in your current plan. |
| PLAN_ELIGIBILITY_UNAVAILABLE | 503 | Yes | Plan eligibility could not be decided. Retry after backoff. |
| SKILL_NOT_FOUND | 404 | No | The requested skill or version does not exist. |
| TENANT_RATE_LIMITED | 429 | Yes | Request rate limit exceeded. Retry after backoff. |
| QUOTA_EXCEEDED | 429 | Yes | Plan quota exhausted. Retryable once the quota period resets. |
| EXECUTION_TIMEOUT | 504 | Yes | Execution exceeded the allowed time budget. |
| TODO_TEXT_INVALID | 400 | No | The request payload failed this skill's input validation. |
| TODO_TEXT_TOO_LARGE | 429 | No | A size, quota, rate, or time limit was exceeded. |
| TODO_LINE_LIMIT_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
| TODO_MARKER_SET_INVALID | 400 | No | The request payload failed this skill's input validation. |
| TODO_DEPTH_INVALID | 400 | No | The request payload failed this skill's input validation. |
| TODO_DOCUMENT_ID_INVALID | 400 | No | The request payload failed this skill's input validation. |
| TODO_EXTRACT_WORK_REFUSED | 429 | No | A size, quota, rate, or time limit was exceeded. |
| TODO_OUTPUT_TOO_LARGE | 429 | No | A size, quota, rate, or time limit was exceeded. |
Other limits
| Limit | Value |
|---|---|
| Recommended inline bytes | 32 KiB |
Limitations
- Does not write to any task tracker, calendar or note store
- Does not accept a pattern, expression or selector of any kind
- Does not adopt a plain bullet as a task; it counts it instead
- Does not read anything inside a fenced code block
- Does not renumber an ordered list; the author's numbers come back as written
- Extracting anything that is not a checkbox, such as a table or a heading
- Matching arbitrary phrases in prose, which wants a pattern skill instead
How to call
POST /v1/execute (requires authentication)
{
"skillKey": "productivity.todo_extract",
"input": {
"documentId": "release-notes",
"text": "# Release\n- [ ] Draft the changelog\n- [x] Tag the release\n"
}
}Examples
Release checklist with one box already ticked
{
"documentId": "release-notes",
"text": "# Release\n- [ ] Draft the changelog\n- [x] Tag the release\n"
}{
"summary": {
"itemCount": 2,
"checkedCount": 1,
"uncheckedCount": 1,
"nonTaskListItemCount": 0,
"maxDepthSeen": 0,
"depthClampedCount": 0,
"textTruncatedCount": 0,
"truncated": false
},
"items": [
{
"id": "release-notes:b7cde273a37783e2:0",
"ordinal": 0,
"depth": 0,
"state": "UNCHECKED",
"marker": "HYPHEN",
"text": "Draft the changelog",
"charStart": 10,
"charEnd": 35,
"lineStart": 2,
"lineEnd": 2,
"flags": []
},
{
"id": "release-notes:79cc6c7a03b3a75b:1",
"ordinal": 1,
"depth": 0,
"state": "CHECKED",
"marker": "HYPHEN",
"text": "Tag the release",
"charStart": 36,
"charEnd": 57,
"lineStart": 3,
"lineEnd": 3,
"flags": []
}
]
}Nested checklist filtered down to the open items
{
"stateFilter": "UNCHECKED",
"text": "- [ ] Ship the API\n - [x] Write the docs\n- Not a task"
}{
"summary": {
"itemCount": 1,
"checkedCount": 1,
"uncheckedCount": 1,
"nonTaskListItemCount": 1,
"maxDepthSeen": 1,
"depthClampedCount": 0,
"textTruncatedCount": 0,
"truncated": false
},
"items": [
{
"id": ":f47efc55f052a94b:0",
"ordinal": 0,
"depth": 0,
"state": "UNCHECKED",
"marker": "HYPHEN",
"text": "Ship the API",
"charStart": 0,
"charEnd": 18,
"lineStart": 1,
"lineEnd": 1,
"flags": []
}
]
}Recommended use cases
- Turn a Markdown planning document into structured tasks an agent can act on
- Diff two versions of a checklist and see which items really changed
Avoid for
- Extracting anything that is not a checkbox, such as a table or a heading
- Matching arbitrary phrases in prose, which wants a pattern skill instead
Related skills
Composable with
Safety & privacy
- Runs without calling any external service.
- Your payloads are never stored permanently.
- Telemetry captures metadata only — never your payload contents.
- We never train models on your payloads.
- No human reviews your payloads.