---
name: splitty-design
description: >-
  Design a splitty pipeline YAML file from a user's natural-language request.
  Use when the user describes an analysis goal but has not provided a pipeline
  file, or when they say "design a pipeline for X", "what pipeline would you
  use for Y", or "make a splitty pipeline that does Z". Outputs a validated
  pipeline.yaml. Does not run the pipeline.
---

# splitty-design

Translate a user request into a valid splitty pipeline YAML file.

## Inputs you have

- The user's natural-language description of the goal.
- The corpus / input source (file, glob, or `@stdin`).
- Optional constraints (output format, model preferences, parallelism limits).

## Procedure

### 1 — Read the schema and examples

You **must** read these before authoring:

- `${CLAUDE_PLUGIN_ROOT}/docs/pipeline-schema.md`
- At least one of:
  - `${CLAUDE_PLUGIN_ROOT}/pipelines/examples/map-reduce-summary.yaml`
  - `${CLAUDE_PLUGIN_ROOT}/pipelines/examples/classify-and-extract.yaml`
  - `${CLAUDE_PLUGIN_ROOT}/pipelines/examples/fan-out-fan-in.yaml`

Pick the example closest to the user's goal as your starting template.

### 2 — Decide the topology

Map the request to one of these patterns. If unsure, ask the user.

| Goal shape                                              | Topology                                                  |
|---------------------------------------------------------|-----------------------------------------------------------|
| Summarize / extract one thing per chunk → one report    | `map → terminal(custom)`                                  |
| Filter chunks, then expensive analysis on survivors     | `map(classify) → gate → map(extract) → terminal`          |
| Two independent analyses combined per chunk             | `map(A) ∥ map(B) → map(merge) → terminal`                 |
| Aggregate counts / structured records                   | `map(extract-json) → terminal(strategy: concat-json)`     |
| Iteratively refine a draft                              | `reduce(draft) → loop(critique→revise) → terminal`        |

### 3 — Pick chunker settings

| Strategy     | Use when                                                      |
|--------------|---------------------------------------------------------------|
| `paragraphs` | Prose, notes, long-form documents (default)                   |
| `lines`      | Logs, CSV-ish, line-oriented text                             |
| `tokens`     | Need consistent prompt sizing across chunks                   |
| `fixed`      | Binary-ish or unstructured streams                            |
| `none`       | Pipeline must see entire input as one chunk                   |

Default chunk sizes:
- paragraphs: `size: 2000` (chars), `overlap: 0`
- lines: `size: 200` (lines)
- tokens: `size: 1000`
- fixed: `size: 4000` (chars)

### 4 — Author each stage

For every `map`, `reduce`, and `custom`-strategy `terminal` stage, write:

- `id` — kebab-case, descriptive (`extract-entities`, not `s1`)
- `agent_def.system` — the **persona** in 1-3 sentences. Be specific about role
  and constraints (e.g., "You never invent facts", "You output strict JSON").
- `agent_def.tools` — almost always `[Read, Write]`. Add `Grep` / `Glob` only
  if the stage genuinely needs to look outside its input.
- `agent_def.model` — `haiku` for cheap classification, `sonnet` (default) for
  most analysis, `opus` only for hard synthesis at the terminal.
- `instructions` — the precise task: format, length, what to include, what to
  exclude. Include negative constraints (no prose, no commentary, no fences).
- `output_format` — `json` whenever downstream stages will programmatically
  consume the output. `markdown` only at the terminal.

For `gate` stages: write a `condition` that operates on JSON keys produced
upstream. Keep it simple — see `docs/pipeline-schema.md` for supported syntax.

For `terminal` with `strategy: concat | concat-json | deep-merge`: no
`agent_def` needed; the union is mechanical.

### 5 — Write the file

Save to `.splitty/pipelines/<name>.yaml` in the user's workspace. If the
directory does not exist, create it. Use the user's stated name or derive a
kebab-case one from the goal.

### 6 — Validate

Run:

```
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/splitty.py validate <path>
```

If validation fails, fix the issues and re-validate. Do not hand off an
invalid pipeline.

### 7 — Show the user

Print:

1. The path to the saved pipeline.
2. A short ASCII diagram of the topology.
3. The 1-line description of each stage (id + role).

Then ask: **"Run it now?"** Do not autorun unless the user said so explicitly
in their original request.

## Anti-patterns to avoid

- **One mega-stage** doing many things. Split into discrete filters, each with
  a single responsibility. The whole point of the plugin is composition.
- **Vague personas** like "you are a helpful assistant". Personas should
  declare a specific filtering role and its hard constraints.
- **Markdown output before the terminal.** Intermediate stages should output
  JSON whenever possible so downstream stages can consume them programmatically.
- **Fan-out without fan-in.** Every leaf must be a terminal. The validator
  enforces this; if you hit the error, add a synthesizer.
