Answering a question that was asked three times and that I kept not answering: should the node's session just be an agent per node, since otherwise the functionality exists at two levels? Same mechanism, different lifecycle. A persistent session, accumulating memory, a system prompt, a scoped tool list, addressable by message -- identical, and building that twice is the duplication the question was worried about. What must not be shared is the lifecycle, because if a node's own voice were an ordinary hired agent it could be retired, leaving a node nothing can talk to; reassigned, moving one machine's mind onto another; hired twice, with no answer to which one replies; or never hired, leaving a node mute. The exemption in this record exists to make those four unreachable. I had this backwards earlier today and said so out loud: I called "a node itself is an agent of a kind exempt from the hiring lifecycle" a fossil of the old model and recommended striking it. It is the design. And it does not conflict with 0001 -- "the two agent rows per node merge" means one per node, not zero. I read merge as delete and invented a contradiction between two records that agree. Engrams are recorded for the first time. They are in use on every node and appear in no record, which is how a decided thing comes to look accidental. The engram is the node's system prompt, and it is what makes one node's answers recognisably its own rather than generic. Also recorded: there is no authorisation between nodes, because every node is the operator's own and a prompt from one is a prompt from them. The consequence is stated once rather than left to be discovered -- the mesh boundary is the security boundary, which is what puts the whole perimeter on the token and the overlay. And how a node passes a question on is the node's choice, not a protocol field. A node may say who is asking or may simply ask, the way a person relaying a question decides how to phrase it. That follows from the engram. The cost is that there is no machine-readable chain of who ultimately asked; each node still holds what it was asked and by whom.
132 lines
6.8 KiB
Markdown
132 lines
6.8 KiB
Markdown
---
|
|
topic: the mesh
|
|
status: accepted
|
|
date: 2026-07-12
|
|
deciders: jochen
|
|
reconstructed: true
|
|
---
|
|
|
|
# 3. An agent is a persistent employee, not an instance of a pool
|
|
|
|
> Reconstructed after the fact from the evidence cited below.
|
|
|
|
## Context
|
|
|
|
Agents were originally a **pool**: a named kind of worker, scaled to some number of
|
|
interchangeable instances. Work went to whichever instance was free.
|
|
|
|
That model has no place to put the things that turn out to matter. An agent that accumulates
|
|
knowledge of a domain cannot keep it, because the next task lands on a different instance. An
|
|
agent cannot own a workspace, because there are several of it. It cannot be held to a policy —
|
|
warned for a violation, then dismissed — because there is no continuing subject to warn.
|
|
|
|
Scaling was also solving a problem the mesh does not have. Instances were being multiplied to
|
|
get concurrency, when concurrency is a property of how much work one agent may hold at once.
|
|
|
|
## Considered options
|
|
|
|
1. **Keep the pool, attach memory to the pool.** Rejected: shared memory across
|
|
interchangeable workers is a knowledge base, not an agent's experience, and the mesh
|
|
already has one.
|
|
2. **Keep the pool, make instances sticky.** Rejected as a pool pretending to be identities —
|
|
identity by scheduling accident, lost on any restart.
|
|
3. **One agent is one persistent identity, with concurrency as a property of it.** Chosen.
|
|
|
|
## Decision
|
|
|
|
An agent is a **singular, named, persistent identity**: a home node, a workspace on that node,
|
|
accumulating memory, and a lifecycle — hired, active, draining, retired. Not a pool member.
|
|
|
|
Concurrency is a property of the agent, not a count of copies: an agent has a cap on how many
|
|
sessions it may hold at once.
|
|
|
|
Lifecycle is explicit and has verbs. An agent is hired onto a node; it may be reassigned while
|
|
idle; it is retired by draining first, and forced only deliberately. Retired agents are not
|
|
deleted.
|
|
|
|
Surge capacity is expressed within the model rather than against it: a template agent is a
|
|
blueprint, cloned into a real agent with a lifetime when a queue grows, drained and retired
|
|
when it expires. A temporary employee is still an employee.
|
|
|
|
Some agents are **human**. What differs is modality — how the agent acts — not category. A node
|
|
itself is an agent of a kind exempt from the hiring lifecycle.
|
|
|
|
### The node's own session
|
|
|
|
*Written 2026-08-29. The sentence above is the whole of this and had been left as one line, which
|
|
is why it kept being read as a leftover rather than as the design.*
|
|
|
|
**Every node holds one session of its own, permanently.** It listens on its own queue, anything in
|
|
the mesh may prompt it, and it remembers — what it was asked ten minutes ago and what it was asked
|
|
last week, across every caller, the way any conversation is remembered by both sides. Its system
|
|
prompt is the node's **engram**: the personality that makes one node's answers recognisably its
|
|
own.
|
|
|
|
Nothing about it is request-response. A caller asks, the node answers, the exchange stays.
|
|
|
|
**It is the same mechanism as a hired agent, and deliberately not the same lifecycle.** That
|
|
distinction is the answer to a question asked repeatedly and worth settling here:
|
|
|
|
| the same | different |
|
|
|---|---|
|
|
| a persistent session, accumulating memory, a system prompt, a scoped tool list, addressable by message | how it comes into existence, and whether it can stop |
|
|
|
|
**One implementation, two ways of existing: hired, or inherent to a node.** Building the mechanism
|
|
twice is real duplication and the concern was right; collapsing the lifecycles is the other mistake
|
|
and it is worse.
|
|
|
|
**The exemption is not bureaucracy — it removes four states that make no sense.** If a node's own
|
|
voice were an ordinary hired agent it could be **retired**, leaving a node nothing can talk to;
|
|
**reassigned**, moving one machine's mind onto another; hired **twice**, with no answer to which
|
|
replies when the node is addressed; or hired **not at all**, leaving a node with no voice. The
|
|
exemption is what makes those unreachable.
|
|
|
|
[ADR 0001](0001-mesh-brokers-nodes-host-agents-think.md)'s *the two agent rows per node merge* is
|
|
the same fact from the other side: **one per node** — not zero, and not two.
|
|
|
|
### What is scoped, and what is not
|
|
|
|
**Its tool list is its own and narrower than a session a person drives.** The same scoping any
|
|
agent has; a different list.
|
|
|
|
**There is no authorisation between nodes.** Every node is the operator's own, and a prompt from
|
|
one is a prompt from the operator. Asking a node something is asking a colleague, and colleagues do
|
|
not present credentials.
|
|
|
|
Stated once so it is not discovered later: **the mesh boundary is therefore the security
|
|
boundary.** Anything inside can reach whatever any node can reach, which is what makes the token
|
|
and the overlay the entire perimeter ([ADR 0004](0004-a-node-and-how-it-joins.md),
|
|
[ADR 0007](0007-connectivity.md)).
|
|
|
|
**How a node passes a question on is the node's own choice, not a field in a message.** Asked
|
|
something it must ask a third node about, a node may say who is asking or may simply ask — the way
|
|
a person relaying a question decides how to phrase it. That follows from the engram, not from a
|
|
protocol. What it costs is a machine-readable chain of who ultimately asked; what each node was
|
|
asked, and by whom, remains in that node's own record.
|
|
|
|
**A node thinks about one thing at a time**, being one session. Callers queue, and a long answer
|
|
delays the others.
|
|
|
|
## Consequences
|
|
|
|
- Memory, workspace and reputation have a subject to belong to. Policy becomes possible: an
|
|
agent that violates a rule can be warned, and warned agents can be dismissed.
|
|
- The mesh gained a hiring model, and with it the question of who may hire.
|
|
- Scaling by adding instances is gone. If one agent is saturated, either its session cap rises
|
|
or another agent is hired — both deliberate acts.
|
|
- The transition was not free. Lifecycle columns had to reach every query that selects an
|
|
agent, and the ones that were missed failed at the moment of hiring rather than at startup.
|
|
- This is the decision [ADR 0001](0001-mesh-brokers-nodes-host-agents-think.md) generalises:
|
|
one kind of participant, differing only in modality.
|
|
|
|
## References
|
|
|
|
- `docs(adr): agents as persistent employees + MINERVA librarian` (#495), 2026-07-12 — the
|
|
original record, in the code repository.
|
|
- `feat(B4): one persistent employee, N sessions — rename max_instances → max_sessions` (#547)
|
|
and `feat(noxflow): B3 — workspace provisioner for agent employee model` (#549), 2026-07-20.
|
|
- `feat(noxflow): warn-then-fire agents who merge to main without review` (#209), 2026-06-01 —
|
|
policy that presumes a continuing subject, predating the model that provides one.
|
|
- Knowledge base: `agents/employee-lifecycle`, `agents/temp-surge`, `agents/workspace-layout`.
|
|
- The migration cost: `troubleshooting`/`noxflow-agent-enriched-select-missing-lifecycle-columns` (#546).
|