Local Writing App

These guides describe v1.1.0, the latest release. The same guides are in the app under Help → Guides.

What the AI sees

User guide. Every chat turn sends the model your prompt, the conversation so far, and a block of lore the app chose for you. This guide is about that block — what goes into it, why, and the few places you steer it. It's automatic by default; the last sections are the parts you can touch.

You never paste your world into a prompt by hand. A prompt names what the model should know about, and the app fetches the entries, removes duplicates, fits them to a size, and places them where the model's cache can hold on to them. Here is what happens between your message and the model, in the order it happens.

Two halves: what you named, and what the app noticed

The lore in a turn comes from two sources, and one switch decides whether the second one runs at all.

  • Declared — what you named. A prompt's own picks (use(), usually fed by a Lore picker), the entries the scene itself references in its fields (its point-of-view character, its location), and every entry whose Context policy is Always include. These are sent whole, every turn. Nothing trims them.
  • Automatic — what the app noticed. Entries named in your message, in the prompt, or in the scene's prose, plus a short reach out from those. This half is fitted to a budget on the assistant, so a big world doesn't swamp a turn.

The switch is the prompt's auto_lore() call. A prompt that calls it gets both halves; the Context door shows lore-enabled · by this prompt at the top of its System section. A prompt without it sends its picks and every always-included entry, and nothing else: no scene references, no noticing. A prompt built to check one entry, or a research prompt that must stay clean, can say so with no_lore(): it sends its own picks and no always-included entries at all, and the door shows lore-free in place of lore-enabled.

The editor's inline actions (Tighten grammar, Expand, Describe and the rest) send the same picks and always-included entries, but never automatic lore, even from a prompt that calls auto_lore(): noticing what you name belongs to a conversation.

A prompt can also place an entry as it was at an earlier snapshot, alongside the entry as it is now — use(node, snapshot=id). Propose's built-in Follow a change does this for the entry that changed, so you see what changed without re-reading two renders yourself. The earlier state rides the stable tier every turn, like a declared pick, so it survives the conversation-history window even many turns later.

Declared — what you named sent whole, every turn, never counted The prompt's picks use(inputs.lore) — a Lore picker The scene's own references its POV character, its location… Entries set to Always include Context policy on the entry Automatic — what the app noticed only when the prompt calls auto_lore() Names in your latest message Names in the prompt, on the first turn Names in the scene's prose …and one step out from those fitted to the assistant's Lore budget and Lore reach One lore block — each entry once Never include drops an entry from either half, a pick too

What automatic lore notices

Noticing is a name match. The app builds one matcher from every entry's Name and aliases — the same detection that underlines mentions while you write (see Lore, Mentions in your prose) — and runs it over three surfaces on every turn:

  1. Your latest message. Name a character and they come along.
  2. The prompt itself, once, on the first turn. If your template's text names an entry, it's noticed as part of setting the scene.
  3. The scene's prose — its body and every long-text field on it, such as a summary. A chat that isn't anchored to a scene has no third surface.

Italics don't hide a name; _The Implant_ is noticed like The Implant. Titles and short fields are not scanned — only prose.

From what it noticed, the app reaches one step out, in two ways:

  • Through prose. Each noticed entry's own body and long-text fields are scanned once for more names. What that finds is not scanned again; the reach stops at one step, so a heavily cross-referenced world can't cascade.
  • Through links. Each noticed entry's reference fields — its faction, its home, the members of a group — are followed once.

The scene's own references and the always-included entries reach out the same way. A prompt's pick does not: picking an entry brings that entry, not its neighbours. If a pick is also named in your message, it is a noticed entry too and reaches out like one.

Three surfaces, one name matcher every entry's Name and aliases, italics included Your latest message every turn The prompt's text first turn only The scene's prose body + long-text fields, each on its own Noticed plus scene refs and Always include One step out through prose its own text, scanned once One step out through links its references, followed once Lore reach: Named only stops here What the step out finds is not scanned again — the reach is one step, so cross-referenced lore can't cascade. A prompt's pick is not a starting point: picking brings the entry, not its neighbours — unless it is also named.

Two settings on the assistant

Both settings shape the automatic half only. Picks, scene references and always-included entries are never counted against them.

  • Lore reach — One hop (the default) or Named only. Named only keeps what was actually named in the message, the prompt or the scene, and drops the step out through prose and links. The Context door still lists what the prose step noticed; it just isn't sent.
  • Lore budget (tokens) — the ceiling on the automatic half, whole entries only. Leave it blank for the default of 16 000. Set it to 0 to send the declared half alone, whatever the prompt calls.

When the noticed entries don't all fit, the app keeps them in the order of how close they are to your own words: entries from your message first, then the prompt, then the scene's prose, then the step out through prose, and the step out through links last. Within a source, the most recently noticed comes first. So the entries the budget drops first are the neighbours-of-neighbours, never the character you just named. The door's Left out section shows exactly what didn't fit, and you can open each one to see what the model would have got.

Fitting the automatic half to the Lore budget whole entries, in order of distance from your own words Declared sent whole, not counted Your message 1st The prompt 2nd Scene's prose 3rd Step out: prose 4th Step out: links 5th — dropped first Lore budget (tokens) Left out → Each entry is kept or dropped whole; nothing is cut mid-entry. Within a source, the most recently noticed comes first. Blank = 16 000 tokens. 0 = the declared half only. The Context door's Left out section lists what didn't fit this turn.

One setting on the entry

Every lore entry has a Context policy field with one of four values:

  • Automatic (alias match) — the default. Noticed when named, followed when linked, available to pickers.
  • Always include — sent with every prompt unless the prompt calls no_lore(), named or not, whether or not automatic lore is on. The step that saves a chat's result (the commit) carries only what the chat picked. Use it for the handful of entries that define your world: the premise, the magic system, the tone sheet, your narration conventions.
  • Manual only — never noticed, never followed as a link; sent only when a prompt picks it or the scene references it. Good for spoilers and notes to yourself that a stray name shouldn't pull in.
  • Never include — kept out of every turn, even if a prompt picks it.

How it's placed, and why that saves you money

Whatever the two halves produced is one set, each entry once, rendered as compact XML. It is then split into two blocks for the turn:

  • Stable — entries unchanged since the last turn of this chat.
  • Volatile — entries that are new this turn, or that you edited since.

The stable block goes first, so a provider that caches prompt prefixes reads it from cache instead of billing it again. An entry you edit moves to the volatile block for one turn and settles back once the app has seen the new version; the door marks such an entry edited until then. Restarting the app doesn't reset this: the chat remembers which versions it last sent.

A prompt can nudge where a pick starts — use(node, "stable") or use(node, "volatile") — but a hint never overrides the check: an entry that actually changed is re-sent whatever its hint says.

Two blocks per turn: stable first, volatile after stable = unchanged since the last turn, the part the provider's cache can reuse Turn 1 everything is new stable — empty volatile Honor Harrington The Collective Premise Turn 2 you edited The Collective in between stable — cached Honor Harrington Premise volatile The Collective edited Turn 3 nothing changed — it settles stable — cached Honor Harrington Premise The Collective volatile — empty The chat remembers which versions it last sent, so restarting the app does not reset this. A use(node, "stable") hint starts a pick in the stable block; an entry that actually changed is re-sent regardless.

Reading the Context door

The door on a chat's composer is the honest version of everything above, before the first send and after every turn:

  • System — the rendered prompt, with lore-enabled · by this prompt when the automatic half is on.
  • Stable lore / Volatile lore — the two blocks with their entries. Open an entry to see the exact XML the model receives. Rows present with no lore-enabled line means "picks or always-included entries placed, automatic off". An earlier state placed by use(node, snapshot=id) appears first in the list of the tier that holds it — the stable tier, except for the one turn after something it refers to was renamed — as an "as of ⟨time⟩" row; the tier row's count includes it as an earlier state.
  • Auto-added this conversation — the noticed entries, each with where it was noticed and on which turn.
  • Left out — what the budget dropped this turn.
  • Inputs (locked) — the picks and other inputs the chat was started with.

In your prompts

These lines cover it. None of them prints anything where you write it.

{% do use(inputs.lore) %}   {# the entries a Lore picker chose — declared #}
{{ auto_lore() }}           {# turn the automatic half on #}
{{ no_lore() }}             {# no always-included entries, no automatic lore #}
{% include "Relevant lore" %}  {# a ready-made optional Lore picker, picks only #}
{% include "Relevant manuscript and plot" %}  {# the same for scenes and plot cards #}

A picked card arrives with its synopsis; a picked scene arrives with its full prose, so pick scenes sparingly.

A prompt that calls neither sends its picks and the always-included entries; one that calls no_lore() sends only its picks. If a prompt calls both, no_lore() wins and the estimate warns. Chats started without a prompt send no lore. Details of the calls are in Writing prompts and the Prompt reference; the picker input itself is its own guide, Context picker.