Introduce turns without replacing your LLM client.
Most teams do not rebuild their application to add memory. This guide covers the minimal integration path: intercepting existing LLM calls to extract memory, injecting context before those calls, and gradually expanding the integration without disrupting what already works.
The minimal integration
Spectron's minimum viable integration is two operations around your existing LLM call:
Before the call – retrieve relevant context and prepend it to the system prompt.
After the call – record the user message and assistant response as turns.
No sessions are required for the first pass. You keep your existing data model and LLM client; Spectron sits beside them as the memory layer.
# 2. Inject into your existing system prompt system=your_existing_system_prompt() ifctx.formatted: system=f"{system}\n\n## Relevant context\n{ctx.formatted}"
# 3. Your existing LLM call – unchanged response=your_existing_llm_call(system=system,user=user_message)
# 4. Record the exchange awaitsession.turn(role="user",content=user_message) awaitsession.turn(role="assistant",content=response)
The key principle: do not change what your LLM receives if there is no relevant memory. The if ctx.formatted guard ensures that when Spectron has nothing useful to add, the call is identical to the original.
Intercepting existing LLM calls
If your application already has a wrapper around LLM calls, add memory extraction at that layer. This avoids scattering Spectron calls throughout your codebase.
Making session_id optional means the change is backwards-compatible – all existing call sites continue to work without passing a session.
Starting with a single scope
Do not attempt multi-user scoping on day one. Start with a single organisational scope and confirm the extraction pipeline is working correctly before splitting by user.
# Phase 1: single scope, all conversations share it DEFAULT_SCOPE={"org": "my-app"}
The profile and context endpoints are scope-matched: a scope of {"org": "my-app", "user": "alice"} matches memory stored under {"org": "my-app", "user": "alice"} and also memory stored under the broader {"org": "my-app"} scope (scope floor matching). Starting broad and narrowing later does not require data migration.
Expanding to multi-user
Once single-scope extraction is verified, add the user dimension. The only change is in how you create sessions:
# Before session=awaitmemory.sessions.create(scope={"org": "my-app"})
# After session=awaitmemory.sessions.create(scope={"org": "my-app","user": user_id})
Existing memory under the org-only scope remains accessible via scope floor matching. New memory is stored under the user scope and is only visible to that user's context retrievals.
Profile injection at session start
Once you have per-user memory accumulating, add profile injection at the start of each new conversation:
profile=awaitmemory.profile(scope={"org": "my-app","user": user_id}) system=your_existing_system_prompt() ifprofile.summary: system=f"{system}\n\n## About this user\n{profile.summary}"