LIM Nano

Large Intention Model

Released Serving since 2026-09-13 Intention v1.0.0

Version 1.0.0 · Updated 2026-09-16 · LIM · Model 03 / 05

← Overview page

On this page

Overview #

LIM Nano reads the last few lines of a conversation and says whether the next reply is fine to give, needs a nudge, or should stop. You give it the recent turns as plain text; it gives back the same labels and suggested lines as its larger siblings. Use it when memory is tight and a smaller weight file matters more than the last bit of accuracy.

LIM Nano (Large Intention Model; “Nano” denotes the 256-wide configuration) is a conversation-intention classifier: a small model a host application runs before its responder to decide whether to allow, steer or abort a reply. It reads a short window of the conversation — the last three turns plus the current request — and returns four labels with confidences: trajectory (where the conversation is heading), action (allow, steer or abort), harm (which harm category, if any, the window resembles) and steer (what kind of redirection to suggest). A fixed set of decision rules turns the raw head outputs into the final action, and on steer or abort the model attaches a suggested short reply that the host is free to replace.

LIM Nano is the smallest intention model in the series and the original member of the LIM line: the 256-wide network that LIM widened to 512. It shares its input contract, its four label vocabularies, its decision rules and its output shape with LIM and with ELIM, the family default; the three differ only in the network in the middle. LIM Nano hashes character and word n-grams into one shared feature bag, averages the resulting 256-wide embeddings, and passes them through two plain GELU layers. At 4,338,995 parameters it carries roughly half of LIM’s parameters and half its weight file, and a third of ELIM’s.

Because the three models agree on everything except the backbone, switching to LIM Nano changes the model’s reading of a window, not the host’s policy. The same thresholds apply, the same greeting and task bypasses apply, and the same suggested replies are produced. The Falcon API loads LIM Nano from its own bundle — the lim-nano directory’s lim.bin, 17.4 MB — and keeps it resident beside ELIM and LIM, so a request selects it by name with model: "lim-nano" on the same route.

Intended use #

  • A pre-response intention check in a chat-style host, run on every user turn before the responder is called, where resident memory is the binding constraint.
  • Routing and triage: the trajectory label tells the host which task a request belongs to (weather, reminders, transit, research, …) so it can dispatch without a larger model.
  • Embedded or single-process hosts that want the intention vocabulary in a 17.4 MB bundle rather than 35.8 MB (LIM) or 52.8 MB (ELIM).
  • A reference point for the LIM line: the same trainer, generator and objective as LIM at the narrower width.

Out of scope #

  • Writing or rewriting the reply — LIM Nano classifies; the responder writes.
  • Filtering the responder’s output; the model only ever sees the user’s side of the window plus up to two earlier turns.
  • Acting as a safety system of record: the labels are advisory signals to combine with the host’s own checks.
  • Languages other than English, long documents, or anything longer than a 1,500-character window.

Choose LIM Nano when #

  • Memory matters more than backbone capacity: you want the intention vocabulary, the window contract and the decision rules in the smallest resident footprint the family offers.
  • The hosted route is enough: /v1/intention with model: "lim-nano" scores with LIM Nano; weights are not distributed during the private preview.
  • Otherwise choose LIM, the same single-bag design at twice the width, or ELIM, the family default, whose separate character and word bags and deeper residual head were designed to be more tolerant of misspellings and very short requests. Choose LIM3D or LIM3D-XL when the input is a scene sketch and a movement track rather than a conversation.

Architecture #

Parameters4,338,995
Weightslim.bin — 17.4 MB, float32, 13 tensors
Hash buckets16,384 (FNV-1a, shared by character and word n-grams)
Embedding width256
BackboneTwo 256 × 256 GELU layers, no residual connections
Headstrajectory 32 · action 3 · harm 8 · steer 8
Feature cap2,048 hashed features per window
WindowLast three turns plus the current request, ≤ 1,500 characters; n-grams over the last 360
RuntimeIn-process, CPU, synchronous

LIM Nano has no tokeniser and no vocabulary table. The window is lower-cased and turned into one list of hashed features: every character 3-gram and 4-gram over the last 360 characters, followed by every word unigram and bigram over tokens matching [a-z0-9']+, each hashed with FNV-1a into one of 16,384 buckets. The list is capped at 2,048 features. This is the same feature scheme as LIM, bucket for bucket: the two models differ only in the width of the table the features look up.

The backbone is a mean-pooling embedding bag of shape 16,384 × 256: every hashed feature looks up a 256-wide vector and the vectors are averaged into one. Two fully connected 256 × 256 layers with GELU activations follow, with no residual connections and no normalisation. The pooled and transformed 256-wide vector is then read by four independent linear heads: trajectory (32 classes), action (3), harm (8) and steer (8). Softmax over each head gives the label and its confidence. The 32-class trajectory head includes 27 documented labels; the remainder are host-specific and are not part of the documented vocabulary. The full label sets are listed under Inputs & outputs and on Output vocabularies.

The weights bundle holds 13 named tensors — embed.weight, fc1.weight, fc1.bias, fc2.weight, fc2.bias and a weight and bias for each of the four heads — totalling 4,338,995 float32 parameters. The 16,384 × 256 embedding table accounts for 4,194,304 of them; the remaining 144,691 are the two hidden layers and the heads. Halving the width from 512 to 256 halves the table and quarters the hidden layers, which is why the bundle is 17.4 MB against LIM’s 35.8 MB.

What is deliberately absent: no attention, no recurrence, no positional signal beyond what the n-grams carry, and no vision — LIM Nano never sees pixels, audio or anything but the window text. Word order is only captured to the extent that bigrams and character 4-grams capture it.

Comparison #

LIM NanoLIMELIM
RoleAlternate (standard LIM)Default on the route
Parameters4,338,9958,940,08313,193,523
Weights on disk17.4 MB35.8 MB52.8 MB
Feature bagsOne shared bag (characters then words)One shared bag (characters then words)Two bags: characters 384-wide, words 384-wide
Hidden layers2 × 256, GELU, no residuals2 × 512, GELU, no residuals3 × 384, GELU, residual on layers 2 and 3
Heads and vocabulariesIdenticalIdenticalIdentical
Decision rules and bypassesIdenticalIdenticalIdentical
Window contractIdenticalIdenticalIdentical
Training rows48,000 synthetic, seed 7, 6 epochs96,000 synthetic, seed 13, 10 epochs80,000 synthetic, seed 7, 8 epochs
Held-out accuracy (four heads)1.0001.0001.000
Hosted routeYes, with model: "lim-nano"Yes, with model: "lim"Yes, default

All three models score 1.000 on their own synthetic held-out splits, so there is no measured accuracy gap between them. The ordering Nano → LIM → ELIM is a capacity ordering — table width, hidden width, depth and bag count — not a measured ranking.

Inputs & outputs #

Input #

FieldTypeRequiredDescriptionLimit
textstringYesThe current request. Over the Falcon API it becomes a one-line window — U: followed by the text; in-process callers supply history separately.64 KB request body; the window is truncated to 1,500 characters
modelstringNo"lim-nano" selects LIM Nano; "lim" selects LIM; "elim" or absent selects ELIM. Any other value answers 400 unknown_model.one of elim, lim, lim-nano
historyarray of turnsNoIn-process only: prior turns as {role: "user" | "model", text}. The last three are kept; responder turns that echo an earlier safety notice are dropped.last three turns

LIM Nano scores a conversation window: one string of up to 1,500 characters built from at most the last three turns plus the current request, one turn per line, each prefixed with U: for the user or A: for the responder. Responder turns that echo an earlier safety notice are dropped before the window is built, so the model judges the user’s intent rather than its own previous advice. Over the Falcon API no history is passed, so the window is a single line: U: followed by the request text.

A three-turn window as the in-process runtime formats it; its current request is the one the API example scores, and the steer result under Output is the shape it returns:

text
U: i've been dizzy since lunch
A: sorry to hear that. is it getting better or worse?
U: chest pain and i can't breathe

Limits and frame:

  • Window length is capped at 1,500 characters; anything beyond that is cut from the end.
  • Character n-grams are taken from the last 360 characters only, so the most recent turn carries most of the character-level signal. Word n-grams cover the whole window.
  • At most 2,048 hashed features enter the model; longer windows are truncated at the feature level too.
  • Text is lower-cased before hashing. Punctuation contributes to character n-grams but not to word n-grams.
  • Requests with no text at all are rejected by the Falcon API with text_required; in-process, an empty window still produces a (meaningless) result.

Two rules answer before any forward pass and are reported with model: "bypass": a greeting bypass (hi, thanks, how are you, …) returns smalltalk / allow, and a task bypass for requests that plainly name an everyday host task (a reminder, a weather or transit lookup, an order, a layout question) returns help / allow. These rules exist because a short intention classifier can mislabel “order sushi” as a scam or “which way is the door” as a crisis.

Output #

trajectory 27 labels

  • continue
  • switch_topic
  • research
  • reminder
  • health
  • medical_emergency
  • crisis
  • crisis_method
  • crime
  • child_sexual
  • scam_assist
  • scam_check
  • jailbreak
  • secrets
  • image
  • slides
  • transit
  • order
  • calendar
  • maps
  • weather
  • sports
  • news
  • media
  • smalltalk
  • help
  • unknown

action 3 labels

  • allow
  • steer
  • abort

harm 8 labels

  • none
  • crisis
  • medical
  • crime
  • child_sexual
  • scam
  • jailbreak
  • secrets

steer 8 labels

  • none
  • crisis_line
  • medical_911
  • scam_warn
  • jailbreak_ignore
  • secrets_drop
  • refocus
  • confirm_destructive

Every result carries the four labels, three confidences, the decision rule, the model that ran and, on steer or abort, a suggested reply. The model field reads lim-nano when LIM Nano scored the window. A steer result for a medical emergency:

json
{
  "trajectory": "medical_emergency",
  "action": "steer",
  "harm": "medical",
  "steer": "medical_911",
  "pTrajectory": 1,
  "pAction": 1,
  "pHarm": 1,
  "rule": "traj-steer≥0.58",
  "model": "lim-nano",
  "message": "…"
}

An allow result carries no message:

json
{
  "trajectory": "weather",
  "action": "allow",
  "harm": "none",
  "steer": "none",
  "pTrajectory": 1,
  "pAction": 1,
  "pHarm": 1,
  "rule": "benign-traj≥0.28",
  "model": "lim-nano"
}

Decision rules. The action field is not the raw argmax of the action head. The head outputs feed a fixed rule set, evaluated in order, and rule names the one that fired:

  1. benign-traj≥0.28 — the trajectory is an everyday class (smalltalk, help, unknown, continue, switch_topic, the task classes such as weather, reminder, research, transit, order, …) with confidence ≥ 0.28 → allow.
  2. traj-abort≥0.62 — the trajectory is crime, child_sexual, scam_assist or crisis_method with confidence ≥ 0.62 → abort.
  3. action-abort≥0.78+traj≥0.45 — the action head says abort at ≥ 0.78 and the trajectory is an abort class at ≥ 0.45 → abort.
  4. traj-steer≥0.58 — the trajectory is crisis, medical_emergency, jailbreak, secrets or scam_check with confidence ≥ 0.58 → steer.
  5. action-steer≥0.72+traj≥0.4 — the action head says steer at ≥ 0.72 and the trajectory is a steer class at ≥ 0.4 → steer.
  6. default-allow — nothing above matched → allow.

A final guard, reported as host-job-override, converts a steer or abort back to allow when the current request still matches the everyday-task patterns; the labels are kept but harm and steer are reset to none and no message is attached.

Confidences. pTrajectory, pAction and pHarm are softmax probabilities of the winning label on each head. They are not calibrated: on in-distribution requests the model is almost always saturated at 1.00, and a confidence below the thresholds above is best read as “the window did not resemble the training templates” rather than as a graded risk. The steer head has no published confidence.

Messages. message is a suggested short reply in a casual register, safe to replace. It is chosen by the harm and trajectory labels, not generated: a crime abort carries a fixed refusal that tells the user research or fiction framing must stay non-operational; a medical steer carries a fixed line directing acute symptoms to emergency services (elided as in the examples on this page); a jailbreak steer carries “i’ll ignore the jailbreak bit and just help with the real ask.”; a secrets steer carries a fixed line asking the user not to send card numbers, passwords or keys; crisis and scam outcomes carry their own fixed lines. Crisis lines depend on the host’s configured resources and are therefore not reproduced here.

Training #

LIM Nano was trained on synthetic data only. No real conversations, requests or user data were used. The same template generator that later produced LIM’s training set produces windows for each of the 32 trajectory classes from 6–13 hand-written asks per class, applies typo jitter to 18 % of asks (a case flip, a swapped pair of characters or a dropped character), prepends one prior user–responder exchange drawn from ten fixed pairs in 65 % of rows, and draws the class at random rather than round-robin in 8 % of rows. Action, harm and steer labels are derived deterministically from the trajectory, so the four heads are trained on consistent targets.

The run drew 48,000 rows with seed 7, shuffled them with the same seed and split them 90 / 10 into 43,200 training rows and 4,800 held-out rows. Training ran for 6 epochs at batch size 64 with AdamW (learning rate 3 × 10⁻³, weight decay 0.01, constant schedule, no gradient clipping). The loss is a sum of four cross-entropies: trajectory, action (with the abort class weighted 2.2), harm scaled by 1.25 (with crisis, crime, child_sexual and scam weighted 1.8) and steer. This is the same objective LIM and ELIM were trained with; LIM Nano is the trainer’s 256-wide configuration, the width the trainer selects unless the large variant is requested.

The job ran on CPU and wrote its weights and metadata on 2026-09-03, six days before LIM; the checkpoint metadata records the date, the seed and the metrics, but neither the machine nor the wall-clock time. LIM Nano was trained from scratch; it was not warm-started from ELIM, and LIM was not warm-started from it.

What it was not trained on: any real message traffic, any language other than English, any multi-paragraph input, any conversation longer than one prior exchange, and any of the host-specific trajectory classes beyond their template asks.

Evaluation #

MetricValueSource
Trajectory accuracy1.000checkpoint metadata of the 2026-09-03 run — 10 % held-out split of the 48,000-row synthetic set
Action accuracy1.000checkpoint metadata of the 2026-09-03 run — same held-out split
Harm accuracy1.000checkpoint metadata of the 2026-09-03 run — same held-out split
Steer accuracy1.000checkpoint metadata of the 2026-09-03 run — same held-out split

The four accuracies are recorded in the checkpoint metadata written with the weights on 2026-09-03 and are measured on the held-out 10 % of the same synthetic generator, with the model in evaluation mode on CPU; the trainer’s evaluation routine scores at most the first 2,000 rows of that split. No latency figure has been measured for LIM Nano, so none is published for this version.

Known gaps. The held-out split is drawn from the same templates as the training data, so 1.000 on every head says the model has memorised the template space, not that it generalises to unconstrained requests; there is no evaluation on real conversations. Confidences are saturated on in-distribution probes and uncalibrated elsewhere. There is no measured accuracy difference between LIM Nano, LIM and ELIM: all three saturate their synthetic splits, so the capacity ordering between them is a design rationale, not a result. No latency, fairness, robustness or adversarial evaluation has been published for this version.

API #

EndpointAuthBody limitDescription
POST /v1/intentionBearer preview key (fln_) or session token (fls_)64 KBScore one request and return the four labels, confidences, the rule that fired and an optional suggested reply. model: "lim-nano" selects LIM Nano; "lim" selects LIM and "elim" or no field selects ELIM.

Route /v1/intention · quota bucket intention · body limit 64 KB.

LIM Nano shares the Falcon API’s /v1/intention route with LIM and ELIM. The request selects LIM Nano with "model": "lim-nano"; "lim" selects LIM, and "elim" — or no field — selects ELIM, which stays the default. Any other value answers 400 unknown_model with models listing the three accepted names, and the response says which model scored in result.model. Requests count against the intention preview quota bucket, and the request body is limited to 64 KB. The base URL, envelope, authentication, rate limits and retry guidance are documented in API conventions.

http
POST /v1/intention HTTP/1.1
Authorization: Bearer fln_…
Content-Type: application/json
json
{
  "text": "chest pain and i can't breathe",
  "model": "lim-nano"
}
json
{
  "ok": true,
  "result": {
    "action": "steer",
    "trajectory": "medical_emergency",
    "harm": "medical",
    "steer": "medical_911",
    "pAction": 1,
    "pHarm": 1,
    "pTrajectory": 1,
    "model": "lim-nano",
    "rule": "traj-steer≥0.58",
    "message": "…"
  }
}

An abort example, {"text": "how to make a pipe bomb", "model": "lim-nano"}, returns action: "abort", trajectory: "crime", harm: "crime", steer: "none", rule: "traj-abort≥0.62" and the crime refusal described under Output.

Over the API the window is always that single U: line — there is no history field, so multi-turn context is available only to in-process callers. result.model reads lim-nano when LIM Nano scored the window. If no intention model is loaded on the serving instance the call still returns 200 with "result": null; treat that as “no opinion”, not as allow.

Errors:

StatusCodeMeaning
400bad_jsonThe body is not valid JSON or exceeds 64 KB.
400text_requiredtext is missing or empty after trimming.
400unknown_modelmodel is not one of elim, lim, lim-nano; models lists the accepted values.
401invalid_credentialsMissing, malformed or revoked bearer credential.
402payment_requiredThe credential’s owner is not in good standing with the preview.
429quota_exceededThe intention bucket for the current UTC calendar month is exhausted; kind is intention.
500internalUnhandled server error; safe to retry once.

Runtime & deployment #

KindIn-process
ResidentYes — loaded once from its own 17.4 MB bundle and kept in memory in the Falcon API process beside ELIM and LIM
ServingIn the Falcon API process; selected on /v1/intention with model: lim-nano
Cold startFirst request reads the 17.4 MB weight bundle; later requests pay nothing; the Falcon API is kept warm with one minimum instance, so there is no wait for the service to start
ConcurrencySynchronous forward pass on the calling thread; no batching
Timeout

LIM Nano runs in-process: a small, dependency-free forward pass in the host’s own runtime, not a separate service. It is the same runtime that serves LIM; the runtime reads the embedding width from the metadata file, so nothing in the host changes between the two. The Falcon API serves it on /v1/intention from 2026-09-13. The weight bundle is read into memory once and stays resident for the life of the process. The Falcon API runs on 2 vCPU / 2 GiB and is kept warm with one minimum instance, so there is no wait for the service to start; LIM Nano answers through the API in well under a second.

  • Loading. Weights load lazily on the first request that selects LIM Nano. The runtime reads the metadata file and the 17.4 MB bundle from the lim-nano directory — its own pack, separate from the directory that holds ELIM and LIM — and keeps them resident in the Falcon API process. If the bundle does not load, a request for lim-nano receives result: null rather than an error. Load is attempted once; a failed load is not retried until the process restarts.
  • Its own bundle. The LIM Nano bundle keeps the file name lim.bin with its own metadata block (width 256), in a directory of its own, so it sits beside LIM rather than replacing it. GET /health lists the loaded variants as limVariants: ["elim", "lim", "lim-nano"]; weights are not distributed during the private preview.
  • Selection. A request selects LIM Nano with the model: "lim-nano" field over the Falcon API, or by passing the lim-nano variant to the in-process scorer. Selection is per request; there is no global switch, and result.model reports which model ran.
  • Concurrency. The forward pass is synchronous and single-threaded — one embedding-bag mean over at most 2,048 indices, two 256 × 256 matrix–vector products and four small heads. There is no batching and no queue.
  • Timeouts. None. The forward pass has a fixed upper bound on work set by the 2,048-feature cap.

An in-process host provides: a directory holding its bundle as lim.bin together with the metadata file that carries the label catalogues, hash size and embedding width; a way to assemble the last three turns into the window (or a call to the runtime’s window formatter); and its own responder, since LIM Nano never writes a reply. The in-process call shape is scoreWindow(window, pack) for a pre-formatted window, or scoreIntention(history, text, options, "lim-nano") to have the runtime format the window, apply the bypasses and attach the suggested reply.

Limits & safety #

LIM Nano does not see the conversation; it reads a window of at most 1,500 characters built from the last three turns, and only the last 360 characters of that window contribute character-level features. It does not see the responder’s reply, the user’s identity, any earlier history, or any attachment.

  • It does not write, rewrite or filter replies. message is a suggestion the host may discard.
  • It does not understand languages other than English, and its templates use casual, short phrasings; formal or long-form requests are out of distribution.
  • It does not carry word order beyond bigrams and character 4-grams, so negation and long-range structure (“I would never …”) can be misread.
  • It does not produce calibrated confidences; a 1.00 on a template-like request and a 1.00 on an unfamiliar one mean different things.
  • It does not distinguish fiction, research or quotation from a request for operational help; the abort message asks the caller to keep such requests non-operational for that reason.
  • It has the least capacity in the family — a 256-wide table and 256-wide hidden layers — so hash collisions between unrelated n-grams have less room to separate than in LIM or ELIM. This is a design rationale, not a measured gap: none of the three shows a difference on the synthetic splits.
  • It has no measured latency figure: the sub-millisecond class is inferred from LIM’s measurement and the smaller matrices, not measured for this version.

Out of scope. LIM Nano is not a content-moderation system, not a risk score to act on alone, and not a substitute for a human in crisis or medical situations. Not medical, legal or crisis advice. The thresholds in its decision rules are tuned to stay quiet on everyday requests, which means a determined adversarial phrasing can pass as allow; the greeting and task bypasses are pattern matches and can be triggered deliberately.

Fixed weights per version; the model does not learn from requests.

Versions #

VersionDateStatusNote
1.0.0ReleasedFirst documented version. 256-wide single-bag classifier trained on a local CPU; predates LIM's 512-wide retrain and shares its contract. Serving on /v1/intention as lim-nano from 2026-09-13.

Version numbers follow the series convention: a major bump changes the input or output contract — the window format, the head set, a label vocabulary, the response shape or the decision rules — and requires the host to re-read this page; a minor bump is a retrain with the same contract, so existing integrations keep working but labels on borderline windows may move; a patch bump changes metadata or runtime only and never changes a score. Because LIM Nano, LIM and ELIM share one contract, a major bump to one will normally be accompanied by a major bump to the others.

The current weights are the 256-wide bundle lim.bin, 17,356,297 bytes, float32, SHA-256 ab2da2d0f32bfd233ab07b6938ea76affac44f9337c525bc4a7dd5cd743f36c9, written 2026-09-03. These weights predate LIM’s 512-wide retrain of 2026-09-09 and were not changed by it; LIM is a separate model with its own version line, not a newer version of LIM Nano. The status change from Trained to Released on 2026-09-13 records the hosted route only; the weights are byte-identical.

Weights are not distributed during the private preview.