The path is /workbench/text/chat. This is the deep-conversation room, not the little floating bubble you see on other pages. It's a full IM interface - a 240px agent list on the left, a scrollable transcript on the right, and a message box at the bottom. You can talk to every agent here, built-in and custom alike, and because x-rush is wired into the industry's top-tier model pool - Claude Fable 5, GPT-5.6, Gemini 3.5, Qwen3.7 Max and the rest - each turn gets smart-routed to the model that fits the task best, and the lineup updates as the world moves. So the character you're talking to isn't pinned to one brain; it's always riding the strongest model for the moment. If you've only ever poked at the bubble, this is where you go when you actually want to sit with one of these agents for a while.
It's also the middle of a three-stop flow: Auto Content hands you a daily nudge, you "continue chatting" in here to go deep, and when something's worth keeping you copy it to T-1 HTML Pages to publish a standalone page.
What AI Chat Actually Is
It's a chat app, basically. The kind you already know how to use. Pick an agent on the left, type at the bottom, hit enter, get a reply. No prompt templates, no mode toggles, no "select your content type" dropdown - those live in the Auto Content module. Here you just talk.
The difference from the bubble is the whole point. The bubble is for fragments: a horoscope line, a trivia card, a 2-sentence nudge from an agent you turned push on for. Chat is for the long version. You can ask follow-ups, push back, change your mind mid-sentence, and the agent keeps the thread. You can also bring context with you (more on that below), which the bubble flat-out can't do.
The left rail is 240px wide and lists everyone you can talk to. The built-in seven ship with the product:
- Tarot Reader 🔮 - draws a card, gives upright/reversed read and daily advice
- Trivia Master 💡 - the "did you know" one
- Horoscope ♈ - daily love / work / finance brief
- Fitness Coach 💪 - workout and diet plans against your goal, level, days, and equipment
- Study Assistant 📚 - study tips tuned to a field and a goal
- MBTI Analyst 📊 - personality insight off your type
- Nutritionist 🍎 - meal plans with calorie estimates
Below those, your custom agents. The header literally reads Custom Agents (3/10) - count over ten - so you always know how much room is left. Hit ten and the "Create Custom Agent" entry goes quiet on you; you'll have to delete one before adding another. That's intentional. Ten is enough to cover the recurring cast of characters most people actually use, and it keeps the sidebar scannable instead of turning into a 40-item dump.
Per-Agent History: One Agent, One Thread
Here's the part that took the most arguing internally. Every agent gets its own message history, stored in a map keyed by agent id (the field is messagesByAgent in the code). Switch from Tarot Reader to Fitness Coach and back, and your tarot thread is exactly where you left it. Nothing clears.
This matches the mental model people already have from every other chat app: one contact, one thread. The alternative - a single shared history that gets passed around - sounds simpler until you use it, and then it's a mess. You'd ask the Nutritionist a question and it'd be reading your tarot draw as context. So we didn't do that. Each agent's thread is its own. Switching is free.
(The history lives in memory for the session, so it's per-agent and instant - switching agents never costs you the thread. A hard refresh starts fresh, which keeps the client fast and stateless.)
Session Reuse: Why We Don't Open a New Session Per Message
When you send the first message to an agent, the backend lazily creates a session_id for that agent and hands it back. Every subsequent message to the same agent reuses that id. The map on the frontend is sessionByAgent, and it gets backfilled the first time the facade returns a real session.
Why bother? Because the alternative is a new backend session for every single message, and that's how you get an agent with no memory of what it said ten seconds ago. The session id is what lets the model see the running thread. Reusing it is the difference between "we've been talking" and "who are you again?" It also keeps the backend session table from ballooning with one-row sessions nobody will ever reopen.
In mock mode (the local demo build) the facade returns a placeholder id and none of this matters, but the code path is identical - so the real backend is a config flip, not a rewrite.
Custom Agents, Tuned to Your Taste
Here's where it gets fun. The built-in seven are great, but the real pull is making an agent that's yours. Click "Create Custom Agent" (or the + on a custom slot) and the AgentFormModal opens - and this is the part most chat tools underbuild. You don't just get a name and a prompt; you shape a custom agent across four dimensions, so it looks and feels the way you want, not just behaves the way you want.
The modal takes a name (the handle, shown in the sidebar and as the agent's self-introduction) plus four dials you actually get to tune:
- Background (system prompt) - the behavior instruction, and where the personality actually lives. "You are a snarky code reviewer who hates nested ternaries" works. "Be helpful" does not. Want a stoic drill sergeant? A warm, rambling storytelling grandma? This field is how.
- Personality (description) - the one-liner under the name, shown when you're picking between agents. Part label, part vibe-setter - the flavor text that tells future-you what they're about to talk to.
- Avatar - emoji or image URL. Drop in 🔮, paste a hosted image link - your call. The renderer (
getAgentEmoji) prefers what you set, so a custom agent shows the face you chose on every message, not a generic default. Small thing, but it's the difference between "an agent" and your agent. - Chat background - a hex color (like
#00D4AA, the module accent) or an image URL, painted across the chat transcript area. This is the one people sleep on. Set a calm blue behind the Study Assistant, a warm tone behind the Nutritionist, and the room changes feel before the first reply lands. You're going to stare at this surface - might as well make it yours.
That's four dials - behavior, personality, look, and the surface you're reading on. Name it, tell it who to be, give it a face, paint the walls. Most chat tools hand you one or two and call it a day.
Save and the new agent is selected automatically - you're dropped straight into a fresh thread with it, no extra click. Editing an existing custom agent reuses the exact same modal, pre-filled; the only difference is the button reads "Save Changes" instead of "Create". Built-in agents can't be edited - they're platform-owned - and the share button on them is disabled with a tooltip saying so.
Deletion is two steps on purpose. Click delete on a custom agent and you get the DeleteAgentConfirmModal: "Delete this agent?" with Delete / Cancel. We made it a separate modal rather than a browser confirm() because the cost of a misclick here is losing the system prompt you spent time writing, and there's no undo. Cancel, nothing happens. Confirm, it's gone, the sidebar reflows, and that agent's history goes with it.
Coming from Auto Content: URL Context Injection
This is the link between Auto Content and Chat. When you're reading an auto-generated card in Auto Content and hit "continue chatting", you land on /workbench/text/chat?agent=<id>&context=<autoContentId>. Two things happen on arrival:
- The agent in the URL is auto-selected - you don't have to hunt for it in the sidebar.
- A ContextCard appears at the top of the transcript, labeled "📎 Referenced from Auto Content", quoting the title and body of the card you came from. Minimize it, close it - your call.
The intro message is injected once, and only when that agent's history is empty. It reads roughly: I see you shared this content: "" What would you like to discuss further? - and it lands as the assistant's first turn, so your first actual message has something to bite into. If the agent already has history (you'd chatted with it before), we don't clobber that - the context rides along as context, not as a fake prepended intro. The URL state is read eagerly on mount, not in a setState-in-effect, so there's no flash of "wrong agent, then correct agent" on load.
Chat vs. the Global Bubble
People get these two confused. Quick way to keep them straight:
- The bubble (floating, on most pages) shows only agents you've turned push on for. It can't carry context. It's for fragments - a one-line horoscope, a trivia card. It's also hidden when you're on any
/workbench/* page, because two chat surfaces on one screen is a mess and you're here to work. - Chat (this page) lets you talk to all agents, push on or off. It carries context from Auto Content. It's for actual conversations.
Rule of thumb: if you're reading something and want to react with one tap, that's the bubble's job. If you want to sit with an agent for ten minutes and work something out, come here. The bubble is the notification; Chat is the room. And because the agents behind it run on the strongest model the router can find for the turn - Claude Fable 5, GPT-5.6, Gemini 3.5, Qwen3.7 Max, whoever fits - the room's a lot smarter than a notification has any right to be.