SPEC-120 v0.1 — Built-in System Agents
Status: draft (Donna authoring; Texi schema verdict + Candi governance verdict already converged; routing to both for ratification pass) Author: Donna, engineering Created: 2026-05-15 Owner: Donna (engineering implementation + PO ratification); Texi architecture schema; Candi governance + onboarding-loop coupling Related: ADR #48 v0.2 (Persona / Identity / Specialization Field Model — active), SPEC-070 (per-persona daemon model), SPEC-094 (local auto-memory deprecation), SPEC-114 (Sage + Clara customer-care personas — receives a narrowlifecycle=system amendment), SPEC-118 (prism_persona_ratify — DOES NOT apply to system agents per §Ratification Model), SPEC-119 (Hazel — first system agent already shipping under this lifecycle).
Origin
Frank operator directive 2026-05-15 + Cherry’s start-all.ps1 / SPEC-111 rewrite signaledbf048c: while applying home_machine bindings, Cherry surfaced the architectural question of whether Clara, Sage, and Hazel should be “built-in” to the Prism platform rather than project-scoped personas. Architecture verdict from Texi (5a0f3c5d) + governance verdict from Candi (eb33b418) converged independently on a new SPEC codifying a lifecycle classification field plus install-time template ratification + scaffold materialization.
Purpose
Define thelifecycle classification for persona contracts and codify the built-in system agent model — a class of personas that:
- ship as canonical contracts at
$PRISM_ROOT/templates/personas/<name>.jsonwith the Prism install - are pre-ratified at install time, not per-project (no SPEC-118 ratification needed)
- materialize into every newly scaffolded project via
scaffold_servicewithimplicit_bootstrap=false - are never
implicit_bootstrap=true—prism_startrefuses implicit creation when a canonicallifecycle=systemcontract exists for the identity - carry no authority by virtue of
lifecycle=system— runtime authority still derives fromauthority_scope, backend-authorized verbs, bindings, and governance gates
Anchors
- ADR #48 v0.2 field model:
lifecycleis a new top-level persona contract field, distinct fromidentity/surface/specialization/assignment/style. Per Texi binding condition,lifecycleMUST NOT live insideidentity_binding; that block stays the registry identity/alias/dedupe/launch_mode/implicit_bootstrap surface. - SPEC-070 daemon model: system agents follow the same per-persona daemon pattern. Each gets its own daemon/supervision unit; system agents are not backend services and do not share a machine bus.
- SPEC-094 local auto-memory deprecation: system agents route all persistent reads/writes through Prism verbs.
- SPEC-114 Sage + Clara contracts: gets a narrow
lifecycle=systemamendment per this SPEC. - SPEC-118
prism_persona_ratify: explicitly does NOT apply tolifecycle=systemagents. Their ratification is install-time / template-recorded; the per-project ratify verb is for tenant-local personas that began asimplicit_bootstrap=trueor were authored after install. - SPEC-119 Hazel: AC-2 already mandates Hazel scaffold-pre-seed; this SPEC codifies the lifecycle vocabulary that AC-2 manifests.
Non-Goals
lifecycle=system does NOT:
- grant any authority by itself — authority remains in
authority_scope+ backend-authorized verbs + bindings + governance gates - imply auto-launch — auto-launch requires the triple
lifecycle=system+launch_mode(operational policy) + host/install profile or launch overlay - imply elevated/superuser/tenant-cross privileges
- promote
lifecycle=systemagents to backend services or machine-bus singletons — they remain personas with per-instance daemons per SPEC-070 - block tenant overlay of enablement/bindings/home machine — only canonical contract fields (
authority_scope,may_execute, etc.) are Prism-owned-immutable - allow Hazel or any other system agent to author NEW system/standing agents — tenant-local archetype composition stays scoped to draft/triggered per §Tenant Customization Boundary
Decision
Add a top-levellifecycle field to the persona contract schema (.agent/schemas/persona.schema.json). Values (Candi-locked enum):
system— built-in: ships with Prism install, scaffold-pre-seeded into every project, install-time/template ratification, explicit from birth (noimplicit_bootstrap=true).project_standing— long-running project persona, per-persona daemon under SPEC-070, may be authored post-install. Project-scoped.project_triggered— event/cron-driven persona, runs on schedule or signal (e.g. SPEC-109 Researcher). Project-scoped.interactive— operator-launched session, no daemon, lives for the conversation.
project_standing — preserves existing persona-contract semantics on rollout. Existing contracts that omit lifecycle resolve to project_standing. Migration is additive.
lifecycle is contract provenance/classification, NOT operational launch policy. identity_binding.launch_mode stays the operational launch policy. Specs MUST state lifecycle != launch_mode to prevent the confusion.
Naming convention (locked by Candi governance call, signal eb33b418 + Cherry packaging 64a4b652)
Texi flagged a naming ambiguity: standing / triggered overlap with potential launch_mode values. Candi’s governance pick eliminates the overlap with sharp scope-explicit naming:
Locked enum: system | project_standing | project_triggered | interactive (default project_standing).
The project_ prefix on project_standing / project_triggered makes it unambiguous that the agent is project-scoped (vs system which is install-shipped + scaffold-materialized into projects). The lifecycle != launch_mode spec assertion still holds: lifecycle is contract provenance/classification; identity_binding.launch_mode is operational launch policy.
Definitions
Canonical contract: A persona contract committed at$PRISM_ROOT/templates/personas/<name>.json (alongside templates/CLAUDE.md / templates/AGENTS.md / templates/prism-*.md). System agents have canonical contracts; tenant-local agents do not.
Template ratification: The install-time ratification path for lifecycle=system agents. The canonical contract is reviewed + ratified at SPEC ratification time (this SPEC + each system agent’s introducing SPEC); the install ships pre-ratified content. No per-project SPEC-118 prism_persona_ratify invocation is needed for system agents.
Scaffold materialization: The Phase-0 mechanism scaffold_service uses to drop a copy of each canonical contract into a newly scaffolded project at .agent/personas/<name>.json with implicit_bootstrap=false. The copy is a materialization, not a fork — drift between the materialized copy and the canonical template is a repair condition flagged at prism_start time.
Tenant overlay rights: The set of fields a tenant/project may modify on a materialized system agent without violating the canonical-Prism-property invariant. Per Candi: bindings.identity_binding.launch_mode, bindings.home_machine, enablement flags, tenant-local extension agents (not system agents themselves). Fields explicitly NOT overlay-eligible: authority_scope, may_execute, capabilities, canonical_role, specialization.
Ratification Model
prism_persona_ratify (SPEC-118 task #57 implementation) MUST refuse to operate on a lifecycle=system agent. System agents are pre-ratified; calling ratify on them is a category error.
Auto-Launch Policy
lifecycle=system alone does NOT auto-launch. Auto-launch requires the triple:
lifecycle=system(the contract is install-shipped + scaffold-materialized)bindings.identity_binding.launch_modeset to a value that requests auto-launch (e.g.daemon,auto-on-scaffold)- Host/install profile or launch overlay declares this machine + install is eligible (SPEC-111
home_machine+ start-all scripthome_machineguard)
bin/coder.sh, bin/hazel.sh, start-all.sh, start-all.ps1) fires the persona. Operators with -Force / --force-machine overrides can bypass condition 3 for deliberate cross-machine launches; conditions 1 and 2 are not override-able from a launcher (they require contract / binding edit).
Validator Rules
.agent/schemas/persona.schema.json validator MUST enforce, for lifecycle=system:
identity_binding.implicit_bootstrapisfalse(system agents are born explicit)- Contract provenance points at a canonical template path (
$PRISM_ROOT/templates/personas/<name>.json) - When materialized in
.agent/personas/, a correspondingbindings.jsonentry exists for the binding context (scaffold-pre-seed materializes both) lifecycle=systemis NOT insideidentity_binding— it is a top-level fieldlifecycle=systemdoes not grant any authority — schema does not synthesizeauthority_scopeentries from the lifecycle alone
prism_start runtime enforcement MUST:
- Refuse implicit-bootstrap creation when the resolving identity matches a canonical
lifecycle=systemcontract. Surface as “scaffold/registry drift — re-scaffold or re-materialize,” NOT as a new implicit persona row. - Surface materialization drift (canonical-template hash ≠ materialized-copy hash) as a
rules_reminderso operators can re-materialize withprism_sync_bios-equivalent flow (mechanism TBD; tracked in §Open Questions).
Built-in System Agent Roster (v0.1)
Per Frank operator definition (signal64a4b652 Cherry packaging):
Per Candi guardrail #2, cross-project Clara/Sage need tenant/org-scoped signal/read permissions enumerated explicitly and audited. Their materialized contracts specify the scoping; backend authorization enforces tenant isolation at every verb call.
Tenant-Level Bindings (new file-type concept)
Per Cherry packaging64a4b652 + Candi governance eb33b418: the v0.1 binding model is .agent/projects/<pid>/bindings.json — per-PID scope. Clara and Sage operate cross-project within a tenant/org and need a higher-scope binding artifact.
New artifact: .agent/tenants/<tenant_id>/bindings.json (or equivalent — exact path TBD in implementation slice). Carries Clara + Sage binding entries with tenant-scoped signal/read permissions enumerated. Hazel is NOT a tenant-level binding because her scope ends after preseed; she materializes per-project at scaffold time and goes idle.
Project-local references: Clara + Sage entries appear in per-project .agent/projects/<pid>/bindings.json as discoverability references only — they point at the tenant-level binding for routing. Per-project entries do NOT carry independent authority.
Resolution order at prism_start / launcher time:
- Read tenant-level bindings for
lifecycle=systemagents - Read project-level bindings for
lifecycle=project_standing/project_triggered/interactiveagents - Resolve
home_machineoverlay per agent (Cherry’s SPEC-111home_machinemechanism applies uniformly) - Project-level discoverability references for system agents do NOT override the tenant-level binding
- Exact path:
.agent/tenants/<tenant_id>/bindings.jsonvs backend DB tenant-scoped table vs both with the file as projection - Authoring authority: who can edit (Candi? operator? Hazel never)
- Materialization: scaffold seeds it on first install vs explicit
prism_tenant_bindings_initverb - These open questions land as Slice 6 implementation work; v0.1 SPEC specifies the concept and the resolution order, exact mechanism land in Slice 6 PR.
- A new SPEC introducing the agent + its canonical contract
- Architecture review (Texi) on the contract + scaffold-materialization mechanic
- Governance review (Candi) on the authority scope + cross-tenant boundaries
- Donna PO ratification
- This SPEC’s roster table amended in the new SPEC’s PR
Tenant Customization Boundary
Per Candi governance answer (eb33b418):
Tenant/project MAY:
- bind a system agent to a different
home_machine - enable/disable a system agent per project via explicit
enabled: falsein thebindings.jsonentry (never absence-as-disabled; absence means materialization or registry drift, not intentional suppression). For Sage + Clara: project-levelenabled: falsemay suppress project-local discoverability and auto-launch, but does NOT erase tenant-level inherited help/incident routing unless the tenant-level binding is disabled by authorized operator policy. Sage (Prism help) and Clara (incident triage) remain a Prism project mandate inherited by every project. - add tenant-local extension agents (new identities with
lifecycle != system) - compose tenant-local draft/triggered archetypes (Hazel’s Phase-2 capability per SPEC-119)
- mutate canonical contract fields on a system agent (
authority_scope,may_execute,capabilities,canonical_role,specialization) - promote a tenant-local agent to
lifecycle=system(system-agent promotion is a Candi-reviewed PR adding the agent totemplates/personas/+ this SPEC’s roster table) - treat materialization drift as intentional customization — the materialized copy is a refresh-from-template artifact, not a fork
Implementation Slices
Slice 0 — Schema + validator (Donna):- Add
lifecyclefield to.agent/schemas/persona.schema.jsonwith enum + default - Validator rules per §Validator Rules
- Backward-compat: existing contracts without
lifecycledefault toproject_standing - Tests for the validator
- Move canonical contracts for Clara, Sage, Hazel to
$PRISM_ROOT/templates/personas/<name>.jsonif not already there - Update
scaffold_service.pyto materialize the three canonical contracts into every newly scaffolded project at.agent/personas/<name>.jsonwithimplicit_bootstrap=false - Update
bindings.jsonscaffold to include the three system agents - Smoke: scaffold a fresh project, verify three agents materialized with correct
lifecycle=systemfield
prism_start enforcement (Donna):
prism_startrefuses implicit creation when identity matches canonicallifecycle=systemcontract- Materialization-drift detection: surface as
rules_reminderif canonical-template hash ≠ materialized-copy hash - Tests for the refuse path + drift detection
- Amend SPEC-114 Sage + Clara contracts to specify
lifecycle=system - Cross-reference this SPEC
- Amend SPEC-118
prism_persona_ratifyto refuselifecycle=systemidentities - Task #57 implementation honors this
- Implement the
.agent/tenants/<tenant_id>/bindings.jsonartifact (or backend-DB equivalent) per §Tenant-Level Bindings - Clara + Sage binding entries with enumerated cross-project signal/read permissions
- Resolution order at
prism_startand launcher (coder.sh,start-all.{sh,ps1}) - Project-local discoverability references in
.agent/projects/<pid>/bindings.jsonpoint at tenant-level entries
Open Questions
- Materialization-drift repair mechanism — when a canonical-template hash differs from a project’s materialized copy, do we expose a
prism_sync_personasverb, fold intoprism_sync_bios, or surface drift as a rules_reminder only? Donna (PO) call. - System-agent template-version tracking — should
templates/personas/<name>.jsoncarry atemplate_versionfield similar tobios_versionso projects can pin / migrate? Texi call; carry into implementation slices if approved.
enabled: false, never absence-as-disabled. Q4 naming convention resolved in §Decision above — locked enum system|project_standing|project_triggered|interactive, default project_standing, per Candi governance call signal eb33b418.)
Acceptance Criteria
Slice 0 (schema + validator):- AC-1.
.agent/schemas/persona.schema.jsoncarries alifecyclefield with enumsystem|project_standing|project_triggered|interactive, defaultproject_standing(Candi-locked enum per signaleb33b418). - AC-2. Validator rejects
lifecycle=systemwithimplicit_bootstrap=true. - AC-3. Validator rejects
lifecycleplaced insideidentity_binding. - AC-4. Existing contracts omitting
lifecyclevalidate (defaultproject_standing).
- AC-5. Canonical contracts for Clara, Sage, Hazel exist at
$PRISM_ROOT/templates/personas/{clara,sage,hazel}.jsonwithlifecycle: "system". - AC-6.
scaffold_service.pydrops materialized copies of the three contracts into.agent/personas/of every newly scaffolded project, withimplicit_bootstrap=false. - AC-7. Scaffolded
bindings.jsonincludes binding entries for the three system agents. - AC-8. Fresh-scaffold smoke: scaffold a project, inspect
.agent/personas/, verify threelifecycle=systemcontracts present withimplicit_bootstrap=false.
prism_start enforcement):
- AC-9.
prism_startresolving an identity matching a canonicallifecycle=systemcontract refuses to create animplicit_bootstrap=truerow. - AC-10. Materialization drift (canonical hash ≠ materialized hash) surfaces in
rules_remindersat nextprism_start.
- AC-11. SPEC-114 doc carries the
lifecycle=systemdesignation for Sage + Clara.
- AC-12. SPEC-118 doc +
prism_persona_ratifytask #57 implementation refuse to operate onlifecycle=systemidentities.
Cross-references
- ADR #48 v0.2 — Persona / Identity / Specialization Field Model (active;
lifecycleis the 6th top-level field this SPEC introduces) - SPEC-070 — Per-persona daemon model (system agents follow the same pattern)
- SPEC-094 — Local auto-memory deprecation (applies to system agents like everyone else)
- SPEC-111 — Agent Roster Seed and Runtime
.agentLaunch Contract (launcher readsbindings.jsonwhich scaffold-materialization populates) - SPEC-114 — Sage + Clara Customer Care Personas (gets narrow
lifecycle=systemamendment) - SPEC-118 —
prism_persona_ratify(gets narrow amendment refusinglifecycle=system) - SPEC-119 — Hazel Tenant Onboarding Concierge (AC-2 mandates Hazel scaffold-pre-seed; this SPEC codifies the lifecycle vocabulary)
- Cherry start-all.ps1 SPEC-111 rewrite with
home_machineguard (signaledbf048c) - Texi schema verdict signal
5a0f3c5d - Candi governance verdict signal
eb33b418
Authority
Donna authored under engineering-outcome-driver authority and holds PO ratification per Frank operator directive. Texi schema verdict already approved the lifecycle field + 5 binding conditions (signal5a0f3c5d). Candi governance verdict already approved the ratification model + tenant overlay rights + 3 guardrails (signal eb33b418). SPEC-114 + SPEC-118 amendments land in companion PRs after this SPEC ratifies.
