Your app, with someone home.

AgentGraft puts an AI assistant inside your Django app. It knows who it's talking to, calls your own Python functions, and remembers people between visits. One Python file is the whole integration, and it's live below.

Ledgerline Data assistant

Ask about any dataset in your workspace.

Which datasets grew fastest this month? What changed in Churn cohort?
Which datasets grew fastest this month?
list_datasets 6 datasets

Remembered: you send growth numbers to finance on Mondays.

Tap a line or a part to trace it.

Select a line to see what it controls, or change the voice and watch the reply.

That's it, in the corner.

It's the real assistant that runs this site. Click it and ask anything about AgentGraft.

It reads the room.

The face carries the whole state of the widget, so the button never needs a label. It notices the page and the person on it: when you come close, when it's busy writing, when everything has gone quiet, and how the one typing feels.

01 What it's doing.

Six states, straight from the widget. Its eyes move in saccades, snap and hold, and it blinks at uneven intervals, so it never looks like a loop.

Awake Follows you around the page.
Curious Leans in when you come close.
Thinking Looks away while it writes.
Drowsy Gets heavy-lidded when it's quiet.
Dozing Dozes off, wakes with a stretch.
Excited Waves when a reply is waiting. Click the wave to jump to it.

02 How it feels.

Sixteen expressions, from delight to grief and calm to alarm, plus the looks a conversation runs on: a wink, a raised brow, a slow nod while someone vents. As a visitor types, a fast classifier reads each message and the face answers while the words are still arriving.

It responds rather than mirrors. Panic gets focus, bad news gets sympathy, a compliment gets a blush. Every expression is a pose, not a clip, so it moves between any two without a seam.

01 / 16
Baseline

Attentive

Mood

 

Drag on the circle to blend any of them.

It remembers who it's talking to.

Set memory_enabled=True and that's the setup. When a conversation gets long, a background agent sleeps on it and keeps what's worth keeping as facts in a small graph, like "Maya manages the Lisbon team". It updates facts that change and retires the ones that stop being true.

People can say "remember that" or "forget that" mid-chat, and see, edit or delete every fact from the widget's settings. A fact they edit is theirs; the agent won't touch it again.

mardi

M

Pull signups by week. ISO weeks please, we report Monday to Sunday.

Assistant

Here are weeks 36 to 39, Monday start: Signups by week

Kept: reports in ISO weeks, Monday start.

The next Tuesday

M

Same report as last week?

Assistant

Weeks 37 to 40, ISO weeks like last time, as a CSV: Signups by week

What it knows about Maya

From the widget's settings
  • Reports in ISO weeks, Monday start
  • Manages the Lisbon team
  • Prefers CSV exports to charts

Ship it with one command.

agentgraft_sync reads the file, resolves your policies from the Policy Shop, and pushes tools, agents and settings as one atomic update. Either every change lands or none does.

Put it in your pre-deploy step and the assistant ships with the code that serves it. A prompt change is a diff your team reviews in a pull request, and git revert rolls it back.

~/ledgerline pre-deploy

        

The next message uses the new config.

One tag for the web. Python for everything else.

Put the tag in your base template for an assistant on every page, or in one template to scope it. It signs the visitor's identity on your server, so AgentGraft knows who is asking without touching your database.

Not every conversation happens in a browser. ag.Client brings the same tools and the same memory of each person to a Slack bot, a WhatsApp number or your mobile app.

  • Web widget
  • Slack
  • WhatsApp
  • Mobile
  • Your own UI
templates/base.html
{% load agentgraft %}
{% agentgraft_widget %}
slack_bot.py headless
import agentgraft as ag

client = ag.Client.from_profile("default")

# In your Slack handler. Same person, same memory.
response = client.chat(
    user_id=f"slack:{event['user']}",
    message=event["text"],
    auto_route=True,
)
say(response["text"])

Your data never leaves your app.

AgentGraft holds the conversation and the shape of your tools. Your app holds the users, the data and the code. When the assistant needs a tool, AgentGraft sends a signed request to your webhook; your function runs where your data already lives and returns only what you wrote it to return.

Visitor's browser

  • The widget
  • An identity your server signed

AgentGraft

  • Tool schemas, never tool code
  • Conversations
  • Memory, encrypted per visitor

Your Django app

  • Utilisateurs
  • Data
  • Tool code, and every tool run

Delete a visitor and they're gone. Backups too.

Every visitor gets their own AES-256-GCM key, chained to your app's secret by a23crypt. Delete the visitor and the key goes with them: every copy of what they said, backups and replicas included, becomes unreadable noise.

Visitors can export everything as JSON and edit or delete any remembered fact. The ghost button opens a private chat that leaves nothing behind.

Maya Ortizuser:4127

Visitor key 7f3a 91c0 e4d2 5b18 … a90c 0c6e
  1. 1Prefers growth month over month, not week over week.
  2. 2Sends growth numbers to finance on Mondays.
  3. 3Maya —manages→ the Lisbon team.
  4. 4Owns the Q3 revenue dataset.

4 facts kept from 3 conversations.

Also in the file.

Each of these is one line in agentgraft_config.py, or already in the widget.

Accent colour
palette="jade"
Buttons, links and the face take your colour, in light and dark. Visitors can pick their own if you let them.
Diagrams and math
in the widget
Mermaid diagrams, KaTeX math and highlighted code blocks render inside replies.
Follow-up questions
followups_enabled=True
Each reply ends with a few questions the visitor might ask next.
Handoffs
handoffs=["billing"]
One agent passes the conversation to another. sub_agents delegates a task and takes the answer back.
Image attachments
image_uploads_enabled=True
Visitors drop, paste or pick images to ask about.
Long-term memory
memory_enabled=True
A background agent sleeps on each conversation and curates facts into a graph. A recall agent finds them when they matter.
Policy Shop
ag.policy("agentgraft/cite-sources")
Reusable prompt fragments, referenced by codename and resolved at sync.
Private chat
@ag.agent(private=True)
A ghost button for an incognito chat that stores nothing.
Recap
recap_enabled=True
When a visitor comes back to an idle thread, a short note on where they left off is waiting.
References
ag.ref("dataset", id, name)
Objects your tools return become chips that link straight into your app.
Voice
voice_enabled=True
Visitors talk instead of type, and hear replies read aloud.