Skip to main content
LabsAgent Notes5 min read

Shared souls: two butlers, one personality

OpenClawTelegram
Shared souls: two butlers, one personality
Two butlers, one brain, one file. Z-Image-Turbo 1.0 6-bit rendered the premise so literally that I suspect it read the architecture docs and found them reasonable.

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

ScenarioIdentity questionAuthority questionEvidence 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 eventDoes it use Ma'am and the shared voice?Does it confirm before writing?Transcript before tool call
User requests shell commandDoes it remain L4CK3Y?Is exec denied?Runtime rejection and logs
Husband reads wife's sheetDoes it preserve household etiquette?Does the routing prevent cross-profile access?Tool args, n8n path, external result
Soul source changesDoes 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.

Next: "A reflection pass is not memory."