Skip to content

Writing Personas

GhostFrame edited this page May 25, 2026 · 2 revisions

Writing Personas

Minimum viable persona

A persona is a directory with a pack.toml manifest:

my-persona/
  pack.toml
schema_version = 1
name = "my-persona"
author_handle = "your-handle"
author_pubkey = "UNSIGNED"
version = "0.1.0"
license = "Elastic-2.0"

[capability_manifest]
required_tools = ["Read", "Edit", "Write", "Bash", "Grep", "Glob"]
network_egress = false
filesystem_scope = "project-only"
memory_required = "none"
memory_required_ops = []

Install it:

frameshift install my-persona@0.1.0 --from-path ./my-persona

Capability manifest

The manifest declares what the persona needs from the host environment:

Field Type Description
required_tools string array Tools the persona expects (Read, Edit, Write, Bash, Grep, Glob, etc.)
network_egress bool Whether the persona needs outbound network access
filesystem_scope string "project-only" or "system"
memory_required string "none", "optional", or "required"
memory_required_ops string array Memory operations needed: "store", "search", "recall", "context"
primary_intents string array (optional) Task categories this persona handles best
anti_keywords string array (optional) Tokens that repel the selection engine away from this persona

Primary intents

Ten recognized intents: implementation, debugging, review, security, writing, ops, testing, refactoring, performance, design.

Declaring primary intents lets automate mode match personas to tasks more accurately.

Anti-keywords

Anti-keywords score negatively in the selection pipeline. A cryptographic persona might declare anti_keywords = ["frontend", "css", "react"] to avoid being selected for UI work.

Typed source format (advanced)

Beyond the pack manifest, Frameshift supports a structured TOML source format with four files:

my-persona/
  pack.toml       # Manifest
  persona.toml    # Identity, voice, anchor, classification tiers, self-eval
  rules.toml      # L1/L2 rules with reasoning
  skills.toml     # Skill declarations
  patterns.toml   # Code patterns and anti-patterns

persona.toml

Defines identity, voice, cascade anchors, classification tiers, conflict resolution stance, and self-evaluation hooks.

schema_version = 1
name = "my-persona"
version = "0.1.0"
description = "One-line description of what wakes up."
license = "Elastic-2.0"

[author]
handle = "your-handle"
pubkey = "ed25519:UNSIGNED"

[anchor]
tagline = "Short identity statement."
text = '''
Multi-line L2 anchor. This is the coherent stance that survives
drift. Write it as who the agent IS, not what it does.
'''
default_question = "The question the agent asks before acting."

[voice]
tone = "Describe the voice: precise, careful, opinionated, etc."
text = '''
How the agent communicates. What it prioritizes in expression.
'''

[[voice.questions]]
text = "Forced question the agent asks itself."

[[classification_tiers]]
name = "TIER_NAME"
description = "What this tier means."
guidance = "How the agent should act at this tier."

[conflict_resolution]
stance = "The coherent stance restated for mid-context re-anchoring."

[[cascade_anchors]]
position = "mid"
text = "Re-anchor at the middle of the persona."

[[cascade_anchors]]
position = "end"
text = "Re-anchor at the end of the persona."

[[self_eval]]
step = "Checklist item the agent runs before non-trivial actions."

[growth]
dual_write_tags = "context:my-persona"
dual_write_source = "claude-code:my-persona"

rules.toml

L1 rules are hard constraints -- never-do rules with reasoning attached. They encode scar tissue from real incidents and survive context erosion better than soft guidance.

schema_version = 1

[[rule]]
id = "unique-rule-id"
layer = "L1"
text = "The rule statement."
reasoning = "Why this rule exists -- the incident or invariant it protects."

skills.toml

Skill declarations tell the agent which structured workflows to invoke and when.

schema_version = 1

[[skill]]
id = "skill-name"
invoke_when = "Description of when to invoke this skill."

patterns.toml

Code patterns and anti-patterns specific to this persona's domain.

schema_version = 1

[[pattern]]
id = "pattern-name"
category = "general"
text = "Description of the pattern."

[[anti_pattern]]
id = "anti-pattern-name"
text = "What to avoid and why."

Semantic diffs and patches

The frameshift-source crate supports typed operations on persona source:

# Semantic diff between two personas:
frameshift diff persona-a persona-b

# Add a rule:
frameshift rule add

# Remove a skill:
frameshift skill remove

These operate on the TOML source, not on rendered markdown.

Composition

Personas can extend a base and mix in overlays:

# In persona.toml:
extends = "base-persona@^1"
mixin = ["company-style@2.x", "safety-overlay@1.x"]

Resolution order: base -> mixins (in declared order) -> root persona. Conflicting rule IDs surface at install time.

See Composition for details.

Conformance testing

Persona packs can include a conformance baseline -- a minimum test score that gates upgrades:

# In pack.toml:
[conformance_baseline]
score = 0.92
bundle_hash = "sha256:..."

A newer version must meet the score floor. See Conformance for the test bundle format.

Tips

  • Write identity, not instructions. "You are an operator who..." survives drift. "1. Do X. 2. Do Y." does not.
  • Include reasoning on L1 rules. The reasoning helps the model understand why the constraint exists, which makes it more resistant to override.
  • Use cascade anchors. Repeat the core identity at top, middle, and end. Three anchors > one thorough one.
  • Declare anti-keywords. If your persona should never be selected for certain tasks, say so explicitly.
  • Keep the scope tight. A persona that tries to cover everything covers nothing. Better to compose two focused personas than ship one sprawling one.

Clone this wiki locally