agentm persona activation - alexherrero/agentm GitHub Wiki
Persona activation is how agentm puts on a persona β the Engineer, the Reviewer, the Planner β and gives it the right model, standards, and tools for the job. Built 2026-07-06 (
scripts/persona_resolve.py+scripts/persona_compile.py) β parent agentm HLD.
A persona is a hat the agent wears for a job β the Engineer, the Reviewer, the Planner β each borrowing tools from the toolbox without owning them. The persona tier design already built the parts a persona is made of: the persona file format, the check that validates it, the always-on brain (the memory engine that sits under every persona), and a first Planner persona. The step that puts a persona on while the agent is running β picking it, loading it, and giving it its model, standards, and tools β is this design, and it shipped 2026-07-06.
As-built: persona_resolve.py's adopt(name, mode) runs select β gate β load β resolve-bindings β compose (steps 1-5 of the six below); persona_compile.py + install.sh's persona-walk realize step 6 (the per-host launch) for the sub-agent mode. The Planner persona can now actually be activated. Several neighboring designs still lean on pieces of their own: model + effort routing's own tier-scale build is separate (this design's tier: binding calls its declared resolver contract regardless), and automatic switching stays research-open (below).
Activation is a short pipeline with one job β turn a named persona into a running one β built to the shape of the resolvers agentm already has: pure, one-way, and graceful when a binding is absent.
A persona is selected, gated, loaded on demand, has its three bindings resolved through their own resolvers, composed with Memory beneath, and run in its mode. On the sub-agent path it compiles down to the host's native dispatch.
A persona is chosen for a task one of three ways. v1 ships the first two; the third stays research-open (operator ruling).
-
Explicit invocation. The operator launches a named persona in a mode it declares β a session wearing the hat, a
/loop, a/goalrunner, or a dispatched sub-agent. Fully tractable; the v1 floor. -
Workflow-step adoption. A crickets phase command puts the fitting persona on for its step β
/workwears the Engineer,/reviewwears the Reviewer. This rides the phase command: the phase spec names the persona to adopt, so it is deterministic and makes adoption feel native. -
Auto-detection from the task (research-open). A mid-conversation cue selects a persona β a design question surfaces the Designer, a failing diagnosis the Troubleshooter. Reliable mid-conversation intent classification to swap stance is an unsolved problem: there is no trigger grammar, confidence gate, false-switch ceiling, or per-turn cost budget for it yet. The design carries the cue as the
triggers:field and binds it only on the sub-agent path, where the host does the routing; automatic in-session stance-swap stays research-open.
Five calls settle how selection behaves once more than the happy path is in play:
-
The phase spec is the source of truth for a workflow step. A crickets phase names the persona to wear; a manifest's
triggers:field feeds only the sub-agent routing path, so the same field never becomes a second, competing selector. -
An explicit choice wins. Precedence runs explicit invocation > workflow-step > auto-detection, so an operator's chosen stance is never silently overridden and auto-detection is the lowest tier. A workflow-step adoption on the sub-agent path is per-dispatch β a cold Reviewer dispatched by
/reviewdoes not contend with the stance worn in the interactive session. - There is no default opinionated persona. When nothing is selected, the working stance is the brain alone (Memory plus the bare agent); wearing an opinionated persona is always an explicit or workflow-step act.
- Operator-initiated switching ships; automatic switching does not. Re-invoking adoption in a session re-runs the pipeline and swaps the stance β an explicit operator act. Only cue-driven automatic switching stays research-open, because the hard part is reading intent, not the swap itself.
-
One opinionated stance at a time, with the brain beneath. An agent wears one stance plus the brain; a persona that needs another β a Tech-Lead needing a Reviewer β dispatches it as a sub-agent. Stacking two stances would make the
tier:andopinions:bindings ambiguous and break single-threaded coherence.
adopt(persona, mode) runs six steps:
-
Select β resolve the persona name to its manifest in
personas/(an explicit name, or the persona the phase step declares). -
Gate β the manifest must pass
check-personas(itsrequires:resolve to substrate). A manifest that fails the gate is never adopted. -
Load on demand β read the manifest body now, reusing the on-demand memory-load path.
brainis always-on through the recall hook; every other persona is dormant until adopted. - Resolve bindings β fold the three axes through their resolvers (below).
-
Compose β the stance (the manifest body) + the resolved tools (from
enhances:) + Memory beneath become the working persona. An absentenhances:tool degrades to absence; the persona still runs on a bare agentm. -
Run β realize the mode: injected context for an interactive session, a dispatched sub-agent (cold or warm), a scheduled
/loop, or a/goalrunner. The Reviewer runs cold on the sub-agent path, for adversarial independence.
Memory beneath is automatic. Every persona is Memory plus a stance β recall at the start, reflect at the end β so the brain composes under every adoption as a built-in pipeline step. The manifest carries no Memory axis; the pipeline supplies it.
A persona stays an ordinary agent-def: an opinionated prose body, an optional model: and read-only tools:, and its declared deps. The gate validates three invariants today (kind, requires: β substrate, no always-load); activation adds four declared axes, each wired into the gate as part of this build.
---
kind: persona # the primitive β gate-checked (must be "persona")
name: reviewer # the dispatch key / filename
requires: [...] # hard deps β gate-checked: must resolve to substrate
enhances: [code-review] # soft composition β any capability; an unmet one degrades
always_load: false # the gate rejects always_load: true for every persona
# --- added by activation ---
tier: T2 # T0 Mechanical β¦ T4 Deep β declared here, the scale owned by model-effort routing
opinions: [good] # the Opinion surfaces it leans on β resolved via opinion_resolve
modes: [sub-agent, interactive] # the launch modes it supports β subset of {sub-agent, interactive, loop, goal}
triggers: [review-phase] # automatic-adoption signals β a workflow-step name, or a cue compiled to the host description
---
The stance β the opinionated prompt body.The persona's working state is not in the manifest; it comes from Memory beneath.
Each binding resolves through the resolver that owns it; activation applies the result and never reaches back. All three resolvers are pure and never raise, so a missing binding degrades gracefully and adoption still completes.
-
tier:β the model + effort routing scale (defined in that design, not in agent memory). The tiers are a five-rung model-and-effort ladder: T0 Mechanical (cheapest model, low effort β rote edits, log-scraping), T1 Execute (opusplan, medium effort β long autonomous build stretches), T2 Author (strongest model, high effort β planning, design, holding the technical bar), T3 Architect (strongest, max effort β cross-system design and roadmap calls), and T4 Deep (strongest, max effort plus orchestration β research and adversarial audit). Activation resolves the persona's declared tier to a concrete model + effort and applies it; the persona declares its tier, the routing design owns the scale. -
opinions:βopinion_resolve(name)from the opinion registry, folding the coded base β the learned supplement, always-latest. The persona-adoption seam is exactly the consumer the registry named as activation-blocked. -
enhances:/requires:βcapability_resolver.py.requires:is hard (gate-floored to substrate);enhances:is soft (absent β graceful degrade).
The arrows run one way β persona β opinions, persona β capabilities, persona β tier scale. Nothing depends back on the persona.
Activation uses each host's own way of launching an agent, so it adds no per-host machinery of its own. The work splits two ways (hybrid): for a dispatched sub-agent, the installer turns each persona into a host-native agent definition at install time, so the host's built-in routing picks it up; for an interactive session, a /loop, or a /goal run, a persona is put on at run time by injecting it into the session. A small, pure helper β persona_resolve, modeled on capability_resolver and opinion_resolve β does the install-time conversion.
-
Claude Code β the sub-agent path compiles a persona to an agent-def:
nameβ the Task tool'ssubagent_type,triggers:β thedescription(the host's auto-route trigger, which the host enforces),tier:β themodel:+ effort frontmatter, theenhances:-resolved tools β thetools:allowlist. The interactive, loop, and goal modes ride injected context + slash commands, where model choice is advisory only (a host can nudge/model). The always-onbrainrecall fires through hooks. -
Antigravity β no first-class sub-agent slot, so a persona compiles to a
SKILL.mdwrap (the existing sub-agent-as-skill pattern); the parent agent reasons over the skill description and delegates through the runtimestart_subagenttool. Hooks have no Antigravity surface, so the brain's hook-driven recall is Claude-Code-only.
install.sh learns to dispatch personas/ β today its agent dispatch walks harness/agents/ only. The per-host consequence to state plainly: detection-via-triggers: is enforceable on the sub-agent/description path on both hosts; in-session stance-swap is advisory on both.
Extend check-personas.py (the built gate β exit 0/1/2, in check-all.sh + CI across Linux/macOS/Windows) to validate the four new axes without breaking the three built invariants:
-
modes:β{sub-agent, interactive, loop, goal};tier:β{T0β¦T4};triggers:well-formed (a workflow-step name or a cue string);opinions:entries are strings. -
Shape only for
opinions:andenhances:β resolution stays a runtime, graceful concern (mirroringopinion_available), so an unmet binding degrades at runtime and never fails the build. - Keep the one-way-arrow invariant: a persona's
requires:stays β substrate β this is what keeps agentm from hard-depending on crickets. - Keep the no-always-load invariant: the gate rejects
always_load: truefor every persona;brainis always-on through the session-start recall hook.
-
vs the opinion registry β the registry owns
opinion_resolve(base β supplement); activation calls it at adoption to bind a persona'sopinions:. The registry's CLI + composition-edge consumers work before activation exists; only its persona-axis consumers wait on this. -
vs the capability resolver β
capability_resolver.pyowns name β installed-capability matching; activation composes the resolved tools into the running persona. - vs model + effort routing β that design owns the T0βT4 scale + per-host rendering; activation applies the declared tier at adoption.
- vs persona tier β that design owns the primitive and the gate (the persona-vs-tool discriminator is owned by personas); this design is its build-part 3 (load-on-demand + the surfacing/activation path), the one part V5-11 did not ship.
-
vs the host dispatch β the host owns
Task/start_subagent+ description-routing; activation compiles a persona down to the host's agent-def orSKILL.mdand rides those rails. A persona is a layer above a host sub-agent β surfaced through one on the cold-dispatch path, while remaining a durable classification that outlives any single dispatch.
-
calls the three resolvers β
capability_resolver.py(built), plus the opinion registry'sopinion_resolveand the model + effort routing scale (both designed, building in the same wave). All are pure, one-way, and never raise. -
extends the built gate β
check-personas.pygains the four new-axis checks; the primitive + the gate stay owned by persona tier. -
rides the host dispatch β Claude Code agent-defs (
Tasksubagent_type+descriptionrouting) and Antigravity'sSKILL.md+start_subagent;install.shlearnspersonas/. -
composes Memory beneath β the always-on
brain(memory system) sits under every adoption. - points up at persona tier (build-part 3) and the agentm HLD Β§Personas; the crickets side of the wiring is composition.
-
Done. Repointed persona tier's build-part-3
[PENDING-IMPL]to name this design as its specification (2026-07-06); thepersona-activationseeding row + the realgoverns:glob are stamped in the area-taxonomy (no new area β it joins persona-tier there). -
Partly done at build: extended
check-personas.pyfor the four axes; wrote the adoption path (persona_resolve.py/adopt); taughtinstall.shto dispatchpersonas/. Done (2026-07-06): renamed the persona filepersonas/rememberer.mdβpersonas/brain.md(frontmattername:included), with its test fixture (test_persona_resolve.py) and the reference pages that named it (persona-tier-schema.md,Completed-Features.md) updated to match. Still open: adding the four new axes to the two existing manifests (brain,team-coordinator) β a separate code change, out of scope for the rename. -
Status honesty β done. Persona-tier's build-part-3 and the neighbor
[PENDING-IMPL]markers flip to as-built in this same pass. The Planner seed and the β₯4-deep board depth still stay hand-maintained until the github-projects Planner (TPM) build lands (Wave D) β activation makes the Planner activatable, it does not make board-depth maintenance automatic.
- Buildability illusion. Activation is the third link in the github-projects β₯4-deep stack (board depth β Planner β activation β opinion registry); each dependent reads "designed" while leaning on this unbuilt seam. Until it ships, the board depth decays and is hand-maintained; no dependent should claim "done" on an unactivatable seed.
-
Auto-detection is an open design problem. Mid-conversation stance-swap has no trigger grammar, confidence gate, false-switch ceiling, or cost budget β so it stays research-open, split from the explicit + workflow-step path; marking it
[PENDING-IMPL]would re-introduce the hazard. -
Per-host asymmetry. Detection-via-
triggers:is enforceable only on the sub-agent/description path; in-session stance-swap and model choice are advisory on both hosts. A reader should not assume symmetric enforcement in interactive sessions. - Coupled bet. The roster, automatic adoption, and tier-enforcement all stand on this one seam β sequence them as one Wave-B leader feeding Wave-D adopters; none ships independently.
- Resist the persona-zoo. Activation makes adding a persona cheap; add the next one only when a real cross-capability concern with no single-plugin home appears.
-
Re-audit triggers: flip persona-tier build-part-3 + the neighbor
[PENDING-IMPL]markers at ship; design the in-session detection mechanism before promoting auto-detection off research-open; re-pin the host-seam details if a host changes its dispatch surface.
-
Selection ships explicit + workflow-step; auto-detection stays research-open (operator ruling) β the
triggers:field is authored and bound on the sub-agent/description path; automatic in-session stance-swap stays research-open. -
Selection policy (operator) β the phase spec is authoritative for a workflow step (
triggers:feeds only sub-agent routing); precedence is explicit > workflow-step > auto-detection; no default opinionated persona (the brain alone); operator-initiated switching ships, automatic switching stays research-open; one opinionated stance at a time with the brain beneath (multi-persona by dispatch). See Β§Selection policy. - Memory beneath is automatic β every persona is Memory + a stance; the brain composes under every adoption as a pipeline step the manifest never declares.
- Bindings resolve through their own resolvers, one-way and never-raise β activation applies the result; a missing binding degrades, it does not fail adoption.
- Activation is persona-tier's build-part 3 β it owns the load-and-surface path; the primitive and the gate stay with persona-tier.
-
No per-host runtime adapter β a persona compiles down to the host's native agent-def /
SKILL.md; the installer learns to walkpersonas/and emit each persona in the host's form. -
The adoption logic is hybrid (operator ruling) β the sub-agent path compiles at install time (riding the host's description-routing); a runtime
adopt()serves the interactive / loop / goal modes that inject context.persona_resolvestays pure, mirroringcapability_resolver/opinion_resolve.
-
The resolver precedents (built):
scripts/capability_resolver.py(the one-wayenhances:resolver) Β·scripts/governs_resolver.py(the markdown-data, never-raise shape) -
The gate to extend:
scripts/check-personas.py(the built persona validator βkind/requiresβ substrate / no-always-load) -
The host dispatch to ride:
harness/agents/*.md(the agent-defsinstall.shdispatches;subagent_type/description/model:are the Claude-Code dispatch form the compile step produces) Β·install.sh(the agent-dispatch path + the AntigravitySKILL.mdwrap) -
The seeds that run today:
personas/brain.md(the degenerate always-on persona) Β·personas/team-coordinator.md(the Planner (TPM) seed + its built capability scripts) - Up: persona tier (build-part 3) Β· personas (the roster + adoption) Β· agentm HLD Β§Personas
- Calls / composes: opinion registry Β· model + effort routing Β· memory system (Memory beneath) Β· composition (the crickets wiring)
Newest first. Collapses to one β€2-paragraph entry at finalization; git holds the granular history.
-
2026-07-06 β
rememberer.mdβbrain.mdrename closed. The rename this build's entry (below) deliberately left out of scope is now done:personas/rememberer.mdβpersonas/brain.md, with the test fixture and reference pages updated to match. The four-manifest-axes item stays open. -
2026-07-06 β built (AG Wave B leader 4/5).
scripts/persona_resolve.py(theadopt()pipeline: select β gate β load β resolve-bindings β compose) +scripts/persona_compile.py(per-host launch: Claude Code agent-def, AntigravitySKILL.md) +install.sh's persona-walk block ship.check-personas.pyextended for the four manifest axes.governs:now points at both new scripts. Design-fidelity correction found during build:requires:is NOT re-resolved throughcapability_resolver.pyas this design's Dependencies section originally implied β it's validated at the gate only (an agentmscripts/stem, ADR 0016 DC-4's existing invariant); onlyenhances:binds through the capability resolver. Two items stay open, deliberately out of this build's scope: therememberer.mdβbrain.mdrename, and adding the four axes to the two existing persona manifests. -
2026-06-28 β lock-down sweep (operator review). All standing fixes clean (diagram sized; no mermaid; no ADR mentions; log already newest-first). Confirmed the selection policy (explicit + workflow-step; auto-detection research-open) and the resolver-shape build (pure Β· one-way Β· never-raise; per-host agent-launch). No content change. Locked as a v5βv8 guidepost.
-
2026-06-26 β authored, reviewed, and finalized. The fourth Bucket-A substrate sub-design (after runner, reporting, and the opinion registry), specifying persona-tier's build-part 3 β the step that puts a persona on at runtime: it picks a persona, loads its file on demand, sets its model + standards + tools through their own resolvers, composes the brain beneath, and runs it in its mode. Built to the resolver shape agentm already has (pure, one-way, never-raise); uses each host's own agent-launch (Claude Code agent-def +
Task; AntigravitySKILL.md+start_subagent); extends the builtcheck-personasgate for four new manifest axes (tier:/opinions:/modes:/triggers:). Operator calls: selection = explicit + workflow-step (auto-detection research-open) plus the five-part selection policy (phase-authoritative Β· explicit-wins Β· brain-only default Β· operator-switching-only Β· one-stance-with-the-brain-beneath); Memory beneath automatic; bindings one-way + never-raise; activation is build-part 3 (the primitive + gate stay with persona-tier); no per-host adapter; hybrid adoption (install-time compile + runtimeadopt()); the always-on persona is named the brain. Re-audit: flip persona-tier build-part-3 + neighbor[PENDING-IMPL]at ship; design in-session detection before promoting auto-detection.