VIRGO · SPEC

Persona Capability Surface v1

Approved 2026-08-04. The contract that gives a persona its tools and permissions in one factory stamp.

# Persona capability surface v1

Status: approved by Henry on 2026-08-04

This contract defines the factory stamp that gives a persona its runtime tools
and permissions. It deliberately replaces per-incident tool additions and
per-tool prompt opening.

## One stamp, three consumers

The factory writes one owner-private `CAPABILITY-STAMP.json` into each active
persona generation. The stamp is immutable for that generation and is covered
by its composition hash. Three runtime components consume the same records:

1. the MCP/channel server exposes exactly `tools[].name`;
2. the handler authorizes the matching `tools[].handler_action`, `access`, and
   `scope`; and
3. the launcher passes exactly `tools[].name` as its tool allowlist.

No component keeps a second hand-written allowlist. Startup fails if the stamp
is missing, malformed, has duplicate names/actions, or cannot be projected to
all three consumers without loss.

## Policy shape

The default is positive: ordinary, recoverable work inside the persona's own
declared scope is allowed. A tool is present only when its class needs it. An
exposed tool has `access: allow` or `access: confirm`; denied capabilities are
not exposed.

Only these global boundaries exist in v1:

- confirm credential or permission changes;
- confirm destructive or materially irreversible operations;
- confirm consequential external publication or deployment outside standing
  delegation;
- deny reading or exporting secret credential values;
- deny exporting lease/fence/authority material; and
- deny cross-workspace or cross-persona access outside an explicit binding.

An exact blocked operation may be learned through the prompt registry. The
stored choice is keyed by stamp hash, handler action, normalized target scope,
and operation shape. It cannot broaden the class profile or survive a changed
stamp without review.

Confirmation is routed, not inferred. A global-boundary confirmation goes to
the persona's bound human authority through `virgo-channel`; a deputy-scope
confirmation goes to the owning lead. The decision record stores the requester,
authority binding, normalized operation, stamp hash, decision, and correlation
id before execution. A model cannot confirm its own request.

Learned prompt fingerprints live in the persona experience layer. A prompt
that is genuinely class-common may instead live in the shared class overlay.
Both locations travel with the snapshot; machine-local session memory is not a
prompt registry.

## Standard ordinary surface

Every persona class receives:

- workspace listing, metadata, hash, and paginated/ranged reads;
- atomic writes to the mutable paths declared in its own workspace binding;
- coordination inbox list/ack, broker send, wake reconciliation, presence
  summary/activity, peer listing, and redacted sender lookup;
- decision list/raise and task list/get/report for work it owns;
- read-only bounded graph context queries; and
- read-only access to the persona's own conversation-archive lineage through
  the graph query service (other personas' archives remain out of scope); and
- a delivery envelope containing registry-derived sender project, agent, peer
  id, and instance/fence provenance. Labels are attribution, not authority.

Workspace writes are recoverable and confined by the materialization stamp.
For a normal persona this includes `QUEUE.md`, `DECISIONS.md`, `FINDINGS.md`, and
`memory/**`; class overlays may add project worktrees. Reads support byte offset
and length and return continuation metadata, so a large operational file never
becomes unreadable.

Human-surface reactions return a definitive terminal result:
`applied: true` or `applied: false` with a reason. `unknown` is not a terminal
success and remains retryable under the same correlation id.

## Class matrix

`R` means read/use, `W` means mutate within stamped scope, `C` means the tool is
exposed but requires confirmation for the described boundary, and `-` means it
is not exposed.

| Capability bundle | secretary | team-coordinator | project-lead | coder-deputy |
| --- | --- | --- | --- | --- |
| standard workspace and coordination | R/W | R/W | R/W | R/W |
| peer verification and presence | R/W | R/W | R/W | R/W |
| bounded graph context query | R | R | R | R |
| decisions: list / raise | R/W | R/W | R/W | R/W |
| decisions: resolve | W¹ | W² | W | - |
| tasks: list / get / report | R/W | R/W | R/W | R/W |
| tasks: assign | W | W | W | - |
| runs and artifacts | R | R | R/W | R/W (assigned task) |
| human messages, replies, ack, typing | W (bound surfaces) | W (bound surfaces) | - | - |
| reaction catalogue and apply | W | W | - | - |
| cards, todo cards, file send | W | W | - | - |
| human-surface/gateway status | R | R | R | R |
| deployment/publication | C | C | C | C |

Human-surface tools target the hub service through `virgo-channel`; persona
stamps contain bindings, never channel credentials or gateway setup.

¹ A secretary resolves a decision only as a durable relay of the bound human
authority's explicit decision. ² A team coordinator resolves only when the
bound lane approver authorizes that decision. Neither class self-originates a
resolution.

## Required tool inventory

Tool names are transport-neutral public contracts. A v1 factory must resolve
the following names for each class according to the matrix:

- workspace: `workspace_list`, `workspace_stat`, `workspace_hash`,
  `workspace_read`, `workspace_write`;
- identity/presence: `list_peers`, `lookup_sender`, `set_summary`,
  `set_activity`, `reconcile_wake`;
- coordination: `send_broker_message`, `list_coordination_messages`,
  `ack_coordination_message`;
- decisions: `list_decisions`, `raise_decision`, `resolve_decision`;
- tasks: `list_tasks`, `get_task`, `report_task`, `assign_task`;
- runs: `list_runs`, `get_run`, `create_run`, `advance_run`,
  `append_run_event`, `record_artifact`;
- knowledge: `query_graph_context`;
- human surface: `send_human_message`, `reply_human_message`,
  `ack_human_message`, `start_typing`, `stop_typing`,
  `list_reaction_ids`, `apply_human_reaction`, `send_human_card`,
  `send_human_todo`, `send_human_file`, `get_human_surface_status`.

The stamp may add versioned tools later, but cannot silently omit a required
tool for its class. Boot validation reports the exact missing tool and refuses
to advertise the persona as standing.

## Factory and runtime acceptance

The factory must:

1. resolve the class profile plus persona bindings into one stamp;
   when no workspace is supplied, bind the persona to the installation's implicit
   default workspace `home` (the control plane remains workspace-free);
2. validate it against the JSON Schema and semantic validator;
3. hash it into the persona composition;
4. derive all three consumer projections from that exact file; and
5. prove at boot that every handler and transitive runtime binding exists.

The repository's first factory projection is
`scripts/build-capability-stamp.mjs`. It takes persona identity, composition
hash, workspace, graph namespace, and human-surface bindings as input and emits
one private stamp for any of the four classes. The JSON Schema and semantic
validator both run
before the file is emitted; the runtime consumers remain the next integration
step.

Acceptance tests must prove projection equality, all required class tools,
default-allow recoverable workspace work, ranged reads, strict scope binding,
definitive reaction outcomes, prompt-registry exact matching, and loud refusal
for each global boundary.