June 22, 2026 — admin

Agency

High-level design for the *agency layer*: the brains attached to *characters* (not seats), and the *noticeboard* that every brain posts to and every body claims from.

Design — Personal controllers & the noticeboard substrate

High-level design for the agency layer: the brains attached to characters (not seats), and the noticeboard that every brain posts to and every body claims from. This is the counterpart to controllers.md: that doc is the dynasty’s intent (positions decide what should happen); this one is agency (the living person who decides what they actually do, and when). Answers to ../GAME_DESIGN.md §2 (the control model — the architectural spine). Builds on characters.md (traits drive the personal brain) and controllers.md (positions are the other brain). Design doc — the model and its rules, not an implementation plan.

This doc is the truth; where the code already agrees (and a surprising amount of it does — see §8), that is convergence, not constraint.


1. Two kinds of brain — intent vs. agency

Everything in the world happens through tasks (GDD §2). But “post a task” and “do a task” are two different decisions, made by two different brains:

Position controller Personal controller
Attached to a seat — a cabinet office or building manager (controllers.md) a character — every living person has exactly one
Owns the dynasty’s intent: what should be done the body’s agency: what I do, and when
Acts by posting tasks to noticeboards claiming posted tasks + generating its own personal needs
Examples Marshal posts “make swords”; a manager posts craft labour which task to take next, when to sleep/eat, go to the tavern, go seek a spouse
Driven by the office’s logic, tinted by the holder’s traits the character’s own traits and needs

The position controller is the supply of work; the personal controller is the demand for it. Neither reaches into the other — they meet only at the noticeboard (§2). This is the same encapsulation discipline as the order/labour split in controllers.md, pushed one layer down to the body.

The personal controller is always autonomous — even in your own dynasty

You play through positions, not bodies. Seating a member and posting work is the full extent of your control over a character; you never puppet their sleep schedule or drag them to a workstation. This is deliberate and load-bearing:

  • It preserves player↔AI symmetry (GDD §2). If the player could hand-drive individual bodies but the AI couldn’t, the symmetry would be a lie — exactly the trap the Elder-Auto toggle avoids one layer up (rival-ai.md).

  • It is where character flavour lives. A Lazy member’s personal controller weights personal tasks over workshop tasks — so you get a worker idling in the tavern during work hours. Occasionally infuriating, frequently a story. This is the Majesty / Dwarf Fortress “indirect command” feel the GDD names: you express intent, characters carry it out in their own character, and the friction is the fun.

The player’s leverage over a lazy worker is therefore indirect: seat a better manager, post more attractive work, or — at the dynasty level — stop employing them. Not a leash.


2. The noticeboard is the one universal substrate

There is one substrate — the noticeboard — and one kind of thing on it: tasks. Position controllers post; personal controllers claim. Routing is entirely a matter of which boards a poster may write to and which boards a claimer may read.

This is the decision that keeps the whole control model from forking into parallel systems. In particular:

  • An order is just a task that links to and monitors another task. The Marshal’s “make swords” is a task posted to the workshop board; when the manager accepts it (by spawning the craft/deliver work), the order-task simply watches the children it caused, via the existing postedBy/postedById parent→child pattern. The order lifecycle from controllers.md §3–4 — accept/decline, expiry, cascading cancel — survives intact, but as states and links on a supervisory task, not a second mechanism. (This reframes controllers.md’s “two tiers of task” into “one substrate; some tasks supervise others” — see that doc’s reconciliation note.)

  • An “addressed” task is just a post to the target’s personal board. “Go marry X” lands on that member’s personal board; “you specifically, deliver this” lands on the worker’s. There is no separate addressing channel — the personal board is the address. Pooled work (any qualified worker may take it) goes to a shared board (workshop / dynasty / city) instead.

So three things that could each have been their own subsystem — orders, addressed tasks, and labour — are one task system on one set of boards, distinguished only by type, links, and which board they sit on.


3. Board topology — who can read (claim from) a board

A character accumulates read access to boards from their roles and memberships; they then claim from the union of those boards. The shape:

Character Boards they read
Hired workshop worker personal · that workshop
City guard personal · city
Dynasty family member personal · dynasty · all dynasty-owned workshops
Family member also on the council personal · dynasty · dynasty workshops · city

The personal board always exists (one per character); the city board is public (everyone reads it). The rest are membership-derived.

The specific access rows above are illustrative, not a spec. The exact “which role sees which board” wiring is common-sense plumbing to be settled during implementation and balancing — the principle (access is role-derived, unioned per character) is the design; the table is an example of its shape.


4. Board topology — who can post to a board

Posting is a property of a position (the intent layer), and likewise role-scoped:

Poster (a position) Posts to
Building manager personal · that workshop
Elder personal · dynasty
Marshal personal · dynasty
A city office (Sheriff, …) city

A position posts to the board whose readers it means to reach: workshop-pool work to the workshop board, dynasty-wide work to the dynasty board, an addressed task to a specific character’s personal board (§2). Same illustrative-not-spec caveat as §3.


5. Filtering — access says what you see, filters say what you take

Board access narrows the field; within an accessible board, two further filters decide what a character will actually claim:

  1. Type + role restriction (on the task). Every task carries a type; a task may additionally restrict which role may take it. A patrol task posted to the city board is restricted to guard, so a councillor reading the same board never picks it up. (Already real in code: employed workers and family skip Hire; only family take Fire — §8.)

  2. Capability (on the claimer). A character won’t claim work it can’t perform — no smithing skill, no craft:sword. The claimer self-filters by what it can do.

Together: board access = visibility, type/role = “is this for someone like me?”, capability = “can I actually do it?”.


6. The personal controller itself — needs, and the dummy→fancy ladder

The personal controller arbitrates between two streams and picks one thing to do now:

  • Posted work it can see and take (§3–5).
  • Self-generated needs — wants the character produces on its own: sleep today; later eat, worship, heal, drink, seek a spouse. A need surfaces as a task on the character’s own personal board, so the same claim machinery handles it.

The needs model is deliberately light and expandable. Today there is one real need worth naming — sleep — and the rest (church / hospital / tavern, each tied to a future building family in production.md §1) are hooks, not an enumerated system. We add needs as the buildings that satisfy them are designed.

Like every brain in this design, the personal controller is a swappable socket (controllers.md §7):

  • Dummy (today’s behaviour, §8): pick the nearest eligible posted task; satisfy a need only when forced. A strategist with no strategy.

  • Fancy (later): weigh personal wants against posted work through the character’s traits — the Lazy member who’d rather be in the tavern, the diligent one who works through the night. Same socket, richer judgment.

The ladder mirrors the manager’s dummy→strategist ladder: ship the floor first, make it characterful later.


7. Where personal agency meets the positions — approvals as queries

The two brains stay decoupled, but they do talk, and they do it through the query mechanism already defined for positions (controllers.md §5): a personal controller asks a position for a judgment, and the position answers tinted by its holder’s traits.

The worked example is marriage (the thread that surfaced this whole layer): a character’s personal controller decides “I want a spouse” and does the seeking itself; but the match is gated by a dynasty office’s approval — a personal→position query (“may I marry into that house?”) answered by whichever seat owns family matters. (Which office that is — a dedicated family/growth seat or another — is deliberately left open in dynasty.md; this doc only fixes the shape: the body proposes, an office disposes.) So family/breeding is a personal-controller activity with a position veto — not a position driving bodies around.


8. Already in code — the substrate largely exists

Unusually for these design docs, much of this layer is already built, and built in line with the model above:

  • NoticeboardComponent — a per-owner runtime index of posted tasks. Its own comment says it lives on “workshops, dynasties, characters (personal-needs board), and future city/guild singletons” — the exact multi-board topology of §3. Source of truth is TaskComponent.postedBy; the list is a rebuildable cache.

  • NoticeboardSystem — signal-driven dispatch: hooks on_construct/on_destroy on TaskComponent and routes each task to the right board. RebuildAllBoards restores the indexes after load.

  • TaskClaimSystem Phase B is the dummy personal controller. For each idle character it builds the relevant-boards list (city · personal · dynasty · all dynasty workshops, or city · personal · workshop), then claims the nearest Posted task across them — with type/role filters live (employed + family skip Hire; only family take Fire). This is §3 + §5 + the §6 dummy, already running.

  • The personal-needs board is stubbed: the claim loop already pushes the character’s own entity as a board “(future: eat/sleep)” — the §6 needs hook is literally a comment waiting to be filled.

  • Task lifecycle: Posted → Claimed → InProgress → Done/Failed (TaskComponent.state), with postedBy/postedById/postedByGameId already modelling the parent reference §2’s supervisory-task (order) story rides on.

What this means: the agency layer is the most-built part of the whole top-down design. The work ahead is mostly additive (needs, trait-weighted selection, the supervisory-task/order type), not a rewrite.


9. ⚠ Tensions with current code

  • The “order” supervisory task does not exist yet. TaskType is {MoveTo, Gather, Hire, Craft, Sell, ReturnGoods, Fire} — all labour. The supervisory task that links to and monitors a child (the order, §2) — with accept/decline, expiry, and cascading cancel as its states — is greenfield, even though the postedBy parent-link it would use is already there. This is the same gap controllers.md §8 records from the intent side.

  • Selection is “nearest”, not trait-weighted. Phase B picks the closest eligible task; there is no trait input yet, so no Lazy-in-the-tavern behaviour — the §6 dummy is real but the fancy brain (and the traits it reads) is not. Traits themselves are still greenfield (characters.md).

  • No needs. Sleep/eat/etc. are a comment on the personal board, not tasks produced by anything. There is no need-generation system and no building yet that satisfies a need.

  • Filtering is hard-coded, not declarative. The Hire/Fire rules are if statements in the claim loop, not a general “task carries a role restriction” field (§5). Generalising it is a small but real change.

  • Dynasty/city boards are partially wired. Family members already read the dynasty board and city board in code; the city board as a council/guard surface depends on the still-greenfield political layer (politics.md).

  • Capability filtering (§5) is not modelled. “Can this character craft a sword?” has no skill gate yet — claim eligibility is structural (role/employment), not skill-based.


10. Open questions (next pass)

  • Trait→selection formula (§6) — how a Lazy/diligent/greedy trait actually weights personal needs against posted work. The heart of the fancy personal controller; balancing-heavy.

  • The needs model (§6) — which needs exist, how urgency builds, what happens when a need goes unmet (penalty? the body just stops?). Grow it alongside the buildings that satisfy needs.

  • Declarative filtering (§5) — promote the Hire/Fire special-cases to a general task role/capability restriction field.

  • The supervisory-task (order) representation (§2) — exactly how an order-task carries its child links and lifecycle states on top of TaskComponent; settled jointly with controllers.md.

  • Need vs. duty arbitration cadence (§6) — does a character re-evaluate every tick, only when idle, or on need-thresholds? (Today: only when idle, i.e. with no CurrentTaskComponent.) Can a pressing need interrupt an in-progress task?

  • City/guild board access (§3) — finalised once politics.md and guilds.md exist.