A portable Claude Code workspace for advisor practice. Open a new Claude Code chat in this folder and a random synthetic RIA client greets you in-character. Practice the full advisor workflow — prospecting, onboarding, quarterly reviews, hard conversations, deliverable presentation — then end with /debrief for a scored rubric and session log.
Built by Andrew Lazzeroni. Designed to be copied to any machine and used locally.
Python alias heads-up (read this first): The SessionStart hook is configured to run with
pythonin.claude/settings.json. Windows installs typically work out of the box. On macOS and Linux, your Python 3 is usuallypython3and barepythonmay point to Python 2 or nothing. If your first session opens without a persona, the fix is almost always this: open.claude/settings.jsonand changepythontopython3in the hook'scommandfield. Verify withpython3 --versionin your terminal (must be 3.9 or newer).
Requirements:
- Python 3.9 or newer on your PATH (stdlib only — no
pip installneeded) - Claude Code installed
Steps:
- Copy this folder to your machine. Anywhere you want — Desktop, Documents, a projects directory.
- macOS / Linux only: Apply the Python alias fix above if bare
pythonis not Python 3 on your system. - Open Claude Code with this folder as the workspace (open Claude Code and point it at the folder, or
cdinto the folder and launch from there). - Open a new chat. The persona auto-spawns via the
SessionStarthook. The first message you see will be the client speaking — that is correct, not a bug.
Expected flow:
- Open a new Claude Code chat in this folder.
- Claude greets you in-character as a randomly selected synthetic client. You are the advisor — stay in your role. Do not break the fourth wall; respond as you would in a real meeting.
- Practice the conversation. Ask fact-finding questions, handle objections, present recommendations, walk through deliverables. Claude will improvise in-character based on a hidden dossier you do not see.
- Type
/coachat any point for a mid-session tactical critique. A separate observer agent gives 2-4 sentences of feedback without revealing dossier specifics, so your fact-finding practice stays honest. - Type
/debriefto close the session. The client drops character for a short reflection, the coach gives tactical bullets, and a 0-5 rubric scores you across 8 dimensions. Everything saves tosessions/YYYY-MM-DD-<name>.md.
Tip: treat the first Claude message as the opening line of a real meeting. Resist the urge to ask meta-questions — if you want tactical input, that is what /coach is for.
/coach— summons an observer agent for 2-4 sentences of tactical critique. Hints at categories you missed (e.g., "you haven't asked about held-away assets") without revealing hidden-dossier specifics. This preserves fact-finding practice./debrief— session close. Client drops character for a human-style reflection on how you handled them, coach gives tactical bullets, the rubric scores 0-5 across 8 dimensions, and everything saves tosessions/YYYY-MM-DD-<name>.mdas a permanent log you can review later.
Each session pre-generates a folder of synthetic documents at personas/documents/ — a "data room" you can browse before or during the meeting. Typical contents:
00-MANIFEST.md— index of what's in the folder01-401k-statement.md— if the persona has a 401(k) or 403(b)02-ira-statement.md— if the persona has an IRA03-brokerage-statement.md— if the persona has a taxable brokerage04-pay-stub.md— if the persona earns income05-insurance-binder.md— always06-will.md— if the persona has a will07-trust-summary.md— if the persona has a revocable trust08-1099-prior-year.md— if the persona has a taxable brokerage09-held-away-notes.md— if the persona has accounts not currently managed at your firm
All numbers in these files are internally consistent with the client's hidden dossier. The folder is overwritten on each new Claude Code session — copy it elsewhere to preserve a set.
The templated docs are the baseline. For richer detail or unusual document types (K-1, Schedule C, specific account positions), ask the client in conversation — they'll generate a more detailed synthetic doc on demand using the generate-artifact skill.
The baseline content is generic RIA practice. To match your actual book and standards, edit:
personas/archetypes.json— add or remove archetypes that match your real client base. Adjust theweightfield on each archetype to make common client types roll more frequently (higher weight = more likely).scenarios/scenarios.json— add scenarios that reflect meetings you actually run. Tightendifficulty_flooranddifficulty_ceilingto control challenge level. Restrictcompatible_archetype_idsso unrealistic pairings (e.g., retiree + startup-equity scenario) cannot roll.rubric/dimensions.md— adjust the 8 scoring dimensions or their 0-5 level descriptions if your firm's standards differ from the defaults.rubric/compliance-watchlist.md— IMPORTANT: replace this with your firm's actual compliance rules. The baseline is generic RIA guidance and will not reflect your specific ADV, disclosures, supervision procedures, or state-level obligations.
RIA Client Simulator/
├── README.md # (this file)
├── CLAUDE.md # Workspace identity, client-voice rules
├── .gitignore # Personal data (ledger, session logs) is gitignored
├── .claude/
│ ├── settings.json # SessionStart hook + slash command config
│ ├── hooks/spawn_persona.py # Persona roller (Python, stdlib only)
│ ├── agents/coach.md # /coach observer subagent
│ └── skills/
│ ├── stay-in-character/SKILL.md # Client voice rules
│ ├── debrief/SKILL.md # /debrief flow
│ └── generate-artifact/SKILL.md # On-demand synthetic documents
├── personas/
│ ├── archetypes.json # 15 client archetype definitions
│ ├── active.md # Current session persona (overwritten per chat, gitignored)
│ └── ledger.jsonl # Novelty history (gitignored — personal)
├── scenarios/scenarios.json # Scenario catalog
├── rubric/
│ ├── dimensions.md # 8 scoring dimensions x 0-5 levels
│ └── compliance-watchlist.md # RIA compliance rules
├── sessions/ # Debrief logs (gitignored — personal)
└── tests/ # Python unit tests for the hook
Anything representing your personal practice history is gitignored so it stays local to your machine:
personas/ledger.jsonl— novelty history, used to avoid rerolling the same persona traits back-to-backpersonas/active.md— the current session's persona, overwritten on each new chatsessions/*.md— your debrief logs
Everything else (archetypes, scenarios, rubric, skills, hook code) is shared content. If you and a coworker both use this workspace, you will have identical client types available but independent practice histories and session logs.
Hook did not fire / no persona appeared. Check the path in .claude/settings.json is correct and the workspace is actually this folder. Then run the hook manually from a terminal in this folder:
python .claude/hooks/spawn_persona.py
The error output will tell you whether it is a Python issue, a path issue, or a JSON parse issue in one of the data files.
Python not found. Install Python 3.9 or newer. If you already have it installed as python3, apply the macOS/Linux note above and change python to python3 in the hook's command field.
Persona feels repetitive after many sessions. Open .claude/hooks/spawn_persona.py and search for min_diff=3. That is the novelty threshold — how many traits must differ from recent personas before a roll is accepted. Lower it (e.g., min_diff=2) to allow more variety in rolls, or raise it (e.g., min_diff=4) to force the roller to try harder for a novel combination. Very high values on a small archetype catalog can cause the roller to stall — widen archetypes.json first if you go above 4.
/coach revealed hidden dossier specifics. That is a bug, not a feature. The coach is supposed to hint at categories (e.g., "you skipped discovery on tax situation") without naming the actual dossier values. Open .claude/agents/coach.md and check the hint-vs-answer rule near the top of the mandate — it should explicitly forbid naming concrete dossier facts. Tighten the language if coach drift is happening in practice.