Skip to main content

Digital Twin — A Partner With Standing

What the Digital Twin is

The Digital Twin is not a separate agent and not a persona file. It is the same AI Partner engine, pointed at you as a partner with standing rather than at a task queue. It adds a layer of mechanisms that carry a relationship on top of ordinary chat and goal execution:

MechanismWhat it gives the twinFile / surface that drives it
CharterStanding to refuse, to confront, and to earn autonomyCHARTER.md
Constitutional memoryFounding commitments and corrections that are never summarized awaymemory class constitutional
Positions + dissent gateEvidence-backed claims about you it will push back frommemory class positions
Confrontation loopA scheduled, evidence-gated challenge when your activity drifts from your goalsGOALS.md + CHARTER.md
Earned delegationThe right to act unasked — graduated per action class by clean approvalsCHARTER.md + approvals ledger

The founding principle is deliberate: the twin has no name and no "voice." A name would make it a costume. It is invoked by using AI Partner normally — the twin behaviors are ambient. See How you invoke it.


The workspace files, and who reads them

Every user's identity and relationship live in plain Markdown files in their own workspace. On a single-user install that is the base workspace; on a multi-user VPS each user has their own copy (see Multi-user on a VPS).

FileBelongs toRead byPurpose
SOUL.mdThe agentEvery chat + goal turnThe agent's identity, character, work standards. Not your personal facts.
USER.mdYouEvery chat + goal turn (as [USER CONTEXT])The single source of truth for who you are — your name, role, stack, preferences.
CHARTER.mdThe partnershipBefore every confrontation + delegated action (hot-reloads)Confrontation domains, resurface policy, delegated authority, founding episode.
GOALS.mdYouWeekly goal review + twin confrontationYour active/paused long-horizon goals ("arcs").
HEARTBEAT.mdThe agentEvery heartbeat tickStanding proactive tasks (briefings, scans). Distinct from the twin's charter-driven schedule.
AUTHORITY.mdYouEvery action the agent takes for youAllow / draft-and-ask / block rules; always wins over earned delegation (instant kill switch).

Your name lives in USER.md, not SOUL.md. USER.md is injected into every prompt as [USER CONTEXT]. If you edit your name and the agent still uses the old one, you almost certainly edited the wrong workspace's copy — see Troubleshooting.


Enabling and configuring

The twin is on by default. Two config flags govern it (in ~/.mindful-assistant/config.json, or per-instance on the server):

FlagDefaultEffect
twinConnectEnabledonMaster switch. false disables all twin behavior, including the relationship sections injected into prompts.
twinDelegationEnabledonOrg-wide delegation kill switch (exposed to admins). false blocks all earned autonomy while leaving memory/confrontation intact.

To use the twin to its full potential you configure CHARTER.md — it hot-reloads on save, no restart:

## Granted Confrontation Domains
# The twin may challenge you ONLY in these domains, and only with >= `evidence`
# distinct observations, at most once per week overall. Empty = never confronts.
- domain: stated_goals_vs_activity + evidence: 3
- domain: project_build_arcs + evidence: 3
- domain: health_habits + evidence: 3

## Resurface Policy
- suppression_cooloff_days: 14
- max_suppressions_per_arc: 3
- third_suppression: present_all_three # third back-off shows all three, then retires the arc

## Delegated Authority
# Action classes the twin may EARN after `graduate_after` clean approvals.
# apply: absent_only = used only when you're unreachable. Not listed = never eligible.
- action_class: send_telegram_dm + graduate_after: 5 + apply: absent_only
- action_class: reply_email + graduate_after: 5 + apply: absent_only

## Founding Episode
<!-- Paste your founding-conversation document here. Ingested once as the twin's
first constitutional memory. Leave empty to skip. -->

Removing a domain removes the twin's standing in it immediately. An empty Granted Confrontation Domains section means the twin never confronts you at all. Deny-by-default in both directions: a domain not listed grants no standing; an action class not listed is never delegable.

To actually exercise the full loop you also need:

  1. A connected messaging channel — Telegram, Discord, or Slack (Settings → Messaging). This is how confrontations and daily digests reach you.
  2. A populated GOALS.md — the source of the "arcs" the twin holds you to.

How you invoke it

You don't summon the twin — you just talk to AI Partner. When twinConnectEnabled is on, its relationship memory, open threads, and held positions are injected into every system prompt, so the agent will disagree with you, cite dated evidence, and hold questions open across sessions on its own.

The places you deliberately engage the twin layer:

  1. 1
    Chat normally

    Speak to AI Partner as usual. It records corrections, forms positions about you, and opens/resolves threads via its twin_record tool as the conversation unfolds — you never call the tool yourself.

  2. 2
    Amend the charter by intent

    Say "I want to amend the charter" in chat. The twin restates the current clause, the proposed clause, and the consequence, then asks for explicit confirmation before editing CHARTER.md. (Direct edits to the file also work and hot-reload — the ceremony just makes constitutional changes deliberate.)

  3. 3
    Answer confrontations

    When your activity drifts from your goals, the twin delivers one charter-gated challenge over your messaging channel (and in-app) with engage / adjust / back_off buttons. A "back off" is obeyed and remembered; silence or timeout is never treated as backing off.

  4. 4
    Use the "Your Twin" panel

    Open the Proactive view → Your Twin. From there you can answer pending asks in-app, resolve open threads, revoke an earned delegation instantly, and read the twin's positions, action feed, and charter.


Multi-user on a VPS

On a multi-user instance every user is an isolated tenant. This is the setup you use when hosting AI Partner on a VPS for a team.

Per-user isolation

Each user created in the Admin Console gets their own workspace, seeded with the full template set (including CHARTER.md, USER.md, SOUL.md, GOALS.md):

<workspace_dir>/ # base — the 'default' / single-user workspace
<workspace_dir>/<userId>/ # tenant workspace for each real user
├── SOUL.md ├── USER.md
├── CHARTER.md ├── GOALS.md
├── AUTHORITY.md └── HEARTBEAT.md

Everything the twin knows is scoped to the login:

  • Chat and goal prompts read that user's own SOUL.md / USER.md — so a user editing their USER.md changes their agent, and no one else's.
  • Confrontations and digests are delivered on that user's own connected bot (per-owner bot resolution), never crossed between tenants.
  • Constitutional memory, positions, open threads, suppressions, and earned delegations are all keyed by user_id.

Admin governance — conduct, never content

Admins govern twins without ever seeing their content. The Admin Console exposes:

ControlWhat it doesWhat it never exposes
Twins listWhich users have an active twin, and delegation status
Earned-action feedWhat each twin did under delegation, with receipts
Per-user freezeSuspend a twin's delegated autonomy
twinDelegationEnabledOrg-wide delegation kill switch

An admin may freeze; only the user can re-earn. Admins never see a twin's memories, positions, confrontation text, back-off reasons, or goals. Actions taken in the organization's name are org business; the relationship is the user's.


Get the most out of it — an owner's walkthrough

Do these once and the twin moves from "on" to "actually a partner":

  1. 1
    Make USER.md real

    Put your actual name, role, and working style in your USER.md. This is the single source of truth for who you are and is read on every turn.

  2. 2
    Grant confrontation standing

    In CHARTER.md, list the domains you want to be challenged on (e.g. stated_goals_vs_activity). Start with an evidence of 3 so the twin only speaks when it has real grounds.

  3. 3
    Give it goals to hold you to

    Populate GOALS.md with your genuine active goals. The twin compares these against your actual weekly activity — no goals, nothing to confront.

  4. 4
    Connect a channel

    Connect Telegram (Settings → Messaging). This is where the weekly confrontation and the daily "while you were away" digest arrive.

  5. 5
    Let it earn delegation

    List a low-risk action class in CHARTER.md Delegated Authority (e.g. send_telegram_dm, absent_only). Approve its drafts cleanly a few times; after graduate_after clean approvals it graduates to acting unasked — and one edit or skip revokes it instantly.

  6. 6
    Correct it, and watch it stick

    When it's wrong about you, say so. Corrections become permanent constitutional memory — a corrected mistake never repeats — and revise the underlying position out loud, with history.

  7. 7
    Optional: write a founding episode

    Paste the conversation that defines the partnership into the ## Founding Episode section of CHARTER.md. It is ingested once as the twin's first constitutional memory — the record of how, and why, this partnership began.


Troubleshooting: "my name isn't picked up"

The name the agent uses comes from USER.md (injected as [USER CONTEXT]). Everything below is fixable from inside the app — no server access needed. If a name change doesn't take:

  1. Edit USER.md in the in-app Workspace browser. Open Workspace in the app and edit USER.md there — that editor always points at your own workspace, on any install. Changes apply from the next message. (Self-hosting admins editing files on the server disk: each user's copy lives at <workspace_dir>/<userId>/USER.md, not the base workspace — but the in-app editor is the safe path.)
  2. A stale name in SOUL.md. Workspaces set up on older versions may still carry your name inside SOUL.md (the agent's identity file). Open SOUL.md in the same Workspace browser and remove any ## User / "You work primarily with…" line so USER.md is the single source.
  3. Memory recall. If you told the agent a different name in earlier conversations, it may recall it. Correct it in chat ("my name is X, not Y") and the correction becomes permanent.

Rule of thumb: SOUL.md = the agent. USER.md = you. One fact, one home.