the skeleton register
document-to-fields
Your intent sounds like: extract fields from a document and keep the evidence One of 14 skeletons the pack ships, green as-is under nika check. Fill the # SLOT: lines, repair from the fix lines, re-check. Machines read the catalog; the binary lists them with nika new '?'.
- 3SLOT pointsthe only lines you edit
- 4patterns lockedarrive correct, stay correct
- 0tools grantedthe minimum for the job
- 7f05592bsha-pinnedre-hashed on every test run
the plan
derived from the file, never drawn by handnormalize_documentinvoke
document_nonemptyinvoke
extractinfer
anchors_presentinvoke
compiledinvoke
the file, whole
conformance-gated upstream on every spec pushdocument-to-fields.nika.yamlsource
# SPDX-License-Identifier: Apache-2.0# yaml-language-server: $schema=https://nika.sh/spec/v1/workflow.schema.json## TEMPLATE · document-to-fields · source text → anchored facts → nonempty proof.## The source is trimmed and proved nonempty before inference. The extraction# is typed, and every value carries the exact source fragment that supports it.# An empty extraction is refused before it can look like a successful read.## Needs · nothing. Runs offline in an empty directory with mock/echo.# Run · nika run <file> --model mock/echonika: document-to-fieldsmodel: mock/echo # SLOT: replace with a local or hosted seatconst: document: | # SLOT: replace with content from nika:read or nika:fetch Invoice INV-204 Supplier: Northwind Tools Total: EUR 84.50 Rehearsal marker: mockpermits: tools: ["nika:jq", "nika:assert"]tasks: normalize_document: invoke: tool: nika:jq args: input: ${{ const.document }} expression: 'gsub("^\\s+|\\s+$"; "")' document_nonempty: with: document: ${{ tasks.normalize_document.output }} invoke: tool: nika:assert args: condition: ${{ size(with.document) > 0 }} message: "Document is empty after whitespace is trimmed" extract: with: document: ${{ tasks.normalize_document.output }} after: document_nonempty: success infer: max_tokens: 600 # SLOT: extraction spend ceiling prompt: | Extract only facts explicitly present in this document. For every value, copy the shortest exact source fragment that anchors it. ${{ with.document }} schema: type: object additionalProperties: false required: [fields] properties: fields: type: array minItems: 1 items: type: object additionalProperties: false required: [name, value, anchor] properties: name: { type: string, minLength: 1 } value: { type: string, minLength: 1 } anchor: { type: string, minLength: 1 } anchors_present: with: fields: ${{ tasks.extract.output.fields }} document: ${{ tasks.normalize_document.output }} invoke: tool: nika:jq args: input: { fields: "${{ with.fields }}", document: "${{ with.document }}" } expression: '. as $root | ($root.fields | length) > 0 and all($root.fields[]; . as $field | (.name | length) > 0 and (.value | length) > 0 and (.anchor | length) > 0 and ($root.document | contains($field.anchor)))' compiled: with: anchors_present: ${{ tasks.anchors_present.output }} invoke: tool: nika:assert args: condition: ${{ with.anchors_present }} message: "Document extraction returned no anchored fields"outputs: fields: ${{ tasks.extract.output.fields }}sha256 7f05592b930782fd…. The copy above re-hashes to its pin on every test run (a copy is re-provable, never trusted). Source: document-to-fields.nika.yaml in the spec pack · open it in the playground →
the patterns it locks
`structured-extraction` | `documents` | trimnonempty assertiontyped fieldsexact source anchors
cross-references
Scaffold it locally: nika new document-to-fields my-flow.nika.yaml. Try the shape in the playground, or walk the showcase for the same patterns on real work. Read the spec →