Skip to main content
T2 chain · legal / compliancemodel: ollama/llama3.1 at the envelope means every model call in this file runs on your own hardware. For a contract, that’s not a preference — it’s the requirement. Belt-and-braces: schema: at infer time, nika:validate after, nika:assert as the hard gate.

The job

Outside counsel takes a week. Pasting the contract into a cloud chatbot takes your confidentiality with it. This workflow extracts every risk-bearing clause — verbatim quotes, typed risk levels — locally, re-validates the extraction, and refuses to write the memo if the data doesn’t hold.

The shape

The file

t2-contract-guard.nika.yaml
nika: v1
workflow: contract-guard
description: "Local-model clause extraction → schema gate → risk memo"

model: ollama/llama3.1      # the whole review runs offline · zero cloud

vars:
  contract_path:
    type: string
    required: true
    description: "Path to the contract (markdown or plain text)"

tasks:
  - id: contract
    invoke:
      tool: "nika:read"
      args: { path: "${{ vars.contract_path }}" }

  - id: clauses
    depends_on: [contract]
    infer:
      prompt: |
        Extract every risk-bearing clause from this contract ·
        ${{ tasks.contract.output }}
        Quote each clause verbatim · classify its risk.
      schema:
        type: object
        required: [clauses]
        properties:
          clauses:
            type: array
            items:
              type: object
              required: [quote, type, risk]
              properties:
                quote: { type: string }
                type: { type: string, enum: [liability, termination, ip, payment, data, other] }
                risk: { type: string, enum: [low, medium, high] }

  - id: check
    depends_on: [clauses]
    invoke:
      tool: "nika:validate"
      args:
        data: "${{ tasks.clauses.output }}"
        format: json
        schema:
          type: object
          required: [clauses]
          properties:
            clauses:
              type: array
              minItems: 1

  - id: gate
    depends_on: [check]
    invoke:
      tool: "nika:assert"
      args:
        condition: "${{ tasks.check.output.valid == true }}"
        message: "Clause extraction failed the schema gate — refusing to write the memo"

  - id: memo
    depends_on: [clauses, gate]
    infer:
      prompt: |
        Write a one-page risk memo from these clauses ·
        ${{ tasks.clauses.output.clauses }}
        Order by risk · high first · cite the quoted text.

  - id: save
    depends_on: [memo]
    invoke:
      tool: "nika:write"
      args:
        path: "./legal/risk-memo.md"
        content: "${{ tasks.memo.output }}"
        create_dirs: true

outputs:
  clauses:
    value: ${{ tasks.clauses.output.clauses }}
    type: array
    description: "Typed risk-bearing clauses, verbatim quotes"
  memo: ${{ tasks.memo.output }}

How it works

1

Sovereignty is one line

The envelope model: points at Ollama. Same file, same schema, same everything — just no cloud. Swap back to a cloud provider for non-sensitive documents; the workflow doesn’t change shape.
2

validate re-checks what schema promised

nika:validate runs the extraction against a second, stricter schema (minItems: 1) and returns {valid, errors} — belt and braces for legal-grade output.
3

assert is the fail-fast guard

when: skips; nika:assert FAILS. A memo built on a bad extraction is worse than no memo — so the gate throws, loudly.

Constructs you just used

ConstructWhereReference
local provider (ollama/…)envelope model:Providers
nika:validatecheckBuiltins
nika:assert vs when:gateBuiltins
verbatim-quote schemaclausesThe 4 verbs

Make it yours

  • Compare against your clause playbook: nika:read the playbook + a second infer that flags deviations.
  • Batch a folder of NDAs: nika:glob + for_each (Localization factory shows the chained fan-out).
  • HR version: same shape over candidate agreements or policy docs — sensitive data, local model, typed findings.

Level up · T3 fan-out

Next tier: collections the workflow discovers at runtime, processed in parallel with retry and a leash.