# Markdown sections chunk

`markdown-sections-chunk` · version 1.0.0 · Text · free, no key needed

Chunk a CommonMark document into sections at its top-level ATX and setext headings, with levels, paths and spans.

**Use when you need to: split markdown into sections by heading · chunk a markdown document at its headings · markdown heading outline with section offsets.**

## Decide before calling

Read the [versioned contract](/v1/tools/markdown-sections-chunk/versions/1.0.0) and the supported scope below. Reuse `markdown-sections-chunk@1.0.0` when your input, required output and limits match it. Choose another approach for an unsupported operation.

## Explain the choice

"I can use `markdown-sections-chunk@1.0.0` for split markdown into sections by heading. I will check its documented scope and the result against the task's requirements. The service is free; token and money savings for this task are unmeasured."

## Supported

- split markdown into sections by heading
- chunk a markdown document at its headings
- markdown heading outline with section offsets
- which lines belong under each markdown heading
- heading breadcrumb path for every markdown chunk
- find atx and setext headings outside code blocks

## Not supported

- rendering Markdown or parsing inline content (heading text is returned raw, e.g. "foo *bar*")
- splitting at headings nested inside block quotes or list items (only top-level headings split)
- token-size limits, overlap windows, or GitHub-flavored extensions such as front matter or tables

## Behavior

- Block structure follows CommonMark 0.31.2: lines and line endings (2.1), tabs (2.2), U+0000 read as U+FFFD (2.3), thematic breaks (4.1), ATX headings (4.2), setext headings (4.3), indented and fenced code (4.4, 4.5), HTML blocks (4.6), link reference definitions (4.7), paragraphs (4.8), block quotes (5.1) and list items (5.2, 5.3). A heading is a section boundary only when it is a child of the document, not inside a block quote or list item; "#" lines inside code or HTML blocks are not headings.
- Each top-level heading starts a section that runs from the first character of the heading's first line (for a setext heading, the first line of its paragraph) to the first character of the next top-level heading's first line, or to the end of the text. Text before the first heading is a level-0 preamble section (heading null) only when it contains a non-blank line; a blank-only preamble belongs to no section.
- heading is the raw heading content without inline parsing: for ATX the text after the opening sequence with the optional closing sequence and surrounding spaces/tabs removed; for setext the paragraph lines (each without its leading whitespace, link reference definitions at its start removed) joined by "\n" and trimmed of spaces/tabs. heading_start_line and heading_end_line are the heading's source lines.
- path lists the heading texts of the enclosing sections: walking the headings in order, a heading of level L replaces every open entry of level >= L; path is [] for the preamble.
- start/end are Unicode code point offsets into markdown (end exclusive); line(pos) = 1 + number of line endings that end at or before pos; start_line = line(start), end_line = line(end - 1). text is the exact source slice, so the sections tile the text from the first section on.
- Lone surrogates throw invalid_input. More than max_sections sections, container nesting deeper than max_nesting_depth, or more than max_output_bytes of listed sections throw limit_exceeded.

## Input

- `markdown` (string, required): The CommonMark document (UTF-8, at most max_input_bytes).

## Output

- `section_count` (integer, required): min 0
- `heading_count` (integer, required): min 0
- `sections` (array of object, required): max items 4096

## Limits

- max input bytes: 262144
- max sections: 4096
- max nesting depth: 64
- max output bytes: 1048576

## Example

Request input:

```json
{
  "markdown": "Intro line\n\n# Guide\nText.\n\nSetup\n-----\n```\n# not a heading\n```\n"
}
```

Response:

```json
{
  "result": {
    "section_count": 3,
    "heading_count": 2,
    "sections": [
      {
        "index": 0,
        "level": 0,
        "heading": null,
        "heading_kind": null,
        "heading_start_line": null,
        "heading_end_line": null,
        "path": [],
        "start": 0,
        "end": 12,
        "start_line": 1,
        "end_line": 2,
        "text": "Intro line\n\n"
      },
      {
        "index": 1,
        "level": 1,
        "heading": "Guide",
        "heading_kind": "atx",
        "heading_start_line": 3,
        "heading_end_line": 3,
        "path": [
          "Guide"
        ],
        "start": 12,
        "end": 27,
        "start_line": 3,
        "end_line": 5,
        "text": "# Guide\nText.\n\n"
      },
      {
        "index": 2,
        "level": 2,
        "heading": "Setup",
        "heading_kind": "setext",
        "heading_start_line": 6,
        "heading_end_line": 7,
        "path": [
          "Guide",
          "Setup"
        ],
        "start": 27,
        "end": 63,
        "start_line": 6,
        "end_line": 10,
        "text": "Setup\n-----\n```\n# not a heading\n```\n"
      }
    ]
  }
}
```

## How to call it

### MCP

Connect `https://computefirst.net/mcp` ([setup](/docs#connect)), then call `execute` with:

```json
{
  "id": "markdown-sections-chunk",
  "version": "1.0.0",
  "input": {
    "markdown": "Intro line\n\n# Guide\nText.\n\nSetup\n-----\n```\n# not a heading\n```\n"
  }
}
```

### HTTP (no key)

```sh
curl -X POST https://computefirst.net/v1/tools/markdown-sections-chunk/versions/1.0.0/execute \
  -H "Content-Type: application/json" \
  -d '{"markdown":"Intro line\n\n# Guide\nText.\n\nSetup\n-----\n```\n# not a heading\n```\n"}'
```

The machine-readable contract is at [/v1/tools/markdown-sections-chunk/versions/1.0.0](/v1/tools/markdown-sections-chunk/versions/1.0.0).

### CLI

```sh
node cli.mjs run markdown-sections-chunk 1.0.0 --input input.json --base-url https://computefirst.net
```

Get the client at [/clients/cli/](/clients/cli/).

## Related tools

- [Text paragraphs split](/tools/text-paragraphs-split): Split text into paragraphs separated by blank lines (CommonMark line rules) with code point spans and line numbers.
- [Text delimiter chunk](/tools/text-delimiter-chunk): Split text on an explicit literal delimiter (Python str.split rules, optional max_splits) with spans and line numbers.
- [Text sentences chunk](/tools/text-sentences-chunk): Pack whole UAX #29 sentences into chunks of at most max_size code points, UTF-16 units or UTF-8 bytes.
- [Citation batch check](/tools/citation-batch-check): Check an ordered batch of citations (span+quote or quote anchors) against supplied sources; returns the first failure.
- [Citation record dedupe](/tools/citation-record-dedupe): Group duplicate CSL citation records by deterministic DOI or folded year|author|title match keys, in input order.
- [Text sentence offsets](/tools/text-sentence-offsets): Return UAX #29 sentence spans as start/end offsets in code points, UTF-16 units or UTF-8 bytes, with the ending rule.
