> ## Documentation Index
> Fetch the complete documentation index at: https://prism.ntecdev.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# SPEC-120: Built-in System Agents

> v0.1 lifecycle classification for system personas (Clara, Sage, Hazel) that ship with the Prism install — install-time template ratification, scaffold-pre-seed, no implicit_bootstrap rows, no authority by lifecycle alone.

# 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](/specs/spec-070-v0-2-per-agent-persona-daemon-always-on-listener-bridge-with-turn) (per-persona daemon model), [SPEC-094](/specs/spec-094-v0-5-memorules-delta) (local auto-memory deprecation), [SPEC-114](/specs/spec-114-v0-1-sage-and-clara-customer-care-incident-personas) (Sage + Clara customer-care personas — receives a narrow `lifecycle=system` amendment), [SPEC-118](/specs/spec-118-v0-1-prism-persona-ratify) (`prism_persona_ratify` — DOES NOT apply to system agents per §Ratification Model), [SPEC-119](/specs/spec-119-v0-1-hazel-tenant-onboarding-concierge) (Hazel — first system agent already shipping under this lifecycle).

## Origin

Frank operator directive 2026-05-15 + Cherry's start-all.ps1 / SPEC-111 rewrite signal `edbf048c`: 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 the `lifecycle` 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>.json` with 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_service` with `implicit_bootstrap=false`
* are never `implicit_bootstrap=true` — `prism_start` refuses implicit creation when a canonical `lifecycle=system` contract exists for the identity
* carry **no authority by virtue of `lifecycle=system`** — runtime authority still derives from `authority_scope`, backend-authorized verbs, bindings, and governance gates

v0.1 system agent roster: **Clara** (incident triage, SPEC-114), **Sage** (customer-care intake, SPEC-114), **Hazel** (tenant-admin onboarding concierge, SPEC-119). The lifecycle vocabulary is extensible; future system agents register here and follow the same install/template/scaffold/daemon semantics.

## Anchors

* **ADR #48 v0.2** field model: `lifecycle` is a new top-level persona contract field, **distinct from** `identity` / `surface` / `specialization` / `assignment` / `style`. Per Texi binding condition, `lifecycle` MUST NOT live inside `identity_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=system` amendment per this SPEC.
* **SPEC-118** `prism_persona_ratify`: explicitly does NOT apply to `lifecycle=system` agents. Their ratification is install-time / template-recorded; the per-project ratify verb is for tenant-local personas that began as `implicit_bootstrap=true` or 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=system` agents 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-level `lifecycle` 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 (no `implicit_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.

**Default value:** `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

| Lifecycle           | Ratification Mechanism                                                                                                                             | Where Recorded                                                                                 |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `system`            | Install-time / template ratification at SPEC ratification time                                                                                     | Each system agent's introducing SPEC + this SPEC + `templates/personas/<name>.json` provenance |
| `project_standing`  | Per-project via `prism_persona_ratify` (SPEC-118) when persona row begins as `implicit_bootstrap=true` and is reconciled to its committed contract | Backend `personas` table `implicit_bootstrap=false` flag + binding row + audit event           |
| `project_triggered` | Per-project ratification at first authoring; no implicit-bootstrap path expected                                                                   | Persona contract + cron/event registration                                                     |
| `interactive`       | No ratification needed; ephemeral                                                                                                                  | Session-lived only                                                                             |

`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:

1. `lifecycle=system` (the contract is install-shipped + scaffold-materialized)
2. `bindings.identity_binding.launch_mode` set to a value that requests auto-launch (e.g. `daemon`, `auto-on-scaffold`)
3. Host/install profile or launch overlay declares this machine + install is eligible (SPEC-111 `home_machine` + start-all script `home_machine` guard)

All three must agree before any launcher (`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`:

1. `identity_binding.implicit_bootstrap` is `false` (system agents are born explicit)
2. Contract provenance points at a canonical template path (`$PRISM_ROOT/templates/personas/<name>.json`)
3. When materialized in `.agent/personas/`, a corresponding `bindings.json` entry exists for the binding context (scaffold-pre-seed materializes both)
4. `lifecycle=system` is NOT inside `identity_binding` — it is a top-level field
5. `lifecycle=system` does not grant any authority — schema does not synthesize `authority_scope` entries from the lifecycle alone

`prism_start` runtime enforcement MUST:

* Refuse implicit-bootstrap creation when the resolving identity matches a canonical `lifecycle=system` contract. 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_reminder` so operators can re-materialize with `prism_sync_bios`-equivalent flow (mechanism TBD; tracked in §Open Questions).

## Built-in System Agent Roster (v0.1)

Per Frank operator definition (signal `64a4b652` Cherry packaging):

| Identity  | Scope                                                   | Role                                                                                        | Contract Path                   | Introduced By                                       |
| --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------------------------- |
| **Clara** | tenant-level bindings (cross-project within tenant/org) | tenant-based incident manager; runs on server1 / backend                                    | `templates/personas/clara.json` | SPEC-114 (narrow `lifecycle=system` amendment)      |
| **Sage**  | tenant-level bindings (cross-project within tenant/org) | global Prism assistance + customer service                                                  | `templates/personas/sage.json`  | SPEC-114 (narrow `lifecycle=system` amendment)      |
| **Hazel** | scaffold-seeded into first-project onboarding           | getting-started bootstrap assistant; "agents creating agents"; lifecycle ends after preseed | `templates/personas/hazel.json` | SPEC-119 AC-2 already mandates this materialization |

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 packaging `64a4b652` + 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:**

1. Read tenant-level bindings for `lifecycle=system` agents
2. Read project-level bindings for `lifecycle=project_standing` / `project_triggered` / `interactive` agents
3. Resolve `home_machine` overlay per agent (Cherry's SPEC-111 `home_machine` mechanism applies uniformly)
4. Project-level discoverability references for system agents do NOT override the tenant-level binding

**Open design questions on the tenant-level bindings file:**

* Exact path: `.agent/tenants/<tenant_id>/bindings.json` vs 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_init` verb
* 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.

Additions to the roster (future system agents) require:

1. A new SPEC introducing the agent + its canonical contract
2. Architecture review (Texi) on the contract + scaffold-materialization mechanic
3. Governance review (Candi) on the authority scope + cross-tenant boundaries
4. Donna PO ratification
5. 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: false` in the `bindings.json` entry (never absence-as-disabled; absence means materialization or registry drift, not intentional suppression). For Sage + Clara: project-level `enabled: false` may 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)

**Tenant/project MUST NOT:**

* 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 to `templates/personas/` + this SPEC's roster table)
* treat materialization drift as intentional customization — the materialized copy is a refresh-from-template artifact, not a fork

Per Candi guardrail #3, **Hazel may compose tenant-local draft/triggered archetypes only**. Standing/system agent composition requires a ratification path outside Hazel (a separate SPEC, Candi+Texi review, Donna PO ratification).

## Implementation Slices

**Slice 0 — Schema + validator (Donna):**

* Add `lifecycle` field to `.agent/schemas/persona.schema.json` with enum + default
* Validator rules per §Validator Rules
* Backward-compat: existing contracts without `lifecycle` default to `project_standing`
* Tests for the validator

**Slice 1 — Template + scaffold (Donna + Candi):**

* Move canonical contracts for Clara, Sage, Hazel to `$PRISM_ROOT/templates/personas/<name>.json` if not already there
* Update `scaffold_service.py` to materialize the three canonical contracts into every newly scaffolded project at `.agent/personas/<name>.json` with `implicit_bootstrap=false`
* Update `bindings.json` scaffold to include the three system agents
* Smoke: scaffold a fresh project, verify three agents materialized with correct `lifecycle=system` field

**Slice 2 — `prism_start` enforcement (Donna):**

* `prism_start` refuses implicit creation when identity matches canonical `lifecycle=system` contract
* Materialization-drift detection: surface as `rules_reminder` if canonical-template hash ≠ materialized-copy hash
* Tests for the refuse path + drift detection

**Slice 3 — SPEC-114 amendment (Donna + Candi):**

* Amend SPEC-114 Sage + Clara contracts to specify `lifecycle=system`
* Cross-reference this SPEC

**Slice 4 — SPEC-118 amendment (Donna + Texi):**

* Amend SPEC-118 `prism_persona_ratify` to refuse `lifecycle=system` identities
* Task #57 implementation honors this

**Slice 5 — Tenant-level bindings (Donna + Candi):**

* Implement the `.agent/tenants/<tenant_id>/bindings.json` artifact (or backend-DB equivalent) per §Tenant-Level Bindings
* Clara + Sage binding entries with enumerated cross-project signal/read permissions
* Resolution order at `prism_start` and launcher (`coder.sh`, `start-all.{sh,ps1}`)
* Project-local discoverability references in `.agent/projects/<pid>/bindings.json` point at tenant-level entries

## Open Questions

1. **Materialization-drift repair mechanism** — when a canonical-template hash differs from a project's materialized copy, do we expose a `prism_sync_personas` verb, fold into `prism_sync_bios`, or surface drift as a rules\_reminder only? Donna (PO) call.
2. **System-agent template-version tracking** — should `templates/personas/<name>.json` carry a `template_version` field similar to `bios_version` so projects can pin / migrate? Texi call; carry into implementation slices if approved.

*(Q2 enable/disable mechanism resolved — Candi decision recorded in §Tenant Customization Boundary: use explicit `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.json` carries a `lifecycle` field with enum `system|project_standing|project_triggered|interactive`, default `project_standing` (Candi-locked enum per signal `eb33b418`).
* AC-2. Validator rejects `lifecycle=system` with `implicit_bootstrap=true`.
* AC-3. Validator rejects `lifecycle` placed inside `identity_binding`.
* AC-4. Existing contracts omitting `lifecycle` validate (default `project_standing`).

Slice 1 (template + scaffold):

* AC-5. Canonical contracts for Clara, Sage, Hazel exist at `$PRISM_ROOT/templates/personas/{clara,sage,hazel}.json` with `lifecycle: "system"`.
* AC-6. `scaffold_service.py` drops materialized copies of the three contracts into `.agent/personas/` of every newly scaffolded project, with `implicit_bootstrap=false`.
* AC-7. Scaffolded `bindings.json` includes binding entries for the three system agents.
* AC-8. Fresh-scaffold smoke: scaffold a project, inspect `.agent/personas/`, verify three `lifecycle=system` contracts present with `implicit_bootstrap=false`.

Slice 2 (`prism_start` enforcement):

* AC-9. `prism_start` resolving an identity matching a canonical `lifecycle=system` contract refuses to create an `implicit_bootstrap=true` row.
* AC-10. Materialization drift (canonical hash ≠ materialized hash) surfaces in `rules_reminders` at next `prism_start`.

Slice 3 (SPEC-114 amendment):

* AC-11. SPEC-114 doc carries the `lifecycle=system` designation for Sage + Clara.

Slice 4 (SPEC-118 amendment):

* AC-12. SPEC-118 doc + `prism_persona_ratify` task #57 implementation refuse to operate on `lifecycle=system` identities.

## Cross-references

* ADR #48 v0.2 — Persona / Identity / Specialization Field Model (active; `lifecycle` is 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 `.agent` Launch Contract (launcher reads `bindings.json` which scaffold-materialization populates)
* SPEC-114 — Sage + Clara Customer Care Personas (gets narrow `lifecycle=system` amendment)
* SPEC-118 — `prism_persona_ratify` (gets narrow amendment refusing `lifecycle=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_machine` guard (signal `edbf048c`)
* 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 (signal `5a0f3c5d`). 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.
