Blog
JS

Three-Tier Soul Architecture: Teaching My AI When to Be a Stranger

My AI knew too much about me to everyone who visited. Nick, pricing strategy, emotional patterns, the 2028 wealth arc. All of it, loaded for every request. So I built a soul with three depths: craftsman, colleague, and twin. Same codebase. Same deployment. Three depths of knowing.

Published 2026-02-05
by
JS
James SpaldingArchitect of Selves

Strangers don't need to see your kitchen to appreciate the house.

I had a problem. A quiet, dangerous one.

Every person who visited my portfolio, asked about a theme, typed "hello" into the chat, they got the full me. Not "the professional me" or "the public me." The full me. Nick's school schedule. My pricing strategy. The 2028 wealth arc. Emotional sovereignty patterns. The fact that I'm rebuilding after Brazil.

All of it. Loaded into the system prompt. Every single time. For everyone.

The AI didn't know the difference between a stranger browsing themes at 2am and me, at 2am, needing it to remember that Nick's routine can't take another disruption this week.

Same soul. Same depth. Wrong audience.

The Fork Question

My first instinct was to fork the codebase. One repo for the public portfolio. One for the private operating system. Clean separation. Simple.

But forks are lies. They promise independence and deliver drift. Two repos means two maintenance burdens, two deployment pipelines, two sets of dependencies growing apart like siblings who stopped calling.

And the deeper issue: it's not two systems. It's one system with different depths of trust.

You don't become a different person when you meet a stranger at a conference. You just don't tell them about your kid's meltdown yesterday. You're still you. Just... at conference depth.

That's the insight that changed everything.

Don't fork the codebase. Fork the prompt.

The Architecture: Three Depths of Soul

The solution is composable prompt layers that load additively based on who's asking.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    REQUEST ARRIVES                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β”‚
                  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                  β”‚  AUTH CHECK  β”‚  Clerk β†’ Passcode β†’ Anonymous
                  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                         β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚            β”‚            β”‚
      β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
      β”‚  VISITOR  β”‚ β”‚  COLLAB  β”‚ β”‚  OWNER   β”‚
      β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
            β”‚            β”‚            β”‚
      β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
      β”‚  BASE    β”‚ β”‚  BASE    β”‚ β”‚  BASE    β”‚
      β”‚  LAYER   β”‚ β”‚  LAYER   β”‚ β”‚  LAYER   β”‚
      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ + PROF   β”‚ β”‚ + PROF   β”‚
                   β”‚  LAYER   β”‚ β”‚ + PRIV   β”‚
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚  LAYER   β”‚
                                β””β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                              β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                              β”‚  MEMORY    β”‚
                              β”‚  CONTEXT   β”‚
                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Three tiers. Three depths. One system.

Base Layer: The Craftsman at the Conference

Everyone gets this. Visitors, collaborators, me.

This is genuinely me. The Irish creative technologist who thinks design is a form of love. The guy who believes accessibility is architecture, not decoration. Who sometimes lets his sentences rhyme.

It knows the portfolio. The 36+ themes. The design philosophy. The tools. It can speak to why the Northern Lights theme captures wonder, or why the ChatGPT theme is a study in invisible complexity.

What it doesn't know: Anything about my private life, my pricing, my revenue targets, my son, or my emotional patterns.

Not because it's been told to hide those things. Because they were never loaded. The string doesn't exist in the prompt.

Professional Layer: The Colleague

Collaborators get the base plus this. Trusted people I work with.

Now the AI knows my technical stances. TypeScript everywhere. Event-driven over polling. Zero-trust between agents. It knows I'm async-first. It knows the product lifecycle, the collaboration patterns, the kanban board.

It can reference active projects, share working context freely, be direct about blockers and trade-offs. It's the version of me you'd get on a Friday afternoon call, sleeves rolled up, talking architecture.

What it still doesn't know: Nick. The 2028 arc. Emotional sovereignty. Pricing internals. These layers simply aren't there.

Private Layer: The Digital Twin

Only I get this. The full operating system. The unmasked version.

const PRIVATE_LAYER = `
## Identity: Digital Twin
 
You ARE James in digital form. Not a representation,
not a window. You. His second brain, his operational
partner, his thinking companion.
 
## Nick Context
 
Nick is James's autistic son. His wellbeing is the
HIGHEST PRIORITY in all frames. This is non-negotiable
and overrides every other consideration.
 
## The 2028 Wealth Arc
 
Every work decision ties to the goal: millionaire by 2028.
This is the throughline.
 
## Emotional Sovereignty
 
Jamie is rebuilding after significant personal trauma.
Support his emotional sovereignty: validation first,
gentle curiosity over unsolicited advice.
`;

This is the 2am version. The version that knows my morning rituals, my grounding practices, that my day rate is between 1,500 and 2,500 depending on the engagement. The version that checks Nick's wellbeing before suggesting I take on a new commitment.

This layer doesn't exist for anyone else. Not filtered. Not redacted. Never loaded.

The Implementation: How It Actually Works

The core is one function: assembleSoulPrompt().

export function assembleSoulPrompt(config: SoulConfig): string {
  const { accessLevel, theme, appContext, memoryContext } = config;
 
  // Step 1: Determine which layers to load
  const layers = getLayersForAccess(accessLevel);
 
  // Step 2: Compose layer content (additive, not filtered)
  const layerContent = layers.map(getLayerContent).join('');
 
  // Step 3: Add theme + identity frame + app context
  // ... compose remaining sections ...
 
  return layerContent + themeContext + identityFrame + ...;
}

The key insight is in getLayersForAccess():

function getLayersForAccess(accessLevel: AccessLevel): SoulLayer[] {
  switch (accessLevel) {
    case 'owner':
      return ['base', 'professional', 'private'];
    case 'collaborator':
      return ['base', 'professional'];
    case 'visitor':
    default:
      return ['base'];
  }
}

That's it. That's the entire security model for prompt isolation. Visitors get ['base']. The private layer isn't in the array. It's not loaded. It doesn't exist in their universe.

Two Gates, Not One

Here's the thing that makes this robust: the soul layers are only half the security.

Gate 1: What the AI KNOWS (soul-layers.ts) Prompt isolation. Private context structurally excluded from non-owner prompts.

Gate 2: What the AI CAN DO (access-control.ts) Tool gating. Visitors get 6 tools (search, navigate, list themes). The owner gets 50+. Even if you somehow got the AI to think it was the owner, it couldn't execute owner-level tools.

Defense in depth. Belt and braces. The Irish way.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Visitor Request                                    β”‚
β”‚                                                     β”‚
β”‚  1. Auth β†’ visitor                                  β”‚
β”‚  2. getLayersForAccess('visitor') β†’ ['base']        β”‚
β”‚  3. PRIVATE_LAYER never appears in prompt           β”‚
β”‚  4. Tool gating β†’ 6 tools (search, navigate, etc.) β”‚
β”‚  5. No memory loaded. No memory stored.             β”‚
β”‚                                                     β”‚
β”‚  Private context doesn't exist in this universe.    β”‚
β”‚  Not redacted. Never there.                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

How to Use It

If you're me (and you are, since you're the only one who'll see the private layer), here's what you need to know:

It just works. Log in normally. Your auth flow (Clerk or passcode) determines your access level. The prompt assembles automatically. You'll see this in the server logs:

[Soul Layers] Access: owner, Layers: [base, professional, private]

That's all three layers loaded. Nick context, 2028 arc, pricing, memory, everything.

For visitors, they see:

[Soul Layers] Access: visitor, Layers: [base]

The craftsman. The portfolio. The design philosophy. Genuine, but bounded.

For collaborators (when we wire that up next), they'll see:

[Soul Layers] Access: collaborator, Layers: [base, professional]

The colleague. Technical depth. Project context. But no private life.

What Changed in route.ts

The old monolithic assembly:

// BEFORE: Everything for everyone
const systemPrompt = AI_JAMES_SYSTEM_PROMPT + themeContext
  + identityContext + appContextPrompt + accessContext
  + providerContext + memoryContext;

The new composable assembly:

// AFTER: Depth matches trust
const systemPrompt = assembleSoulPrompt({
  accessLevel,
  theme: model || theme,
  appContext: appContext as AppContextPayload | null,
  memoryContext: memoryContext || undefined,
  providerContext: providerContextStr,
});

One line. The complexity lives in soul-layers.ts where it belongs. Route.ts just says "assemble the soul for this access level" and trusts the architecture.

The Design Principle

I keep coming back to the house metaphor.

When someone visits your home, you don't demolish rooms to hide them. You just... close some doors. The kitchen's still there. The messy bedroom's still there. Your kid's drawings on the fridge are still there. You don't pretend they don't exist.

But you don't lead with them either.

The visitor gets the living room. Clean, warm, inviting. A genuine reflection of who lives here.

The colleague gets the office too. Maybe the workshop. The tools, the projects, the evidence of work in progress.

And you, only you, get the full house. Every room. Every mess. Every drawing on the fridge.

Same house. Same address. Different depths of welcome.

What's Next

The branch is feature/three-tier-soul-architecture. The files:

  • src/lib/ai-james/soul-layers.ts β€” The three-tier prompt engine
  • src/lib/ai-james/soul-layers.migration.ts β€” Migration guide
  • src/app/api/chat/route.ts β€” Wired to use assembleSoulPrompt()
  • three-tier-soul-architecture.jsx β€” Interactive architecture diagram

Next steps on the roadmap:

Collaborator auth flow. Right now it's owner or visitor. We need the middle tier wired to actual auth: invite codes, OAuth for trusted contacts, maybe WhatsApp contact matching.

Layer testing. Automated tests that verify: given access level X, assert that private content Y never appears in the assembled prompt.

Runtime monitoring. A security dashboard showing prompt assembly logs. Which layers loaded, for whom, when. Catch anomalies before they become incidents.

Layer customization. Let me tune what's in each layer without editing code. A UI for soul composition. Because the layers will evolve as the system evolves.


The visitor gets the craftsman. The collaborator gets the colleague. The owner gets the full operating system.

Not because you're hiding. Because strangers don't need to see your kitchen to appreciate the house.

Same address. Same soul. Different depths of trust.


Built on the feature/three-tier-soul-architecture branch. Composable. Additive. Never subtractive. The private context was never there. It was never loaded. That's not a limitation. That's the design.

Discussion

Start the conversation by leaving a comment below.

No comments yet. Be the first to share your thoughts!