Primitive
Split
Give Wity a thread, a contract, a chat export or a log, and say what one item is. You get back every email, clause, message or entry as its own piece, with exact character positions, in under a tenth of a second. Nothing is summarised, reworded or dropped: every item is a slice of your original text.
Signature
split(text, unit)
Returns
the text, cut into whole items
Use it for
One document → the things inside it.
New in wity-1
Why it matters#
Real inputs arrive in bundles. A custodian export holds hundreds of emails, a contract fifty clauses, a support log thousands of entries. Your decisions are about one of them at a time: is this email privileged, is this clause one-sided, does this entry need a human. Cutting by size splits sentences in half and glues two emails together; cutting by regex breaks on the first unusual header. Split cuts where the meaning changes.
A custodian export, “one item per email”
→ 7 emailsevery header intact
A services agreement, “one item per clause”
→ 14 itemstitle, parties, 12 clauses
A team chat export, “one item per message”
→ 12 messagesone per line
One call#
Send the text and the unit in plain words. The response lists the items in document order; each one is exactly text[start:end] of what you sent, with surrounding whitespace trimmed.
From: dana.whitlock@kestrelfoods.comSubject: Batch 2207 seal testTeam, the seal integrity test on batch 2207 failed at 3 of 20 sample points. Can we hold the batch?From: marcus.reyes@kestrelfoods.comSubject: RE: Batch 2207 seal testWe can't hold it, the order ships Monday. Ship it and we'll retest next week.From: events@kestrelfoods.comSubject: Friday social - pizza and quiz nightReminder: quiz night in the canteen at 5:30.
curl https://api.wity.alphanimble.com/v1/split \-H "Authorization: Bearer $WITY_API_KEY" \-H "Content-Type: application/json" \-d '{ "text": "From: dana.whitlock@kestrelfoods.com\nSubject: Batch 2207 ...", "split": "one item per email" }'
{"items": [{ "start": 0, "end": 186, "text": "From: dana.whitlock@kestrelfoods.com\nSubject: Batch 2207 seal test\nTeam, the seal ..." },{ "start": 188, "end": 361, "text": "From: marcus.reyes@kestrelfoods.com\nSubject: RE: Batch 2207 seal test\nWe can't hold ..." },{ "start": 363, "end": 499, "text": "From: events@kestrelfoods.com\nSubject: Friday social - pizza and quiz night\n..." }],"how": "model","timing_ms": { "total": 231 },"usage": { "input_tokens": 512, "output_tokens": 0 }}
Split, then decide on every piece#
This is the pattern Split was built for. Cut the bundle into items, ask one typed question about each item in parallel, and keep the ones that pass, still in document order and still pointing at the exact place in the original. Relevance, privilege, risk, routing: whatever you would ask about one item, now asked about all of them.
import os, requestsfrom concurrent.futures import ThreadPoolExecutorAPI = "https://api.wity.alphanimble.com"H = {"Authorization": f"Bearer {os.environ['WITY_API_KEY']}"}http = requests.Session()def split(text, how):r = http.post(f"{API}/v1/split", headers=H, json={"text": text, "split": how}, timeout=120)r.raise_for_status()return r.json()["items"]def is_yes(item, question):r = http.post(f"{API}/v1/systemone", headers=H, timeout=60, json={"state": item["text"], "reasoning": "off","questions": {"q": {"type": "noul", "instructions": question}}})r.raise_for_status()return r.json()["answers"]["q"]["noul"] # P(yes)emails = split(export_text, "one item per email")with ThreadPoolExecutor(8) as pool:p = list(pool.map(lambda e: is_yes(e, "Is this email about the failed seal test?"), emails))relevant = [e for e, py in zip(emails, p) if py >= 0.5] # in document order, with exact offsets
Each item is an ordinary decision, so everything in Probabilities & confidence applies: act on the sure ones, route the close ones to a person.
Say what an item is#
In plain words
"one item per email", "one item per clause", "one item per message", "one item per news story", "one item per changelog entry": any unit you can name. A few structures are cut by rule, instantly and exactly:
sentence,line(alsologentries),bullet/list item,paragraph(blank-line separated)speaker turn: consecutive lines by the same speaker stay together
As a split spec
When you know what your data looks like, say so. A spec gives the unit plus up to eight short descriptions each of where items start, what stays together and where an item never starts. It sharpens the cuts on formats Wity would otherwise have to guess at.
{"text": "...","split": {"unit": "email","starts_at": ["a 'From:' header line"],"keep_together": ["the headers, body, quoted reply and signature of one email"],"never_split": ["at blank lines inside an email"]}}
Teach it your format#
When your documents are cut a particular way (your ticket export, your firm's contract template, a log format nobody else uses), show Wity how. Make a split skill with one or more example splits: the text and its items (or the character offsets where items start). Wity learns from them in seconds and then splits documents like them your way. In the console, split a document, fix the cuts where they are off, and click Teach this split.
curl https://api.wity.alphanimble.com/v1/skills \-H "Authorization: Bearer $WITY_API_KEY" \-H "Content-Type: application/json" \-d '{"name": "our-tickets","split": "one item per ticket","examples": [{ "text": "#4471 Login fails\nOpened by ana, 09:02\n...\n#4472 Invoice question\n...","items": ["#4471 Login fails\nOpened by ana, 09:02\n...", "#4472 Invoice question\n..."] }]}'# a few seconds later, split with it like any splitcurl https://api.wity.alphanimble.com/v1/split -H "Authorization: Bearer $WITY_API_KEY" -H "Content-Type: application/json" \-d '{ "text": "...", "skill": "our-tickets" }'
- One example already helps where the plain instruction cuts your format wrong. Splitting JSON, INI, XML and key-value data into fields, one example lifted accuracy on other documents of the same kind from 0.73 to 0.99. Across 14 unusual formats, a skill switched itself on after one example in half the cases, and there it went from 0.68 to 0.91.
- It checks itself. A skill is used only if it beats the plain instruction on examples it did not learn from: with two or more, each one held back in turn; with one, it learns from the first half of the items and is checked on the second. Where the plain instruction already cuts well, the skill stays off and splits exactly as before (
active,qualityon the skill). Every split with a skill says which version answered and how:"skill": {"name", "version", "answered_by", "active"}. - Examples of the same kind teach the most. A skill learns your format, not a new instruction: keep one skill per kind of document.
| step | typical time |
|---|---|
| Make a skill, add examples | returns at once |
| Learn from one example | 2 to 4 seconds |
| Learn from three examples | about 10 seconds |
| A split with a skill | the same as without |
Split skills live with your other skills: list, rename, add or delete examples with the skills API, or in the console's Skills & sessions page.
How good it is#
Measured on the live splitter (19 October 2026) against hand-labelled item boundaries: 70 real documents (GitHub and Hacker News threads, IRC logs, mailing lists, server logs, changelogs, contract provisions and news feeds) and about 390 test documents in formats from emails to JSON, XML and config files:
Good to know#
- Up to 60,000 characters per request. Long texts are read in windows, so a long list costs about the same per character as a short one.
- Cuts fall at line breaks or after a sentence (
. ! ? ; : ) ]and a space). Fields inside one line, like{"a": 1, "b": 2}, are not cut apart. - Where it is weakest: formats it has never seen, cut an unusual way. That is what split skills are for.
- Billing:
usage.input_tokenscounts the text once plus a few hundred tokens of instructions (texts over about 5,000 characters are read in overlapping windows and count up to about twice), at the usual $0.042 per million. Requests that fail cost nothing. - Full request and response reference: POST /v1/split.
