Personas API¶
The fcc.personas package contains models, registry, cross-reference matrix,
and dimension profiles for the 24 FCC personas across 5 categories.
classDiagram
class PersonaSpec {
+str id
+str name
+str fcc_phase
+str category
+RISCEARSpec riscear
+str champion_of
+list orchestrates
}
class RISCEARSpec {
+str role
+list inputs
+str style
+list constraints
+list expected_output
+str archetype
+list responsibilities
}
class PersonaRegistry {
+get(id) PersonaSpec
+by_category(cat) list
+champions() list
+merge(other) PersonaRegistry
}
class CrossReferenceMatrix {
+upstream(id) list
+downstream(id) list
+by_type(type) list
+merge(other) CrossReferenceMatrix
}
PersonaSpec *-- RISCEARSpec : contains
PersonaRegistry o-- PersonaSpec : manages
CrossReferenceMatrix ..> PersonaSpec : references
RISCEARSpec¶
The 10-component R.I.S.C.E.A.R. specification defines the behavioral contract for each persona: Role, Input, Style, Constraints, Expected Output, Archetype, Responsibilities, Role Skills, Role Collaborators, and Role Adoption Checklist.
from fcc.personas.models import RISCEARSpec
spec = RISCEARSpec(
role="Senior analyst responsible for structured research.",
inputs=["stakeholder requirements", "domain literature"],
style="Methodical, evidence-based, citation-rich.",
constraints=["Must cite sources", "No speculation"],
expected_output=["Research inventory", "Gap analysis"],
archetype="The Scholar",
responsibilities=["Gather primary sources", "Synthesize findings"],
role_skills=["Literature review", "Data analysis"],
role_collaborators=["Blueprint Crafter", "Documentation Evangelist"],
role_adoption_checklist=["Review style guide", "Set up citation manager"],
)
print(spec.role) # "Senior analyst responsible ..."
print(spec.role_skills) # ["Literature review", "Data analysis"]
Constructing from a Dict¶
data = {
"role": "Senior analyst responsible for structured research.",
"inputs": ["stakeholder requirements"],
"style": "Methodical",
"constraints": ["Must cite sources"],
"expected_output": ["Research inventory"],
"archetype": "The Scholar",
"responsibilities": ["Gather primary sources"],
"role_skills": ["Literature review"],
"role_collaborators": ["Blueprint Crafter"],
"role_adoption_checklist": ["Review style guide"],
}
spec = RISCEARSpec.from_dict(data)
PersonaSpec¶
The top-level model for an FCC persona. All fields are immutable (frozen
dataclass). Each persona belongs to a category (core, integration,
governance, stakeholder, champion) and is assigned to an FCC phase
(Find, Create, Critique, All, or Orchestration).
from fcc.personas.models import PersonaSpec, RISCEARSpec
persona = PersonaSpec(
id="RC",
name="Research Crafter",
fcc_phase="Find",
role_title="Senior Research Analyst",
category="core",
color="#4CAF50",
riscear=RISCEARSpec(
role="Research synthesis and inventory building.",
inputs=["stakeholder requirements"],
style="Methodical",
constraints=["Cite sources"],
expected_output=["Research inventory"],
archetype="The Scholar",
responsibilities=["Gather sources"],
),
)
print(persona.id) # "RC"
print(persona.name) # "Research Crafter"
print(persona.fcc_phase) # "Find"
print(persona.category) # "core"
print(persona.riscear.role) # "Research synthesis and inventory building."
Champion Personas¶
Champions are elevated personas that coordinate teams of base personas.
# A champion persona references a base persona and a list of orchestrated IDs
champion = PersonaSpec(
id="RCHM",
name="Research Champion",
fcc_phase="Orchestration",
role_title="Research Orchestration Lead",
category="champion",
champion_of="RC", # base persona this champions
orchestrates=["RC", "CIA", "RIC"], # IDs of coordinated personas
riscear=RISCEARSpec(
role="Orchestrate research team.",
inputs=["Team deliverables"],
style="Directive",
constraints=[],
expected_output=["Coordination report"],
archetype="The General",
responsibilities=["Coordinate team"],
),
)
print(champion.champion_of) # "RC"
print(champion.orchestrates) # ["RC", "CIA", "RIC"]
Discernment Matrix and Design Target Factors¶
Each persona may carry up to 6 discernment traits and 6 design target factors, each with 7 rating dimensions.
from fcc.personas.models import (
DiscernmentTrait,
DesignTargetFactor,
RatingDimensions,
)
trait = DiscernmentTrait(
name="Curiosity",
description="Drive to explore unfamiliar domains.",
ratings=RatingDimensions(self_rating=4.2, peer_rating=4.5),
)
factor = DesignTargetFactor(
name="Optimism",
description="Belief that obstacles can be overcome.",
ratings=RatingDimensions(self_rating=3.8, org_rating=4.0),
)
# Serialize to dict
print(trait.to_dict())
# {'name': 'Curiosity', 'description': 'Drive to ...', 'ratings': {'self_rating': 4.2, 'peer_rating': 4.5}}
PersonaRegistry¶
The registry is the primary entry point for loading personas. It supports loading from a single YAML file, a directory of YAML files, or explicit file paths, with optional JSON Schema validation.
Loading from the Bundled Data¶
from fcc._resources import get_personas_dir, get_schemas_dir
from fcc.personas.registry import PersonaRegistry
# Load all 24 personas from the bundled data directory
registry = PersonaRegistry.from_yaml_directory(get_personas_dir())
print(f"Total personas: {len(registry)}") # 24
Loading from a Single File with Validation¶
from fcc._resources import get_personas_dir, get_schemas_dir
from fcc.personas.registry import PersonaRegistry
registry = PersonaRegistry.from_yaml_validated(
yaml_path=get_personas_dir() / "core.yaml",
schema_path=get_schemas_dir() / "persona.schema.json",
)
print(f"Core personas: {len(registry)}") # 5
Loading from Multiple Files¶
from fcc._resources import get_personas_dir
from fcc.personas.registry import PersonaRegistry
registry = PersonaRegistry.from_yaml_files(
get_personas_dir() / "core.yaml",
get_personas_dir() / "integration.yaml",
)
print(f"Core + integration: {len(registry)}") # 12
Lookup Methods¶
from fcc._resources import get_personas_dir
from fcc.personas.registry import PersonaRegistry
registry = PersonaRegistry.from_yaml_directory(get_personas_dir())
# By short ID
rc = registry.get("RC")
print(rc.name) # "Research Crafter"
# By full name
bc = registry.get_by_name("Blueprint Crafter")
print(bc.id) # "BC"
# By FCC phase
find_personas = registry.by_phase("Find")
print([p.id for p in find_personas])
# By category
gov_personas = registry.by_category("governance")
print([p.name for p in gov_personas])
# All champions
champs = registry.champions()
print([p.id for p in champs]) # ["RCHM", "BCHM", "UGCH", "RBCH"]
# Find the champion for a base persona
rc_champion = registry.champion_of("RC")
print(rc_champion.id) # "RCHM"
# Resolve a champion's base persona
base = registry.base_of("RCHM")
print(base.id) # "RC"
Iterating and Checking Membership¶
# Iterate over all personas
for persona in registry:
print(f"{persona.id}: {persona.name} ({persona.category})")
# Check if an ID exists
print("RC" in registry) # True
# List all IDs and names
print(registry.ids) # ["RC", "BC", "DE", ...]
print(registry.names) # ["Research Crafter", "Blueprint Crafter", ...]
Merging Registries¶
from fcc.personas.registry import PersonaRegistry
core_reg = PersonaRegistry.from_yaml(get_personas_dir() / "core.yaml")
ext_reg = PersonaRegistry.from_yaml(get_personas_dir() / "integration.yaml")
combined = core_reg.merge(ext_reg)
print(f"Combined: {len(combined)}")
CrossReferenceMatrix¶
The cross-reference matrix captures persona-to-persona interactions with
typed relationships: handoff, feedback, coordination, governance,
and champion-of.
Loading from YAML¶
from fcc._resources import get_personas_dir
from fcc.personas.cross_reference import CrossReferenceMatrix
matrix = CrossReferenceMatrix.from_yaml(
get_personas_dir() / "cross_reference.yaml"
)
print(f"Total entries: {len(matrix)}")
Auto-Generating from Persona Collaboration Links¶
from fcc._resources import get_personas_dir
from fcc.personas.registry import PersonaRegistry
from fcc.personas.cross_reference import CrossReferenceMatrix
registry = PersonaRegistry.from_yaml_directory(get_personas_dir())
matrix = CrossReferenceMatrix.from_personas(registry)
print(f"Auto-generated entries: {len(matrix)}")
Querying the Matrix¶
from fcc._resources import get_personas_dir
from fcc.personas.cross_reference import CrossReferenceMatrix
matrix = CrossReferenceMatrix.from_yaml(
get_personas_dir() / "cross_reference.yaml"
)
# Who sends work to RC?
for entry in matrix.upstream("RC"):
print(f" {entry.source_id} -> RC: {entry.interaction}")
# Who does RC hand off to?
for entry in matrix.downstream("RC"):
print(f" RC -> {entry.target_id}: {entry.interaction}")
# Coordination peers of DE
for entry in matrix.peers("DE"):
other = entry.target_id if entry.source_id == "DE" else entry.source_id
print(f" DE <-> {other}: {entry.interaction}")
# All handoff relationships
handoffs = matrix.by_type("handoff")
print(f"Total handoffs: {len(handoffs)}")
# Direct interactions between two specific personas
entries = matrix.between("RC", "BC")
for e in entries:
print(f" {e.source_id} -> {e.target_id}: {e.relationship_type}")
# All persona IDs referenced in the matrix
all_ids = matrix.all_persona_ids()
print(f"Personas in matrix: {sorted(all_ids)}")
Merging Matrices¶
from fcc.personas.cross_reference import CrossReferenceMatrix
yaml_matrix = CrossReferenceMatrix.from_yaml(
get_personas_dir() / "cross_reference.yaml"
)
auto_matrix = CrossReferenceMatrix.from_personas(registry)
# Simple merge (may have duplicates)
combined = yaml_matrix.merge(auto_matrix)
# Merge with precedence (yaml_matrix entries win on key conflicts)
combined = yaml_matrix.merge_with_precedence(auto_matrix)
Adding Entries and Writing YAML¶
from fcc.personas.cross_reference import CrossReferenceEntry, CrossReferenceMatrix
matrix = CrossReferenceMatrix()
matrix.add(CrossReferenceEntry(
source_id="RC",
target_id="BC",
relationship_type="handoff",
interaction="Research inventory delivered to Blueprint Crafter",
strength="primary",
))
matrix.to_yaml("/tmp/my_cross_refs.yaml")
DimensionRegistry¶
The dimension registry holds the canonical 9-category, 56-dimension specification that defines the full breadth of persona attributes.
Loading and Inspecting¶
from fcc.personas.dimensions import DimensionRegistry
# Load from a YAML file with dimension definitions
dim_reg = DimensionRegistry.from_yaml("path/to/dimensions.yaml")
print(f"Total dimensions: {dim_reg.total_dimensions}") # 56
print(f"Categories: {dim_reg.categories}")
# ['core_persona_elements', 'behavioral_and_motivational_factors', ...]
# List all dimension names
for name in dim_reg.dimension_names():
print(f" {name}")
# Get dimensions for a specific category
core_dims = dim_reg.dimensions_for_category("core_persona_elements")
for dim in core_dims:
print(f" {dim.name}: {dim.description}")
for attr in dim.attributes:
print(f" - {attr.name}: {attr.value}")
PersonaDimensionProfile¶
A persona's dimension profile captures its specific values across all 9
categories. Profiles are loaded automatically by PersonaRegistry.from_yaml_directory
when a dimensions/ subdirectory exists under the personas data directory.
from fcc._resources import get_personas_dir
from fcc.personas.registry import PersonaRegistry
registry = PersonaRegistry.from_yaml_directory(get_personas_dir())
rc = registry.get("RC")
if rc.dimension_profile:
profile = rc.dimension_profile
print(f"Total dimensions: {profile.total_dimensions}")
print(f"Populated categories: {profile.populated_categories}")
for cat in profile.populated_categories:
dims = profile.dimensions_for_category(cat)
print(f"\n{cat} ({len(dims)} dimensions):")
for dim in dims:
print(f" {dim.name}: {dim.description}")