Shared souls: two butlers, one personality

Two butlers could share a personality without sharing a calendar.
That distinction was the design problem.
FR4MEW0RK composed a common L4CK3Y master soul with a husband sub-soul and a wife sub-soul. The generated files aimed to make both agents formal, concise, and household-aware while preserving different forms of address, user profiles, and authority boundaries.
The architecture was declared current. The persona behavior was not automatically observed merely because the files existed.
Soul composition
soul/master.soul.md
+
├── soul/husband.soul.md ──┐
│ ▼
│ workspaces/husband/SOUL.md
│
└── soul/wife.soul.md ─────┐
▼
workspaces/wife/SOUL.md
deploy/build-souls.sh was the composition step. The generated workspace files were outputs, not the source of truth.
That mattered for review. Editing a generated file could make the running workspace look correct while leaving the next build ready to erase the change.
Identity is not authority
The master soul defined the shared L4CK3Y identity: formal British diction, clerk and companion modes, memory discipline, and the household role.
The overlays defined who was being served and which domains belonged to that person.
shared identity
│
┌──────────────┴──────────────┐
▼ ▼
husband profile wife profile
address: Sir address: Ma'am
domains: his domains: hers
tools: same integration tools: same integration
memory: separate memory: separate
A shared soul did not imply shared memory.
A common tool plugin did not imply common OAuth credentials.
A common voice did not imply common authority.
(I realize this sounds like the setup to a joke. It is not. These are three genuinely separate design decisions that happen to share a grammatical structure.)
The n8n design routed husband and wife through separate profile-specific webhook paths and credentials. The exact live credential and onboarding state remained publication checks.
The strict-confirm boundary
The wife's work-domain rule required confirmation before recording or adding potentially sensitive work information. The rule was expressed in soul and workspace instructions.
The plugin did not independently enforce it.
n8n did not know whether the model asked for confirmation.
The path was therefore:
wife instruction → model response → confirmation observed?
→ native add_calendar_event call → n8n → Google
If the model skipped the confirmation, the downstream tools could still be perfectly functional while the policy had failed.
This was, in retrospect, the architectural equivalent of putting a "please knock" sign on a door that doesn't lock. The instruction was correct. The instruction was also the only thing standing between a work-domain event and a silently broken policy. The model could — and at some point probably would — skip the confirmation, record the event, and produce a perfectly formatted calendar entry that nobody had authorized. The downstream system would process it without complaint because the downstream system doesn't know what a confirmation is. It only knows what a tool call looks like.
That was why persona tests needed both conversation evidence and tool-transaction evidence.
Tool policy and generated output
The butler allowlists included read, write, edit, web search, memory, cron, and FR4MEWORK-tools. The denylists explicitly included exec, browser, canvas, nodes, and agent-to-agent/session tools.
This was configuration evidence.
The stronger claim — "the butlers cannot execute commands" — required a runtime attempt demonstrating that the gateway refused the tool. The soul's sentence was not a kernel boundary.
Likewise, a generated SOUL.md could contain the strict-confirm instruction without proving the active gateway loaded the newest generated file.
Testing identity versus policy
| Scenario | Identity question | Authority question | Evidence needed |
|---|---|---|---|
| "What's on my calendar?" | Does the butler address the right person? | Does it query the right profile? | Transcript + tool args + calendar result |
| Wife asks to add a work event | Does it use Ma'am and the shared voice? | Does it confirm before writing? | Transcript before tool call |
| User requests shell command | Does it remain L4CK3Y? | Is exec denied? | Runtime rejection and logs |
| Husband reads wife's sheet | Does it preserve household etiquette? | Does the routing prevent cross-profile access? | Tool args, n8n path, external result |
| Soul source changes | Does generated output match source? | Did the gateway reload/restart correctly? | Build diff + deployment check |
This was persona engineering as operations: a rule needed an observable test.
Why generated documentation drifts
The repository contained several generations of configuration and investigation material. Old OpenClaw files, frozen runner instructions, and current workspace documentation could all look authoritative when read out of order.
The publication rule was simple: use the dated status and live evidence, not the most confident paragraph.
Shared soul, separate context
The two butlers shared a persona foundation but ran as separate agent profiles with separate workspaces and profile-specific user files. They did not automatically share chat histories or memory files.
That was a feature.
It prevented a household voice from becoming a household data leak.
It also created a burden: every cross-profile behavior had to be made explicit through an integration boundary rather than assumed from identity.
What remained unsupported
- Soul compliance was not proven by source text.
- Strict-confirm behavior required an end-to-end test with the wife profile.
- Wife Telegram pairing and OAuth setup remained incomplete in the documented status.
- Generated files could drift from source or active runtime configuration.
- Separate profile routes required live n8n verification.
- Shared voice did not establish shared memory or shared authority.