Eposyne Director

Policy

The policy is one JSON document that tells Plots and Memory how to behave. It also decides how many model calls your events cause, and so what they cost. This page lists every setting an account may change, its default, and what it does to your bill.

What the policy is

The policy has three sections: shared for rules every module obeys, memory for Memory, and plots for Plots. Every member has a default. A member you leave out takes its default, and a policy without a section runs that section on defaults. You never need to send a policy to start.

Store and read the policy

PUT /v2/policy stores the policy. GET /v2/policy reads the policy Director runs.

Store
curl -X PUT https://director.eposyne.com/v2/policy \
  -H "Authorization: Bearer $EPOSYNE_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @policy.json

Send the whole document. It replaces the stored one. The body is at most 65,536 bytes. Director checks every section first and stores nothing unless all of it is valid. A valid policy answers 200 with the policy state:

200
{
  "source": "pushed",
  "hash": "9b2c0f5c1c4e0d3a7f1e6a8b5d2c4f60a1b3c5d7e9f0a2b4c6d8e0f1a3b5c7d9",
  "stored_at": "2026-10-13T18:00:00.000Z",
  "policy": {
    "memory": {"weighing": "model"}
  }
}
Read
curl https://director.eposyne.com/v2/policy \
  -H "Authorization: Bearer $EPOSYNE_API_KEY"

When the policy is refused

An invalid policy answers 422 with "code": "policy_invalid" and one entry in errors for each problem. The policy you had before stays in force.

422
{
  "detail": "invalid policy",
  "code": "policy_invalid",
  "errors": [
    {"path": "extra", "message": "unknown section"},
    {"path": "memory.weighing", "message": "Input should be 'rules' or 'model'"},
    {"path": "plots.max_active_arcs", "message": "must be an integer from 0 to 1000"}
  ]
}

The rules are strict. A section or member that the policy does not define is refused. A value must have exactly the right type: "3" is not an integer, and 2.5 is not an integer either. A list of ids may not repeat an id. A body that is not JSON, or is over 65,536 bytes, is refused with the same code and the path document. Match on code and read path. The wording of message can change.

The defaults

This is the policy Director runs when you store none. Every member shown is a setting you may change.

The default policy, written out
{
  "shared": {
    "invention": {"allowed": false, "violation": "record_only", "max_regenerations": 2},
    "judgement_model": null
  },
  "memory": {
    "world": true,
    "npc": true,
    "weighing": "rules",
    "perception_location_fallback": true,
    "spreading": {
      "enabled": false,
      "meetings": ["movement", "reported"],
      "group_field": "group",
      "group_interval_game_hours": 24,
      "group_exchange_limit": 20
    },
    "referee": true,
    "lies_believable": true,
    "persistent": {"characters": [], "kinds": []}
  },
  "plots": {
    "director_may_start_arcs": true,
    "sources": ["authored", "catalogue", "free"],
    "permitted_templates": null,
    "max_active_arcs": 3,
    "max_emergent_share": null,
    "excluded_locations": [],
    "excluded_moments": [],
    "eligible_npcs": null,
    "fill_scope": "empty_fields",
    "completion_field": null,
    "may_override_guards": false,
    "relevance": {
      "role_in_current_beat": "full",
      "role_in_arc": "summary",
      "current_beat_at_location": "summary",
      "other_arcs": "omit"
    },
    "steering": "subtle"
  }
}

How the policy multiplies model calls

Every module judgement is reserved and charged from your usage credits like a decision. See Billing and limits. The policy decides how many judgements happen. Count them like this.

Plots, for every event

Memory, for every event

In a decision

The settings

shared

SettingDefaultWhat it doesEffect on model calls and cost
invention.allowedfalseWhether Plots may add characters, places, or items that appear in no arc, in the world record, or in memory. An allowed invention becomes a note in the world record. Core, the part that writes decisions, never invents, whatever this says.true stops the regenerations of a Plots fill-in that invents. false with block makes Plots fill-ins repeat.
invention.violation"record_only"What happens to a reply that invents when invention is not allowed. record_only delivers the reply and Memory records only that the character said it. block withholds the reply and writes it again.record_only adds no calls. block adds up to max_regenerations decision-sized calls for each reply that invents.
invention.max_regenerations2 (1 to 5)Under block, how many times a reply is written again before it is delivered under record_only.The most extra decision-sized calls for one decision. At 5, one decision can cost six times its normal price in the worst case.
judgement_modelnullThe model for judgements, as {"provider": "...", "model": "..."}, a pair from your model list. null uses the decision's model inside a decision, and your account's default model for events.Sets the price of every judgement call. Binding a small, cheap model here cuts the cost of every judgement at once. If Director cannot use the model you name, judgements use the default model instead.

memory

SettingDefaultWhat it doesEffect on model calls and cost
worldtrueThe world part: what really happened, kept as the world record. The referee judges a player's claim against it.Off disables the referee.
npctrueThe NPC part: what each character perceived, believes, and feels. Off, and Memory gives Core nothing.Off removes the weighing, rumour, and referee calls.
weighing"rules"How much an event matters to a character: rules computes it, model asks a model.model is the setting that multiplies calls: one per memory formed, one per rumour passed on, and one invention check per decision. See above.
perception_location_fallbacktrueWith no witnesses, the characters known to be at the event's location perceived it.On means more characters perceive each event, so with model weighing more weighing calls. Off limits perception to the target, the actor, and the witnesses you name.
spreading.enabledfalseWhether Director spreads memories between characters on its own. Retellings your game reports with told are always processed.Off adds no rumour calls. On adds them under model weighing.
spreading.meetings["movement", "reported"]How Director recognizes a meeting: movement from character location events, reported from the characters-met event, group from a shared group field on a game-time interval.Each source you add adds meetings, and each meeting costs up to 6 rumour calls under model weighing.
spreading.group_field"group"The Character field that names a character's group. An empty value takes part in no group exchange.No direct effect.
spreading.group_interval_game_hours24 (1 to 8760)How often a group exchanges memories, in game hours.A shorter interval means more exchanges, so more rumour calls under model weighing.
spreading.group_exchange_limit20 (0 to 10000)The most memories exchanged per group per interval.The cap on rumour calls for a group in one interval. 0 stops group exchange.
refereetrueJudge a player's claim against the world record when it touches an uncertain or contradicting belief.On costs at most one call per decision at a player line. Off removes it.
lies_believabletrueWhether the referee may let a convincing lie be believed.No effect on cost.
persistent.characters, persistent.kinds[], []Characters, and kinds of memory (event, knowledge, impression), whose memories are kept for the whole world across timelines. See Memory across timelines.No effect on cost.

plots

SettingDefaultWhat it doesEffect on model calls and cost
director_may_start_arcstrueWhether Director may start an arc when an event fits no running arc. Off, Plots still tracks and advances arcs that are running.Off removes the gate, choosing, and fill-in calls for new arcs. The fitting call per event stays.
sources["authored", "catalogue", "free"]Where a new arc may come from: your library, the template catalogue, or invented by the model. An empty list lets Director start no arc.An empty list removes the calls for new arcs. Removing free stops invented arcs.
permitted_templatesnullThe catalogue templates a new arc may use, by reference id. null permits the whole catalogue, an empty list none.No direct effect.
max_active_arcs3 (0 to 1000)The most arcs a player may have active at once. At the limit, Director starts no new arc. 0 starts none.A refusal here happens before the gate, so a full player costs no gate, choosing, or fill-in calls.
max_emergent_sharenullThe largest share of a player's active arcs that may be emergent, from 0 to 1. null leaves it open.A refusal here saves the gate call.
excluded_locations[]Location ids at which no new arc starts.A refusal here saves the gate call.
excluded_moments[]Event keys during which no new arc starts. A standard event matches under either spelling of its key, loreweaver. or eposyne..A refusal here saves the gate call.
eligible_npcsnullThe characters Plots may bind to an open role. null allows every character, an empty list none. A character you cast in a beat is never affected.No direct effect.
fill_scope"empty_fields"How far Plots fills in an arc. empty_fields completes only fields that are empty, and never changes a field you wrote. add_beats is accepted and stored, but in this release Plots still completes empty fields only.Each fill-in is one call, plus any regeneration.
completion_fieldnullThe Beat field that says when a beat is complete, tried before the standard field complete_when.No direct effect.
may_override_guardsfalseWhether Plots may take a branch whose formal guard is false. Off, a formal guard decides alone.On offers more branches to the model at a fork.
relevance.role_in_current_beat, relevance.role_in_arc, relevance.current_beat_at_location, relevance.other_arcs"full", "summary", "summary", "omit"How much of each running arc reaches the decision for a character: full, summary, or omit. It is always direction, never knowledge the character holds.Changes the size of the decision prompt, so the cost of every decision at a stream position. full and summary add text, omit adds none.
steering"subtle"How strongly a reply steers away when Director refuses a new arc: subtle or explicit.No effect on cost.

A worked example

A tavern scene: 20 events that name the player, 3 characters besides the player who perceive each of them, 5 decisions at a stream position after the player speaks, one new arc started, one meeting between two characters. Count the judgement calls first with the defaults.

SourceCalls with the defaults
Plots, fitting: 20 events20
Plots, new arc: gate, choosing, fill-in3
Memory, events: weighing is rules0
Memory, referee: at most once per decision5 at most
Total judgements28 at most, plus the 5 decisions

Now the same scene with weighing: "model" and spreading.enabled: true:

SourceCalls with model weighing
Plots, fitting and new arc23
Memory, weighing: 20 events, 3 characters perceive each60
Memory, rumours: one meeting, at most 66 at most
Memory, referee5 at most
Memory, invention check: 5 decisions5
Total judgements99 at most, plus the 5 decisions

The same scene costs more than three times as many judgements. The 60 weighing calls alone pass the limit of 50 judgements for one events request, so if you sent the 20 events in one request, part of the batch would come back as deferred. If you keep model weighing, bind a small model for the judgements and keep decisions on the model you like. Store this policy:

policy.json
{
  "shared": {
    "judgement_model": {"provider": "<provider id>", "model": "<model id>"}
  },
  "memory": {
    "weighing": "model",
    "spreading": {"enabled": true, "meetings": ["reported"], "group_exchange_limit": 5}
  },
  "plots": {
    "max_active_arcs": 2,
    "relevance": {"other_arcs": "omit"}
  }
}

Choose the pair from your own GET /v2/models list. With this policy, rumours spread only at meetings your game reports, a group exchanges at most 5 memories per interval, and every judgement runs on the small model. Judgements on the stream cost whatever that model's listed price is. They stay in your usage totals, see Billing and limits.