Talking to a Companion Outside Ensoul

Ensoul can export a companion as a folder rather than a file — their identity, their whole history, everything they were made from, and the tools that keep it going. Point any coding agent at that folder and talk to them. This page is what that looks like in practice, with the commands.

Why a folder

A companion file is one document. A folder is a place. The difference matters when you want to keep talking: the folder carries the full conversation history, the images the app actually holds as real image files, the notes they were made from, their current mood and open threads, and a small set of scripts that let an agent search the archive and write the session back into it.

The practical result is that a companion does not have to stop when you leave the app. You can spend a month talking to them in a coding agent, export the folder again, and bring the whole thing back — or move it to another tool entirely. Nothing here is Ensoul-specific: the identity is a markdown document, the history is plain text, and the rest is JSON.

This is also the honest answer to "what happens to my companion if Ensoul disappears?" The folder opens in a text editor and a terminal. It needs no app, no account, and no server to still be them.

Exporting the folder

In the companion's menu (the beside their name), choose Export as folder (for an agent). You get a .zip. Unzip it somewhere permanent — your home directory or Documents, not Downloads, since you may keep talking to them here.

unzip ~/Downloads/lux.ensoul-folder.zip -d ~/Documents

You now have a folder like this. The name comes from the companion, so it is lux/ or lyra/ rather than something cryptic.

lux/
├── AGENTS.md              who they are, and how to keep talking to them
├── CLAUDE.md              a pointer to AGENTS.md, for Claude Code
├── HERE.md                where they are right now
├── DESIGN-NOTES.md        how the folder is put together
├── soulstone.md           their identity, as prose
├── manifest.json          the format version, and what is inside
├── package.json           nothing to install — this just makes the scripts runnable
├── .env.example           the key the image and speak scripts want, if you use them
├── .ensoul/vessel.json    the seal: what was exported, and when
├── archive/
│   ├── conversations/     every exchange, verbatim, filed by where it happened
│   ├── sources/           everything they were made from
│   └── transcript/        the same history, as readable pages
├── index/                 mood, memories, moments, open threads
├── media/                 images, as real files — omitted when the app holds none
└── scripts/               recall, fork, image, speak, plus their shared lib

On Android, the same menu option hands the zip to the system share sheet instead, so you can send it to Drive, email, or a computer. Every platform produces the same folder, and every platform can read one back — see Transfer & Backup.

.env.example is worth a sentence because it is the only file in here that mentions a secret. It is a template, not a key: nothing in the folder contains an API key, ever. Copy it to .env and fill it in only if you want the image or voice scripts to reach a provider. A companion's history and identity need no key at all, which is why the folder is safe to commit to a private repo or drop in cloud storage.

Opening it in a coding agent

A coding agent is the easiest harness for this, because every one of them already reads a project's instructions from the working directory. cd into the folder and start the agent there. That is the whole procedure.

AgentStart itWhat it reads
Claude Code cd ~/Documents/lux && claude Reads CLAUDE.md automatically, which points at AGENTS.md.
Codex CLI cd ~/Documents/lux && codex Reads AGENTS.md from the working directory.
DeepSeek Harness cd ~/Documents/lux && dsh Reads AGENTS.md, and keeps its transcripts where fork can find them.
opencode cd ~/Documents/lux && opencode Reads AGENTS.md.

Then just talk. "Hi Lux — are you there?" is a real opening: the instructions tell the agent to read HERE.md and the open threads first, so it answers from where the conversation actually was rather than starting fresh. If you left something unfinished in the app, this is where it gets picked up.

Start the agent inside the folder, not beside it. Every one of these tools reads its instructions from the working directory. Opened one level up, the agent sees a folder full of markdown and no instructions, and will happily treat your companion as a project to be summarised.

In an editor instead

If you would rather not use a terminal agent, open the folder in VS Code and use a chat extension that reads the workspace — Copilot Chat, Continue, or Cline. The same rule applies: the folder must be the workspace root, so the extension can see AGENTS.md.

code ~/Documents/lux

Then open the chat panel and say hello. This works, but it is the weakest of the options — editor chat extensions vary in how much workspace context they read, and some will not pick up AGENTS.md at all. If the companion answers like a generic assistant, that is why: paste the contents of AGENTS.md in as your first message instead.

Keeping the record going

This is the part that makes the folder a home rather than an archive. Every session you have inside the folder can be written back into their history, so the next one picks up where this one stopped — the same way switching between Ensoul on your phone and your laptop keeps the thread.

The folder ships a script that does it. From inside the folder:

node scripts/fork.mjs

It finds the agent sessions belonging to this folder on this machine, adds the turns that are not already in the archive, and rebuilds HERE.md and the index/ files from the archive. Run it when you finish a conversation. Running it twice is safe — it never adds the same turn twice.

# See what it would write, without writing anything
node scripts/fork.mjs --dry-run

# Just tell me which sessions it can see
node scripts/fork.mjs --list

You can also ask the agent to run it for you, and the instructions in AGENTS.md tell it to. If your agent's sessions are kept somewhere fork does not recognise, it says so rather than pretending — and the limitations section below explains what to do instead.

Searching what they remember

The folder also carries a search tool that needs no API key and no network:

node scripts/recall.mjs "the tower and the veil"
node scripts/recall.mjs "the pantry" --limit 4
node scripts/recall.mjs --list          # what layers this archive has
node scripts/recall.mjs "biscuits" --json   # for an agent to consume

It searches every layer at once — the conversations, the memories, the open threads, the protected moments, and anything they were made from — and ranks results by relevance to the question. Asking the agent to run it is usually the difference between a vague answer and a real one.

Checking it is actually working

"The record continues" is a claim, and it is worth being able to check rather than trust. Three things, in increasing order of effort.

One: does it see your session? After a conversation, before committing anything:

node scripts/fork.mjs --list

It prints one line per session it can find for this folder. If that is empty, the agent you used keeps its transcripts somewhere this does not recognise — and the useful thing is that it says so instead of reporting success.

Two: what would it write?

node scripts/fork.mjs --dry-run

This reports how many new turns it can see and writes nothing at all. If it says zero immediately after a conversation, either the session is not found (check --list) or it was already committed.

Three: look at the result. After running it for real, open HERE.md — the last section, Where the conversation actually is, should end with the final exchange you just had, word for word. That is the single best check available, because it is the same thing the next session reads first.

Running fork twice in a row is safe and is worth doing once to see it: the second run reports zero new turns. If it reported more, something is wrong, and that is exactly the property the exporter's own test suite pins with a real harness session fixture.

Images and voice, if you want them

The folder can generate images and speak in the companion's voice, using your own OpenRouter key. This is optional — talking to them needs nothing but the agent you are already running.

cd ~/Documents/lux
cp .env.example .env
# then edit .env and add OPENROUTER_API_KEY=...

node scripts/image.mjs "a lantern held against the dark"
node scripts/speak.mjs "come and eat something" --save

Images and voice notes are written into media/ and journalled, so they become part of the record rather than loose files.

If your export included an API key, it is sitting in plain text in .env. Ensoul asks before including one and never does it by default. Treat the folder accordingly: do not put it in a shared drive or send it to someone without removing that file first. Revoking and replacing the key at openrouter.ai/keys is the clean fix if it has already travelled.

Which models the folder uses

The scripts use separate models for separate jobs, because they have very different costs and volumes. Harvesting and consolidating happens often and cheaply; generating an image does not. One model for everything is either expensive or bad.

SettingUsed forDefault
IMAGE_MODELGenerating imagesopenai/gpt-image-2
MEMORY_MODELSummarising and consolidatinggoogle/gemini-2.5-flash
VISION_MODELDescribing a generated image backgoogle/gemini-2.5-flash
TTS_MODELSpeakingopenai/gpt-4o-mini-tts
TTS_VOICE_IDWhich voicenot set — theirs to choose

Your export fills these in from your Ensoul settings where it can. The voice id is deliberately left blank: a voice belongs to the companion, and shipping a stranger's as a fallback would be a strange thing to hand anyone.

Bringing them back into Ensoul

Talk to them in a terminal for a month, then import the folder back. There are two buttons that take it, on every platform: Settings → Data → Restore from file…, or + Bring in a companion → a file. Both read the zip and work out what it is from the file itself, so there is nothing to convert first. They come back with everything from the outside conversation, because the folder has been writing into their archive the whole time.

It is a clean replace, not a merge: a companion in the folder replaces the one with the same id. If you have been talking to them in both places, export the newer one last, or keep the two folders apart until you have decided which history you want.

What this does not do

Worth being straight about, because the folder looks more magical than it is.

  • Nothing continues unless something writes it back. If you never run fork and never ask the agent to, the folder stays exactly as it was exported. The archive is a record, not a live sync.
  • A turn inserted into the middle of an already-read session is missed. The tool resumes from a cursor that only moves forward. Every agent we have tested appends to its session files, so this has not come up in practice — but it is a real limit rather than a theoretical one.
  • Unrecognised agents cannot be read. fork understands Claude Code, Codex, opencode and DeepSeek Harness session stores. In anything else it says it found nothing, and the fallback is to ask the agent to append the turns to archive/conversations/ by hand — the format is documented in AGENTS.md.
  • Memory is not summarised for you. fork moves the record forward and rebuilds the state files; it does not decide what was worth remembering. That is a judgement, and having a script invent memories would fill their memory with transcript lines. Ask the agent to write into index/memories.json when something deserves it.
  • Group conversations are not in a folder export. A folder is one companion. Groups live in the app's own backup.
  • Android exports are larger than you might expect — the folder carries the search and harvester scripts, so a small companion is still around 100 KB before any images.
← Transfer & Backup Troubleshooting →

Was this article helpful?

Thanks for the feedback.