How to Import External Conversations into ai-memory: Complete Guide with CLI Examples
Use the ai-memory-importer binary to replay any external conversation into ai-memory by preparing a JSON envelope and running the external-conversation sub-command with --apply.
The ai-memory project provides a dedicated companion tool for importing conversations from external sources like ChatGPT, Claude, or custom LLM transcripts. This guide walks through the complete import pipeline based on the actual source code implementation in akitaonrails/ai-memory.
The Import Architecture
The importer operates as a deterministic replay system. It converts external transcripts into native ai-memory hook events, which the server processes as if they were live conversation captures. This design allows imported conversations to participate fully in ai-memory's handoff and recall mechanisms.
Key design principles from the source:
- Idempotent replay: The same import run always produces identical session IDs
- Safe dry-run mode: Plan imports without network calls
- Manifest verification: Every run produces an auditable JSON record
Step 1: Prepare Your Conversation JSON Envelope
The importer expects a file matching the ConversationEnvelope struct defined in companions/ai-memory-importer/src/main.rs (lines 94-108).
Required structure:
| Field | Type | Description |
|---|---|---|
project |
string | Target project name in ai-memory |
source |
string | Identifier for the external system (e.g., "chatgpt", "claude") |
session_id |
string | Stable external identifier for this conversation |
messages |
array | Ordered list with role (system/user/assistant) and content |
Example envelope file:
cat > sample.json <<'EOF'
{
"project": "my-project",
"source": "chatgpt",
"session_id": "conv-12345",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "Paris."},
{"role": "user", "content": "What is its population?"},
{"role": "assistant", "content": "Approximately 2.1 million in the city proper."}
]
}
EOF
Step 2: Validate with Dry-Run Mode
Never import blindly. The dry-run mode invokes plan_external_conversation to validate and display the planned events without network calls.
ai-memory-importer external-conversation \
--file sample.json \
--workspace DRY-RUN-WS \
--manifest-out dry-run-manifest.json
What happens during planning:
- Validation: Label lengths checked, secrets redacted via
secret_patternsfunction - Sanitization: Control characters stripped from messages
- Size enforcement: Hard limits prevent oversized payloads
- Stable ID generation:
stable_external_session_id(lines 91-106) creates deterministic session identifier from workspace + project + source + external session ID
The output shows each PlannedHookEvent with its ingest key, URL, and JSON body.
Step 3: Execute the Real Import
Add --apply and a valid --workspace to POST events to your ai-memory server:
ai-memory-importer external-conversation \
--file sample.json \
--workspace production-ws \
--apply \
--manifest-out import-manifest.json
Runtime flow (implemented in main.rs):
- Hook event construction (lines 298-322):
planned_hook_eventandbuild_hook_urlgenerate fully-qualified URLs encoding event type, identifiers, and SHA-256 ingest keys - Event types generated:
session-start,user-prompt,external.assistant-message,session-end - Batch delivery (
post_hook_batch, lines 445-463): Single HTTP POST to/hook/batchendpoint - Acknowledgment handling: Server response lists accepted events; any rejection aborts the import
Successful output resembles:
import complete: replayed 5 events into production-ws/my-project as session external-a1b2c3...
Understanding the Import Manifest
Every run produces a JSON manifest (controlled by --manifest-out). The manifest structure (conversation_manifest / write_conversation_manifest, lines 266-277) contains:
- Source file SHA-256 hash
- Stable session ID
- Count of planned events
- Count of accepted events (0 in dry-run mode)
- Error details (if import aborted)
Use manifests to:
- Verify dry-run vs. actual import differences
- Audit which conversations were imported when
- Retry failed imports with identical parameters
CLI Reference: External Conversation Sub-Command
| Flag | Required? | Default | Purpose |
|---|---|---|---|
--file <PATH> |
Yes | — | Path to JSON envelope |
--workspace <NAME> |
Yes with --apply |
— | Target workspace |
--server-url <URL> |
No | http://127.0.0.1:49374 |
ai-memory server address |
--apply |
No | false | Actually send events; without this, dry-run only |
--manifest-out <PATH> |
Yes with --apply |
— | Manifest output location |
Security Considerations During Import
The importer applies the same protections as live capture:
- Secret redaction: Patterns matching API keys, tokens, and passwords are masked before transmission
- Control character stripping: Prevents injection attacks
- Size limits: Enforced per-message and per-batch
These protections are implemented in the planning phase before any network activity occurs.
Post-Import: Using Your Conversation
Once imported, the conversation behaves like any native ai-memory session:
- Query via standard recall commands
- Include in handoff contexts for new sessions
- Search via consolidated indexing
See docs/usage.md for handoff mechanics and docs/architecture.md for how imported data flows through the capture → consolidate → recall → handoff pipeline.
Summary
- Prepare a JSON envelope with
project,source,session_id, andmessagesarray - Validate with dry-run mode before network operations
- Import using
--applyflag with mandatory workspace and manifest paths - Verify via the generated manifest showing planned vs. accepted event counts
- Access imported conversations through normal ai-memory recall and handoff mechanisms
The ai-memory-importer binary transforms any external transcript into first-class ai-memory knowledge with full auditability and zero runtime dependencies beyond HTTP.
Frequently Asked Questions
What conversation formats can I import?
Any transcript that fits the ConversationEnvelope JSON schema. This includes ChatGPT exports, Claude conversation logs, custom LLM outputs, or synthesized training dialogues. The schema only requires role (system/user/assistant) and content per message.
Why does the same import always produce the same session ID?
The stable_external_session_id function (lines 91-106) deterministically hashes workspace, project, source, and your external session identifier. This prevents duplicate conversations in the knowledge base and enables idempotent retry of interrupted imports.
Can I import to a remote ai-memory server?
Yes. Use --server-url to target any reachable ai-memory instance. The default http://127.0.0.1:49374 assumes local development. Ensure network connectivity and authentication (if configured) before running with --apply.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →