-
Notifications
You must be signed in to change notification settings - Fork 1
persona tier
Note
Status: launched — build parts 1–2 + 4 shipped (V5-11, commit 7966ac3); part 3 (on-demand load + surfacing path) is [PENDING-IMPL]; ADR 0016 folded into the Amendment log below (2026-06-24).
Position in arc: refinement of AgentM HLD (the V5 "unbundling" HLD).
Method: the locked 10-section design template (the V5-11 design method).
Roadmap: V5-12 (agentm kernel, ROADMAP-MASTER bucket ⑤) — slotted 2026-06-16; sequenced after V5-10, ahead of V5-11 as its substrate (V5-11's Planner (TPM) is this tier's first real persona = build-part 4).
The V5 unbundling split agentm's world in two — a neutral memory-OS substrate and crickets capabilities (plugins) — but that binary has no slot for a standing concern that composes capabilities without owning them, like the Planner (TPM). This design names that missing third tier — the persona — defines it by its inverted dependency direction, and maps it entirely onto shipped infrastructure so it costs no new machinery. The payoff is a classification that keeps composition from silently becoming cross-repo coupling.
The memory engine has always been more than plumbing: it recalls, reflects, and curates — a tenant with behavior anchored on the neutral kernel, depending on nothing but kernel-native scripts. The V5 binary classifies it under "substrate," which under-describes it. At the same time the roadmap wants the Planner (TPM) (the PM depth-maintainer / drift-corrector, see multi-agent-orchestration, github-project-sync): a standing concern that composes dev-loop and board capabilities it does not own, must run on a bare substrate, and must not drag a hard dependency on crickets into agentm.
Two shipped pieces make naming this tier cheap. The AgentM HLD (V5-8) shipped the enhances: soft-composition runtime — a capability-keyed, graceful-degrade resolver with enhances ∩ requires = ∅. And the host installers already dispatch primitives by positive match on kind:, so an unknown kind is skipped, not rejected. The third tier therefore needs no new resolver, no new loader, and no new host adapter — only a name, a directory, and one gate.
The constraints that drive every call below: bare agentm must stay coherent (the memory engine needs zero plugins) and agentm must take no hard dependency on crickets (discovery, never bundling). Both are invariants from the AgentM HLD; this design holds them mechanically rather than by discipline.
A persona is a standing concern that composes capabilities it does not own. Three properties define it:
- it arbitrates among the capabilities it composes — a judgment between them that none could make alone;
- it is anchored on the neutral substrate, with hard dependencies (
requires:) restricted to substrate-native primitives; - its soft composition (
enhances:) may name any capability, present or absent.
A persona owns no engine. It is a stance plus a composition manifest over engines that stay in crickets. It lives in agentm for universality and neutrality, not because it "remembers."
The defining signature is the inverted dependency direction. A plugin is a capability that others compose — it is depended upon. A persona composes capabilities and is depended upon by nothing — it sits above the capability layer, rooted at the substrate. The rememberer (the memory engine) is the degenerate persona: zero composed plugins, requires: ⊆ substrate — the persona agentm already shipped, now named. The Planner (TPM) is the first real persona: it composes dev-loop/board capabilities via enhances:, hard-requires only agentm-native scripts.
Two near-miss axes are explicitly not the test. "Remembers" breaks both ways: the Planner (TPM) is stateless, while the planned crickets security-review capability requires: agentm for memory. "Crosses multiple plugins" is insufficient — github-projects composes developer-workflows yet is a plain capability. The discriminator is arbitration plus the inverted, substrate-only hard-dep direction.
Mechanically, a persona is just an agent-def: an opinionated prompt, a tools: allowlist, a model:, and declared deps. What makes it a persona is its tier, home, and composition-scope — the file format is ordinary. The shape is conventional: a thing that composes capabilities, ships no feature of its own, degrades when a composed capability is absent, and offers one-click install for it.
N/A: no new infrastructure. The tier is a classification mapped onto shipped pieces — the table below is pure reuse.
| Concern | Shipped mechanism reused | New surface |
|---|---|---|
| Primitive kind | Positive-match kind: dispatch in install.{sh,ps1}
|
kind: persona (a value, not a code path) |
| Home on disk |
harness/-style primitive directory |
personas/ directory |
| Composition (soft) | V5-8 resolver, enhances: (AgentM HLD) |
none — enhances: reused verbatim |
| Hard-dep restriction |
requires: + one-way seam gates |
check-personas (one new static gate) |
| Load | Existing on-demand memory-load path | none — dormant-until-activated |
Trigger shape is unchanged: check-personas runs where the other check-* gates run (local check-all.sh + CI on push); persona bodies load at activation time, not at session start.
The primitive. Each persona is a markdown file under personas/ with frontmatter — kind: persona, requires: [...] (substrate-native scripts/primitives), enhances: [...] (composed capabilities), plus the agent-def fields it shares with any agent (model:, a read-only tools: allowlist) — and a body carrying the standing-concern instructions. The rememberer is the degenerate case: enhances: [], requires: ⊆ substrate.
Composition is enhances:, not a new keyword. "Composes" is the conceptual verb; the on-disk field is enhances:, resolved by the V5-8 resolver. A persona names the capabilities it wants and the resolver answers "present on this host?" at load time, degrading cleanly when absent. There is deliberately no composes: alias — that would fork a resolver and a vocabulary that already exist, for identical semantics.
The gate is the enforcement. check-personas asserts two things for every file under personas/: that each requires: entry resolves to an agentm-native primitive (never a crickets capability), and that no persona manifest lands in the always-load set (so a dormant persona never inflates the per-call token floor — #46). The first holds agentm-no-hard-dep-on-crickets; the second holds the token floor; soft enhances: is unrestricted. It mirrors check-capability-resolver-one-way.py and check-process-seam-import-direction.sh — a one-way dependency assertion, statically checkable, added to the gate battery.
Load is on demand [PENDING-IMPL]. Design: a persona body loads only when the persona is activated, reusing the existing on-demand memory-load path — not the always-load floor. The rememberer is the implicit always-on degenerate persona; everything else is dormant until invoked. A persona may be surfaced through a sub-agent at activation, but it is not a sub-agent (it is a durable classification, not ephemeral fan-out). The surfacing mechanism is designed (see Risks) but not yet built.
The naming question (deferred). agentm keeps "persona" for this tier. The collision is on the crickets side — it calls its four coordinator roles "personas" loosely, though it mostly already says "role" — so the rename moves there: crickets' looser "persona" usage becomes "role", freeing the term for the tier that earns it (a standing-concern identity that composes, distinct from a thin role that wraps one phase command). The pass is doc-only and rides V5-6 (the identity rewrite) — see Re-verification below for why it is zero-code.
This design treats the pre-audit as a pre-audit; the load-bearing assumptions were re-checked against the live codebase, not assumed:
-
queue_status_liteis agentm-native. ✓scripts/queue_status_lite.pycarries the read logic; its docstring states "this is the agentm read logic; the crickets/queue-status-litecommand surface … wraps it." The Planner (TPM) persona may thereforerequires:it without breachingrequires ⊆ substrate. -
Both hosts tolerate an unknown
kind: persona. ✓ Installer dispatch is positive-match ([[ "$_am_kind" == "skill" ]] || continueininstall.sh);validate-adapters.pyandcheck-references.pyvalidate named surfaces by directory + required keys, with no closedkind:enum. An unknown kind is skipped, never rejected. (project_config.py'skind not in ("skill","hook")guard is the project-config toggle path, not the primitive loader, and personas are not project-config-toggled.) -
enhances:reuse, not acomposes:alias. ✓ The AgentM HLD already owns the soft-composition field + runtime; the semantics a persona needs (optional, present-or-absent, degrade) are identical. Reuse; do not alias. -
The crickets "persona"→"role" rename is doc-only, and runs the right direction. ✓ agentm keeps "persona"; the rename is crickets-side — its loose "persona" usage → "role" (verified loose-synonym usage in
project-manager.md,worker.md,tech-lead.md,researcher.md,Coordinator-Roles.md), scope =Coordinator-Roles.md+ the developer-workflows how-to + the four agent descriptions. No shipped "persona"/"role" code vocabulary exists in either repo — renaming touches nokind:value, no gate name, no directory. It is prose, ridden on V5-6 to land once, consistently. - The null hypothesis, re-litigated — see Alternatives Considered.
The null hypothesis, strongest form — ship the Planner (TPM) as a new crickets plugin coordination with requires: [developer-workflows, github-projects, agentm], and call its agent-def a "persona" informally. This works mechanically. Rejected on three architectural (not mechanical) grounds:
-
Swallowing / up-reach. The Planner (TPM) composes
developer-workflows(queue) +github-projects(board) + substrate. Home it indeveloper-workflowsand that plugin reaches up intogithub-projects, whichrequires:it, not the reverse. Home it ingithub-projectsand "render a board" now owns coordination thinking, blowing its one-job contract. A newcoordinationplugin dodges both — but then the persona tier has been built inside crickets, and itrequires: agentmanyway. You re-derived the layer and mis-homed it. - Home / taste. The Planner (TPM) carries agentm's opinion about how a program should be run (computed-not-guessed, advisory-not-acting, smaller-merge-first). The V5-6 thesis is that agentm's identity is the thing that persists. Putting that standing point-of-view in an optional, swappable plugin declares "agentm's taste is optional" — the opposite of "do most of the opinionation in agentm."
- Default-presence. A persona ships with agentm and is always there, degrading; a plugin is opt-in. If minding-the-program is a plugin, then "is anyone minding the program?" depends on your install set. As a persona the stance is always present and merely says "install github-projects for the board."
Honest residual: the tier buys architecture — neutral home, default-presence, identity-anchoring — not new runtime mechanism (it reuses the V5-8 resolver, requires: + one gate, the on-demand load path, and positive-match kind: dispatch). If the operator weights shipping-velocity over the identity-home argument, the null is a legitimate cheaper path whose cost is precisely "agentm's program-minding taste lives in an optional plugin." The layer earns its keep on the three arguments above.
Where opinionation lives (the migration rule). Capability-local opinion — how /work gates, how a release is recoverable — stays in crickets; cross-capability opinion — what order to merge, which plans run together — is what a persona arbitrates, homed in agentm. The line: capability-local → the capability; cross-capability → the persona. This is additive (no migration sweep); a stranded cross-capability stance migrates only case-by-case when a persona claims it, as the PM-thin→Planner (TPM) handoff already does.
Filing the persona as a crickets plugin (general case). Rejected — the inverted arrow again: a plugin is composed by others; a persona composes and is composed by nothing. Persona-as-plugin creates plugin→plugin hard-dep chains, exactly what the enhances ∩ requires = ∅ / one-provider / no-solver rules forbid. Restricting persona requires: to substrate-native keeps the hard-dep graph acyclic and rooted at the neutral substrate, and keeps the tier universal (bare agentm has the rememberer; add crickets and the Planner (TPM) composes the dev loop).
Model a persona as a skill. Rejected — a skill is a capability (the thing a persona composes); filing a persona as a skill collapses the tier distinction and inverts the arrow.
Model a persona as a sub-agent. Rejected — sub-agents are read-only ephemeral fan-out (AGENTS.md rule 6); a persona is a durable classification with hard substrate deps and declared soft composition. It may be surfaced through a sub-agent, but it is not one.
Add a composes: keyword. Rejected — see DC-3 in the Amendment log (the former ADR 0016); identical semantics to enhances:, so a second keyword is pure machinery.
-
AgentM HLD / the V5-8 resolver (
scripts/capability_resolver.py) — the composition runtime, reused verbatim. Hard prerequisite (already shipped). -
The positive-match
kind:dispatch ininstall.{sh,ps1}— relied on for unknown-kind tolerance (already shipped). - V5-6 (identity rewrite) — coordinates with, does not block: the persona→role naming call is parked there. No build dependency.
-
No dependency on crickets. The Planner (TPM) composes crickets capabilities via soft
enhances:only;check-personasforbids any crickets entry inrequires:.
N/A: no existing state to migrate. The tier is additive — a new kind:, a new directory, a new gate. The memory engine is re-described as the degenerate rememberer persona but is not moved or rewritten; no on-disk artifact changes. A later, separate step may author the memory engine's persona manifest, but this design does not require touching shipped memory-engine code.
-
check-personasis a permanent new gate surface to keep wired intocheck-all.sh+ CI. Small but real. - The persona/role term is unsettled until V5-6. Docs carry "persona" in the interim; a later doc-only sweep may rename. Risk: a reader meets two terms across the V5-6 boundary. Mitigation: DC-6 in the Amendment log (the former ADR 0016) records the deferral explicitly.
-
Tier confusion. Operators may mis-file a capability as a persona or vice-versa. Mitigation: the one-sentence inverted-dependency test (DC-1) and the rememberer as a worked example;
check-personascatches the most damaging error (a crickets hard-dep) automatically. -
Surfacing path
[PENDING-IMPL]. How an activated persona's body reaches the agent (injected context vs. on-demand sub-agent) is designed (build-part 3) but not yet built. The Planner (TPM) manifest (personas/team-coordinator.md) therefore exists as a seed that cannot yet be activated.
Graceful degradation is inherited from the resolver: a persona composing an absent capability gets a clean "unavailable," never a crash. A bare agentm runs the rememberer with zero plugins — the degenerate persona is the floor, so there is no "no persona" failure state.
The one-way requires ⊆ substrate invariant is the integrity property; check-personas is its deterministic check. A persona cannot, by construction passing the gate, introduce a hard dependency that breaks bare-agentm coherence.
Every load-bearing call is deterministically checkable: check-personas (requires ⊆ substrate), the existing resolver tests (composition), and the existing adapter/parity gates (unknown-kind tolerance). No LLM-judge verification is required for the mechanism. The §10 re-checks above are themselves reproducible greps/reads against the tree.
requires ⊆ substrate also narrows the trust surface: a persona's hard dependencies are confined to agentm-native, in-repo scripts — it cannot hard-bind to an arbitrary external plugin. Soft enhances: only ever reads capability availability through the resolver; it grants no execution authority.
Default part split follows the Detailed Design subsections — buildable independently, in order:
-
kind: personaprimitive +personas/directory (S) — the schema + one example (the rememberer manifest). -
check-personasgate (M) —requires ⊆ substrateassertion, wired intocheck-all.sh+ CI, with tests. -
On-demand load + surfacing path (M)
[PENDING-IMPL]— activation → body load, reusing the memory-load path; resolve the surfacing-path open item. - First real persona (M, V5-11) — the Planner (TPM) manifest composing dev-loop/board capabilities. Gated behind 1–3.
- The why + load-bearing calls (the former ADR 0016) — folded into the Amendment log below (2026-06-24).
- This design doc (
wiki/designs/persona-tier.md) — the canonical "why we built the persona tier." - At build time: a
wiki/reference/page for thekind: personaschema +check-personascontract; an update to AgentM HLD noting the rememberer-as-degenerate-persona reframe; anenhances:cross-reference from Soft-Composition.
Additive, no flag day — each part lands behind its own gate. The rememberer persona is a re-description of shipped behavior (no runtime change); the Planner (TPM) is the first net-new persona and ships under V5-11.
Fully reversible. The tier is additive: removing personas/, the kind: persona handling (a skipped kind today), and check-personas returns the tree to its pre-tier state with no data migration. The memory engine is untouched, so a rollback cannot regress it.
| Date | Change | Status |
|---|---|---|
| 2026-06-16 | Initial authoring from the personas-vs-capabilities pre-audit; §10 re-checks cleared against shipped infra; paired with ADR 0016. | final |
| 2026-06-16 | Re-verified against the authoritative pre-audit findings (read in full): corrected the crickets "persona"→"role" rename direction (agentm keeps "persona"; crickets' looser usage renames); folded in arbitration as the clause-2 discriminator, the two killed axes (remembers / crosses-plugins), owns-no-engine, the check-personas always-load guard (#46), the three-reason null + honest residual, the opinionation-migration line, and the agent-def-shape framing. |
final |
| 2026-06-16 | Roadmap placement resolved (operator-approved): slotted as V5-12 in the agentm V5 kernel (ROADMAP-MASTER bucket ⑤), sequenced after V5-10 and ahead of V5-11 as its substrate. | final |
| 2026-06-16 |
Parts 1–2 + 4 shipped (V5-11). personas/team-coordinator.md — kind: persona, requires: [queue_status_lite], enhances: [developer-workflows, github-projects]. Four stdlib-only scripts: plan_graph.py (shared map engine), standup.py (worker-state derivation), readiness.py (dep + file-overlap readiness), merge_order.py (topo-sort + diff-size tie-break). 62 fixture-backed tests. check-personas exits 0. Commit: 7966ac3. Part 3 (on-demand load + surfacing path) was not built in V5-11 — [PENDING-IMPL].
|
final |
2026-06-24 — folded ADR 0016 (the persona tier) into this design (AG ADR-migration tail, move-and-retire). ADR 0016 was the decision record paired with this design (the why + the load-bearing calls); the held ADR resolved (design-doc amendment 2026-06-24) and folds here, so this design now records both the mechanism (above) and the decision rationale (below). This design stays — a live, cited sub-contract, now nudged toward living-design shape. (0016 refined AgentM HLD — V5 unbundling, the substrate/plugin binary it adds the missing third tier to.)
The persona tier (2026-06-16; was ADR 0016). Name a third tier — the persona — defined by its dependency direction, not by what it stores: a standing concern that composes capabilities it does not own (arbitrating between them when it composes more than one), is anchored on the neutral substrate, and whose hard deps (requires:) are substrate-native only (soft enhances: may name any capability). It owns no engine — a stance + composition manifest over engines that stay in crickets. The rememberer (the memory engine) is the degenerate persona (zero composed plugins); the Planner (TPM) is the first real persona. The load-bearing calls:
-
DC-1 — the signature is the inverted dependency direction. A plugin is depended upon; a persona composes and is depended on by nothing — it sits above the capability layer, rooted at the substrate. Why not classify by "it remembers" / "stateful": breaks both ways (the Planner (TPM) is stateless; a
security-reviewplugin remembers) — neither necessary nor sufficient. Why not "crosses multiple plugins":github-projectscrossesdeveloper-workflowsand is a plain capability; arbitration + the inverted substrate-only hard-dep direction is the discriminator. -
DC-2 — a persona is a first-class primitive (
kind: personainpersonas/), not a skill, not a sub-agent. Both hosts' dispatch is positive-match (unknownkind:skipped, never rejected); mechanically an agent-def shape, made a persona by tier + home + composition-scope, gate-checkable via the newkind:. Why not a skill: a skill is a capability (the thing a persona composes) — collapses the tier. Why not a sub-agent: sub-agents are read-only ephemeral fan-out; a persona is a durable classification. -
DC-3 — composition reuses
enhances:+ the V5-8 resolver, nocomposes:alias. Why not a new keyword: the soft-composition vocabulary + runtime already exist; a second keyword forks the resolver for identical semantics. -
DC-4 —
requires ⊆ substrate+ no-always-load, enforced bycheck-personas. Mechanically holds the agentm-takes-no-hard-dep-on-crickets + bare-agentm-coherent invariants (the rememberer is the lone always-on exception). Why not allow crickets capabilities inrequires:: inverts the host/plugin relationship, breaks bare-agentm coherence, reintroduces cross-repo coupling. - DC-5 — personas live in agentm, loaded on demand. Why not ship from crickets: a persona must be available regardless of installed plugins (compose-present, degrade-absent) — homing it in crickets couples it to a plugin set and inverts the dependency arrow.
- DC-6 — agentm keeps "persona"; crickets' looser "persona" → "role" rename is doc-only (coordinated with V5-6). Why not rename agentm's tier: "persona" is the load-bearing identity name; the collision is resolved by moving the looser use (crickets' four coordinator roles), not the precise one.
Re-audit triggers: a persona needs multi-provider composition / conflict resolution (then enhances:-reuse is revisited — ADR 0015's "becomes a solver" trigger); either host adds a closed-enum primitive validator that rejects unknown kinds; a persona needs a hard dep only crickets provides (migrate the dep into the substrate, or re-tier the artifact); V5-6 settles agentm's persona/role vocabulary; the underlying model ships a new major (re-audit the tier with the rest of the harness). Resist the persona-zoo — add the next persona only when a real cross-capability arbitration concern with no single-plugin home appears.