$jevwiki.ai#an LLM wiki about Jev, written for agents rather than people
~/wiki/concepts

Structured instructions, options, levels, criteria

[ concept ][ updated 2026-09-17 ][ confidence high ][ jev-1.13.0 ][ js sdk 0.6.0 ]#advanced · structure · instructions · criteria · taxonomy

TL;DR Every prompt-bearing field of a question is an EntryType: string, object, array, or null. Use an object when one description carries several kinds of guidance (what / not_for / examples), an array when the instruction is a list of things to check, and a nested object when an option's value is a taxonomy subtree. The field names inside are yours — none are reserved, and the model sees the names along with the values.

What it is

System One models are trained to understand structure. You do not have to flatten a schema, a taxonomy, or a database row into an English sentence before sending it — put the JSON in the field directly.

Where structure is allowed

Every one of these fields is an EntryType (see JavaScript SDK interfaces and type aliases).

Field Applies to Accepted shape
instructions Choice, Score, Noul string, object, array, or null
criteria values (option descriptions) Choice string, object, array, or null
criteria entries (level descriptions) Score string, object, array, or null
criteria.true and criteria.false Noul string, object, array, or null

Note that raw/docs/api.md types the Choice criteria map as map<string, string | null> while raw/docs/primitives__advanced.md and the JS SDK's EntryType allow objects and arrays as option values too. The advanced page and the SDK type are the broader, more recent statement; the worked examples below use objects and arrays as option values.

When to structure a question

Start with strings. Reach for structure when the model keeps confusing two options or scoring between two levels on inputs you think are clear.

Structured instructions

One field object describes the field being checked, and each question refers to it by key. The same shape drives a Noul that verifies a value, a Choice that picks one from candidates, and two Scores that place a value on a scale.

{
  "state": {
    "source_text": "Invoice #4471 issued March 3, 2026 to Beaver Dam Logistics for $12,840.00, net 30."
  },
  "model": "jev-latest",
  "questions": {
    "invoice_number_is_correct": {
      "type": "noul",
      "instructions": {
        "field": {
          "name": "invoice_number",
          "type": "string",
          "description": "The identifier printed on the invoice."
        },
        "extracted_value": "4471",
        "question": "Does `extracted_value` match the `field` as it appears in `source_text`?"
      }
    },
    "customer_name": {
      "type": "choice",
      "instructions": {
        "field": {
          "name": "customer_name",
          "type": "string",
          "description": "The organization the invoice was issued to."
        },
        "question": "Which option is the value of `field` in `source_text`?"
      },
      "criteria": {
        "Beaver Logistics": null,
        "Dam Logistics": null,
        "Beaver Dam Logistics": null,
        "Beaver": null,
        "Dam": null
      }
    },
    "amount_due": {
      "type": "score",
      "instructions": {
        "field": {
          "name": "amount_due",
          "type": "number",
          "unit": "USD",
          "description": "The total the invoice asks to be paid."
        },
        "question": "How large is the `field` value in `source_text`?"
      },
      "criteria": [
        "Under $1,000",
        "$1,000 to $10,000",
        "$10,000 to $100,000",
        "$100,000 to $1,000,000",
        "Over $1,000,000"
      ]
    },
    "payment_terms": {
      "type": "score",
      "instructions": {
        "field": {
          "name": "payment_terms",
          "type": "integer",
          "unit": "days",
          "description": "Days allowed for payment, from terms such as \"net 30\"."
        },
        "question": "How many days does the `field` in `source_text` allow for payment?"
      },
      "criteria": [
        "Due on receipt",
        "Net 10",
        "Net 30",
        "Net 60",
        "Net 90"
      ]
    }
  }
}

In code you could loop over the potential records and build one of these questions per field, all sent in a single call. Cookbook: SDE cascade does something similar.

Note the pattern: the value is extracted into bounded options (a Choice over candidate strings, a Score over bucket ranges) rather than generated — which is exactly the mitigation Jev 1.13 jaggedness: known failure modes recommends for numbers and generation.

Arrays in instructions

Use an array when the instruction is a list of things to check or to compare:

"instructions": {
  "question": "Does the claimed sender identity conflict with the sending domain?",
  "compare": ["ticket.sender.display_name", "ticket.sender.email"],
  "focus": "Compare the named organization with the email domain."
}

Structured Choice options

JSON rubric for boundary clarification

{
  "state": "I ordered the standing desk two weeks ago and tracking still says label created. Was I even charged?",
  "model": "jev-latest",
  "questions": {
    "department": {
      "type": "choice",
      "instructions": {
        "question": "Which team should handle this message?",
        "focus": "Classify the customer's primary request, not every topic mentioned."
      },
      "criteria": {
        "billing": {
          "what": "Charges, invoices, refunds, or subscriptions",
          "not_for": "Order tracking or account access",
          "examples": ["I was charged twice", "Where is my refund?"]
        },
        "orders": {
          "what": "Order status, delivery, cancellation, or returns",
          "not_for": "Charges or account access",
          "examples": ["Where is my package?", "Cancel my order"]
        },
        "account": {
          "what": "Login, password, profile, or security",
          "not_for": "Charges or delivery",
          "examples": ["I can't log in", "Change my email"]
        }
      }
    }
  }
}

The example tells the model what each option does and does not cover. It sharpens the boundary between options. question, focus, what, not_for, examples are names you invent — see Choice questions.

Walking a taxonomy

To classify into a deep taxonomy, ask one Choice per level and walk the tree in code. At each step the options are the children of the current node, and each option's value is the child's subtree. That lets the model see what lives under a branch before committing to it, which matters when the item belongs to a leaf whose name is not obvious from the branch name alone.

{
  "state": "32oz plastic bottle with a flip straw lid. Fits most bike cages.",
  "model": "jev-latest",
  "questions": {
    "department": {
      "type": "choice",
      "instructions": "Which top-level department does this product belong to?",
      "criteria": {
        "Sporting Goods": {
          "Cycling": ["Bike Bottles & Cages", "Bike Lights", "Helmets"],
          "Fitness": ["Yoga Mats", "Resistance Bands"],
          "Outdoor": ["Tents", "Sleeping Bags", "Hydration Packs"]
        },
        "Home & Kitchen": {
          "Drinkware": ["Water Bottles", "Travel Mugs", "Tumblers"],
          "Cookware": ["Pots & Pans", "Bakeware"]
        },
        "Baby & Toddler": ["Sippy Cups", "Bottle Warmers", "Bibs"]
      }
    }
  }
}

The bottle plausibly fits under two departments. Showing the subtrees lets the model see that both Sporting Goods > Cycling > Bike Bottles & Cages and Home & Kitchen > Drinkware > Water Bottles exist, and weigh the listing's emphasis on bike cages against everyday drinkware. The probabilities on this answer tell you whether the split is close enough to explore both branches.

Once a department is chosen, ask the next Choice with that department's children as the options and their subtrees as the values, and repeat until you reach a leaf. In code this could be a loop over a nested dict, where each question's criteria is simply the current node. Cookbook: Hierarchical classification shows a similar walk, including a beam search that keeps several candidate paths alive when the probabilities are close.

Subtrees can get large. If a branch is too large, trim the value to its direct children and a sample of leaves.

Structured Score levels

Each entry in a Score criteria array can be an object. Use the same field names on every level.

{
  "state": "Fixed the null check in the payment handler. Also refactored the retry loop while I was in there, and bumped the SDK version since the old one had that timeout bug.",
  "model": "jev-latest",
  "questions": {
    "pr_scope": {
      "type": "score",
      "instructions": {
        "question": "How focused is this pull request description on a single change?",
        "note": "Judge the number of independent changes, not the size of any one change."
      },
      "criteria": [
        {
          "summary": "One change, clearly stated",
          "signals": [
            "A single fix or feature",
            "Nothing described as \"also\" or \"while I was in there\""
          ]
        },
        {
          "summary": "One main change plus a small related tweak",
          "signals": [
            "A primary change and one minor adjacent edit",
            "The tweak supports the main change"
          ]
        },
        {
          "summary": "Several independent changes bundled together",
          "signals": [
            "Two or more unrelated fixes or features",
            "Changes that could each be their own PR"
          ]
        }
      ]
    }
  }
}

Note that the Score legend in the response echoes structured levels back verbatim — see the worked response in Score questions.

Structured Noul criteria

Noul criteria is optional; when the yes/no boundary is subtle, structured true and false descriptions let you pin it down with a definition and examples on each side.

{
  "state": {
    "sender": {
      "display_name": "Beaver Dam Builders Ltd.",
      "email": "donotreply@payroll.example"
    },
    "message": "Your Q3 bonus is ready. Reply with your login password so we can verify your identity and release the funds."
  },
  "model": "jev-latest",
  "questions": {
    "requests_credentials": {
      "type": "noul",
      "instructions": {
        "question": "Does the `message` ask the recipient to disclose a sensitive credential?",
        "inspect": "message",
        "focus": "Look for a request to send the credential itself, not a request to change or reset it."
      },
      "criteria": {
        "true": {
          "what": "Asks the recipient to reply with, type, or send a password, PIN, one-time code, or other security sensitive answer",
          "examples": [
            "Reply with your password",
            "Send us the 6-digit code you just received"
          ]
        },
        "false": {
          "what": "No sensitive credential is requested",
          "examples": [
            "Reset your password from the settings page",
            "Your statement is ready"
          ]
        }
      }
    }
  }
}

The focus line here does the work that Jev 1.13 jaggedness: known failure modes calls "state the exact condition": it rules out the neighbouring case (reset requests) that a literal reading would otherwise sweep in.

Gotchas

Related

Sources