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.

AgentM Persona Activation Design

Objective

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).

Overview

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.

The activation pipeline: a persona is selected (explicit invocation or a workflow step; auto-detection is research-open), passes the check-personas gate, loads its manifest on demand, resolves its three bindings through their own resolvers (tier via model-effort routing, opinions via opinion_resolve, capabilities via capability_resolver), composes stance + tools + Memory beneath, and runs in its mode; on the sub-agent path it compiles down to a host agent-def or SKILL.md wrap

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.

Design

Selection β€” three paths, two ship

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 /goal runner, 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 β€” /work wears the Engineer, /review wears 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.

Selection policy

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 /review does 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: and opinions: bindings ambiguous and break single-threaded coherence.

Adoption β€” the pipeline

adopt(persona, mode) runs six steps:

  1. Select β€” resolve the persona name to its manifest in personas/ (an explicit name, or the persona the phase step declares).
  2. Gate β€” the manifest must pass check-personas (its requires: resolve to substrate). A manifest that fails the gate is never adopted.
  3. Load on demand β€” read the manifest body now, reusing the on-demand memory-load path. brain is always-on through the recall hook; every other persona is dormant until adopted.
  4. Resolve bindings β€” fold the three axes through their resolvers (below).
  5. Compose β€” the stance (the manifest body) + the resolved tools (from enhances:) + Memory beneath become the working persona. An absent enhances: tool degrades to absence; the persona still runs on a bare agentm.
  6. Run β€” realize the mode: injected context for an interactive session, a dispatched sub-agent (cold or warm), a scheduled /loop, or a /goal runner. 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.

The manifest β€” five built fields, four new axes

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.

Binding resolution β€” through their own resolvers, one-way

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.

How it launches on each host

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's subagent_type, triggers: β†’ the description (the host's auto-route trigger, which the host enforces), tier: β†’ the model: + effort frontmatter, the enhances:-resolved tools β†’ the tools: 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-on brain recall fires through hooks.
  • Antigravity β€” no first-class sub-agent slot, so a persona compiles to a SKILL.md wrap (the existing sub-agent-as-skill pattern); the parent agent reasons over the skill description and delegates through the runtime start_subagent tool. 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.

Enforcement

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: and enhances: β€” resolution stays a runtime, graceful concern (mirroring opinion_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: true for every persona; brain is always-on through the session-start recall hook.

The boundary

  • vs the opinion registry β€” the registry owns opinion_resolve (base βŠ• supplement); activation calls it at adoption to bind a persona's opinions:. 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.py owns 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 or SKILL.md and 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.

Dependencies

  • calls the three resolvers β€” capability_resolver.py (built), plus the opinion registry's opinion_resolve and 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.py gains the four new-axis checks; the primitive + the gate stay owned by persona tier.
  • rides the host dispatch β€” Claude Code agent-defs (Task subagent_type + description routing) and Antigravity's SKILL.md + start_subagent; install.sh learns personas/.
  • 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.

Migrations

  • Done. Repointed persona tier's build-part-3 [PENDING-IMPL] to name this design as its specification (2026-07-06); the persona-activation seeding row + the real governs: glob are stamped in the area-taxonomy (no new area β€” it joins persona-tier there).
  • Partly done at build: extended check-personas.py for the four axes; wrote the adoption path (persona_resolve.py / adopt); taught install.sh to dispatch personas/. Done (2026-07-06): renamed the persona file personas/rememberer.md β†’ personas/brain.md (frontmatter name: 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.

Risks & open questions

  • 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.

Locked design calls

  • 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 walk personas/ 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_resolve stays pure, mirroring capability_resolver / opinion_resolve.

References

  • The resolver precedents (built): scripts/capability_resolver.py (the one-way enhances: 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-defs install.sh dispatches; subagent_type / description / model: are the Claude-Code dispatch form the compile step produces) Β· install.sh (the agent-dispatch path + the Antigravity SKILL.md wrap)
  • 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)

Amendment log

Newest first. Collapses to one ≀2-paragraph entry at finalization; git holds the granular history.

  • 2026-07-06 β€” rememberer.md β†’ brain.md rename 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 (the adopt() pipeline: select β†’ gate β†’ load β†’ resolve-bindings β†’ compose) + scripts/persona_compile.py (per-host launch: Claude Code agent-def, Antigravity SKILL.md) + install.sh's persona-walk block ship. check-personas.py extended for the four manifest axes. governs: now points at both new scripts. Design-fidelity correction found during build: requires: is NOT re-resolved through capability_resolver.py as this design's Dependencies section originally implied β€” it's validated at the gate only (an agentm scripts/ stem, ADR 0016 DC-4's existing invariant); only enhances: binds through the capability resolver. Two items stay open, deliberately out of this build's scope: the rememberer.md β†’ brain.md rename, 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; Antigravity SKILL.md + start_subagent); extends the built check-personas gate 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 + runtime adopt()); 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.

⚠️ **GitHub.com Fallback** ⚠️