persona tier - alexherrero/agentm GitHub Wiki
Note
Status: launched β all four build parts shipped (2026-07-06). See the amendment log below for build history. Position in arc: refinement of AgentM HLD (the V5 "unbundling" HLD). Roadmap: V5-12 (agentm kernel, ROADMAP-MASTER bucket β€).
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 makes a cross-capability judgment β a call spanning more than one capability that none could make alone (the persona/tool discriminator, owned by personas);
- 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 brain (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 development-lifecycle yet is a plain capability. The discriminator is cross-capability judgment, with the inverted, substrate-only hard-dep direction as its mechanical floor (the canonical test lives in personas).
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 brain is the degenerate case: enhances: [], requires: β substrate.
Composition reuses enhances:. "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 β built 2026-07-06. 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 brain is the implicit always-on degenerate persona; everything else is dormant until invoked. A persona may be surfaced through a sub-agent at activation; even so, it stays a durable classification, not ephemeral fan-out. The surfacing mechanism is specified β and now built β by the persona activation design (build-part 3): persona_resolve.py's adopt() pipeline + persona_compile.py's per-host launch compile.
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 key 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. β 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 development-lifecycle 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: [development-lifecycle, 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
development-lifecycle(queue) +github-projects(board) + substrate. Home it indevelopment-lifecycleand 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 brain; 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 brain 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 brain as a worked example;
check-personascatches the most damaging error (a crickets hard-dep) automatically. -
Surfacing path β built 2026-07-06. How an activated persona's body reaches the agent (injected context vs. on-demand sub-agent) is specified, and now built, by the persona activation design (
build-part 3). The Planner (TPM) manifest (personas/team-coordinator.md) can now be activated β the github-projects Planner build itself (Wave D) is a separate, still-open piece.
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 brain 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 design call here 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 brain manifest). -
check-personasgate (M) βrequires β substrateassertion, wired intocheck-all.sh+ CI, with tests. - On-demand load + surfacing path (M) β built 2026-07-06 β activation β body load, reusing the memory-load path; the surfacing-path open item resolved by the persona activation design.
- First real persona (M, V5-11) β the Planner (TPM) manifest composing dev-loop/board capabilities. Gated behind 1β3.
- The why + key 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 brain-as-degenerate-persona reframe; anenhances:cross-reference from Soft-Composition.
Additive, no flag day β each part lands behind its own gate. The brain 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.
2026-07-06 β rememberer.md β brain.md rename closed. The manifest file rename this tier's prose already assumed throughout is done β personas/rememberer.md is now personas/brain.md (frontmatter name: included), with test fixtures and reference pages updated to match. The four-new-manifest-axes item (below) stays open.
2026-07-06 β build-part 3 ships; all four parts now as-built (AG Wave B leader 4/5). The on-demand load + surfacing path this tier left [PENDING-IMPL] since V5-11 is built β see the persona activation design (persona_resolve.py's adopt() pipeline, persona_compile.py's per-host launch compile, install.sh's persona-walk). The Planner (TPM) manifest can now actually be activated. Two items stay open, and are explicitly NOT this design's doing: the rememberer.md β brain.md file rename this tier's own prose already assumes throughout, and adding the four new manifest axes to the two existing personas β both are code work, not documentation, so neither happened in this wiki-authorship pass.
2026-06-28 β lock-down sweep (operator review). Removed the redundant ## Document History table (the AG convention is amendment-log-only; its build status lives in the launched NOTE, its rationale in the folded ADR 0016 below, granular history in git). No content change to the tier contract. Locked as a v5βv8 guidepost.
2026-06-26 β reconciled the discriminator wording to cross-capability judgment. The Overview + DC-1 led with "arbitrates," which personas had already recorded as superseded by "cross-capability judgment" β but the tier body was never repointed (a one-directional supersession). The body now leads with the live test and keeps the inverted-dependency direction as its mechanical floor, pointing at personas as the canonical home. No change to the rejected near-miss axes or the github-projects counterexample. Re-audit trigger: if the canonical discriminator section in personas is renamed or moved, repoint this body's link.
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 key 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 brain (the memory engine) is the degenerate persona (zero composed plugins); the Planner (TPM) is the first real persona. The key 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-projectscrossesdevelopment-lifecycleand is a plain capability; cross-capability judgment is the discriminator, with the inverted substrate-only hard-dep direction as its mechanical floor β see personas. -
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 brain 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 established 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.