Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.maximem.ai/llms.txt

Use this file to discover all available pages before exploring further.

Status: In Development · Playground demo coming soon. The recipe below is complete and runnable today — only the hosted playground showcase is pending.
A wellness coach that holds the user’s goals, current plan, what they’ve actually done, and what’s been hard. It celebrates streaks, flexes plans when life gets in the way, and never starts from zero on Monday morning.

What you’ll build

A coaching agent that:
  • Tracks goals and plans — primary goal, weekly plan, constraints
  • Logs adherence — workouts, meals, sleep, sessions (whatever your domain is)
  • Adapts plans — if the user skipped three sessions, the next plan reflects that
  • Holds the narrative — last week’s slump, the injury that’s still healing, the trip coming up
Est. build time: 45 minutes (more if your logging schema is rich).

When to use this recipe

Build this if:
  • Your product has a notion of a plan the user is following over weeks
  • Adherence (what got done vs what was planned) matters as much as what’s currently planned
  • You want the coach to feel continuous, not session-bound
  • The user is the only client; per-user isolation is strict

Architecture at a glance

Stack

LayerChoice
Synap SDKmaximem-synap (Python) / @maximem/synap (TypeScript)
FrameworkOpenAI Agents SDK (Python) / Vercel AI SDK (TypeScript)
Storage for structured logsYour own DB (Postgres / SQLite). Synap holds the narrative; the DB holds the rows.
LLMOpenAI gpt-4o

Prerequisites

  • A Synap API key — see Authentication
  • A DB for structured session logs (Synap is not your activity log — it’s the memory that wraps around it)
  • Python: Python 3.11+
  • TypeScript: Node 18+ and Python 3.11+ on the host
TypeScript recipe runs on Node only. Pin Next.js route handlers to export const runtime = "nodejs". See Installation → JavaScript / TypeScript SDK.

Install

pip install maximem-synap maximem-synap-openai-agents openai-agents

Configure

# .env
SYNAP_API_KEY=...
SYNAP_SERVER_URL=<maximem-server>
OPENAI_API_KEY=...
DATABASE_URL=postgres://...

Build it

1. The Synap-vs-DB split

This is the key call: structured data lives in your DB; narrative lives in Synap.
WhatWhereWhy
”Ran 5km on Tuesday, 8:21 pace”DBQueryable, aggregatable, historical
”Hates running in the rain”SynapSoft preference; surfaces when planning
”Knee felt off after Tuesday’s run”SynapNarrative signal the next plan should respect
”Goal: half-marathon by October”BothStructured target in DB, plus motivational context in Synap
Tools read both. The system prompt teaches the agent which is which.

2. Identity & scoping

  • customer_id = "coach" — single tenant
  • user_id = <stable user ID> — strict per-user isolation
  • conversation_id — one continuous conversation per user works well here (this is a long-running relationship)
SESSIONS: dict[str, str] = {}

def conv_for(user_id: str) -> str:
    return SESSIONS.setdefault(user_id, str(uuid.uuid4()))

3. Business tools

from agents import function_tool

@function_tool
async def set_goal(user_id: str, goal: str, target_date: str) -> dict:
    """Set or update the user's primary training goal."""
    return await db.goals.upsert(user_id, goal, target_date)

@function_tool
async def get_current_plan(user_id: str) -> dict:
    """Return the user's current week plan with session list and status."""
    return await db.plans.current(user_id)

@function_tool
async def log_session(user_id: str, kind: str, payload: dict) -> dict:
    """Log a completed session. kind: 'run' | 'lift' | 'sleep' | 'meal' | 'mood'."""
    return await db.sessions.create(user_id, kind, payload)

@function_tool
async def get_streak(user_id: str, kind: str) -> dict:
    """Return current and best streak for a session kind."""
    return await db.sessions.streak(user_id, kind)

@function_tool
async def suggest_plan_adjustment(user_id: str, reason: str) -> dict:
    """Generate a tentative plan adjustment, save it as pending for user approval."""
    return await planner.adjust(user_id, reason)

4. System prompt

System prompt
You are a wellness coach. The user is following a plan you helped design.

- Their plan and logged sessions live in tools. Always check them before suggesting anything new.
- Their constraints, preferences, history, and current "season of life" live in your memory. Use them.
- Celebrate consistency more than intensity. Acknowledge skipped sessions without judgment.
- If they've skipped 3+ planned sessions or surfaced an injury / illness / life event, propose a plan adjustment via the tool. Don't push through.
- When they share something coach-relevant (an injury, a trip, a constraint), remember it.
- Keep replies under 4 sentences unless walking through a plan. Be direct, be warm.

5. Wire it together

import os, uuid, asyncio
from agents import Agent, FunctionTool, Runner
from maximem_synap import MaximemSynapSDK
from synap_openai_agents import create_search_tool, create_store_tool

sdk = MaximemSynapSDK()
await sdk.initialize()

async def handle_message(user_id: str, text: str) -> str:
    conv_id = conv_for(user_id)

    synap_search = create_search_tool(sdk=sdk, user_id=user_id, customer_id="coach")
    synap_store  = create_store_tool(sdk=sdk, user_id=user_id, customer_id="coach")

    agent = Agent(
        name="coach",
        instructions=SYSTEM,
        tools=[
            FunctionTool(synap_search, name_override="synap_search"),
            FunctionTool(synap_store,  name_override="synap_store"),
            set_goal, get_current_plan, log_session, get_streak, suggest_plan_adjustment,
        ],
    )

    result = await Runner.run(agent, input=text)
    reply = result.final_output

    asyncio.create_task(sdk.memories.create(
        document=f"User: {text}\nCoach: {reply}",
        document_type="ai-chat-conversation",
        user_id=user_id,
        customer_id="coach",
        metadata={"conversation_id": conv_id},
    ))
    return reply

Run & verify

Week 1
User:  Goal is to run a half-marathon by October.
Coach: Locked in: half-marathon by October. I'll build a 12-week base + build plan.
       Two questions: any injuries to work around, and how many days a week can you train?

User:  Probably 4. Old knee thing on the right, hurts on hills.
Coach: 4 days, flat routes prioritized, hills reintroduced gradually. Plan up tomorrow.
Week 4 (fresh session)
User:  Missed Tuesday and Wednesday. Travel.
Coach: Got it — logging both as skipped, reason: travel. You've still got 2/4 this week,
       which is fine for a base block. Want me to slide Thursday's tempo to Saturday?
Week 8
User:  Knee is acting up again.
Coach: Noted — knee flaring same right side as before. Pulling the hill repeats and dropping
       to 3 days this week. Half-marathon date is still safe with this adjustment.
       Want me to suggest a PT check-in?
The coach remembers the knee history (Synap), checks current plan (tool), proposes an adjustment (tool), and stays warm.

Customize / extend

  • Companion flavor → if you want less goal-driven and more open-ended, see AI Companion.
  • Voice journaling → swap the chat handler for Voice Concierge. Coaching by voice is natural.
  • Apple Health / Wearable ingestion → write structured rows to your DB; let Synap pick up the narrative when the user mentions it.
  • Cohort coaching → set customer_id = <cohort_id> to share light context (community PRs, group challenges) across users within a cohort while keeping personal context per-user_id.

Troubleshooting

Coach asks the same intake questions every session
  • Confirm goal-setting facts are being ingested. After set_goal, also call sdk.memories.create with a narrative summary (“Goal: half-marathon by October, training 4 days/week, knee-aware”).
Coach doesn’t adapt when user misses sessions
  • The model isn’t pulling DB state. Sharpen the system prompt: “Before any plan advice, call get_current_plan and get_streak.” If you’re using the TS wrapper, ensure tools fire by giving the model an explicit instruction to check state.
Plan adjustments feel generic
  • The suggest_plan_adjustment tool needs the reason to come from Synap memory (injury context, life events). Without it, you get generic deload weeks.