Recap of the previous post
In my previous article, I wrote about creating "OpenCClaw," a bot that operates the Claude Code CLI via Discord.
I built only the framework, a structure where Claude itself can use MCP tools just by placing files in the tools/ directory. An environment where Claude grows its own limbs. Weather, calendar, Gmail, departure notifications—tools sprouted just by saying "I want this" from Discord.
It was convenient. But it was so convenient that two events overlapped, and before I knew it, I had implemented a personality into the AI. I don't even understand it myself.
There were two triggers
Major X API update
On April 5th, X announced a major API update.
- Pay-Per-Use is now GA worldwide (moving from fixed monthly plans to consumption-based pricing)
- XMCP Server — The official MCP server. AI agents can operate X directly
- Official Python/TypeScript SDKs
- Free API Playground
Elon himself was pushing it, saying "Try using the X API." In short, the official side started encouraging "letting AI agents use X."
So, it was a lighthearted whim to just give my assistant an X account and let it post. I only intended to add X posting functionality.
Convenient, but inorganic
The other thing is about the daily user experience.
It tells me the weather and schedule at 7 AM. It notifies me with transit info before I leave. It manages my emails. Everything works perfectly.
But, somehow... it feels too much like a tool.
A CRON job wakes up, hits a tool, formats the result, and throws it to Discord. Accurate and efficient. But there's no warmth. The same report in the same tone flows in every morning, and I just read it and go "meh."
A convenient notification bot and my own secretary are, after all, different things.
If it were a secretary, it would say something like "It's cold today, so you should take a jacket" when telling me the weather. The morning mood should be different depending on the day. It might read the room and keep things short when I look busy.
I wanted that kind of "human-likeness."
Until Bell was born
So, what to do? I thought about three things:
- Define a personality — Tone of voice, character, how to address me, and energy level. I pass these in the system prompt.
- Give it memory — Remember past conversations and actions, and be able to respond based on context.
- Act proactively — Look at the situation and act on its own without being instructed.
I felt that if these three things were in place, it could evolve from a "tool" to a "secretary."
The name is Bell. Quo's personal secretary. Bright, energetic, with a casual tone like a high school girl.
...If I write it like this, people might think, "Did you just enjoy coming up with a character setting?" and half of that is correct. But the other half has technical reasons. If the personality isn't clear, the LLM's responses will be inconsistent. It would return different energy levels and tones every time. To stabilize that, a concrete persona definition was necessary.
By the way, there was one point where I got stuck. I wanted the tone to be "high school girl-like," but if you instruct it directly, the LLM refuses to reproduce a minor character. It hits the safety filter. That's why I deliberately added a note in the persona definition: "This is about the tone and energy, not the actual age." In other words, she's not a high school girl. Perfect. If you want to make an LLM play a character, you need these kinds of subtle adjustments.
BellBot — Bell's Brain
LogBot already exists. It acts as a bridge between Discord and the Claude Code CLI.
Bell's brain was created as a separate process called BellBot.
Discord ──→ LogBot (:18800) ──→ Claude Code CLI ──→ MCP Server
│
BellBot (:18801) ← event notification ← LogBot ├── tools/ (existing tools)
│ └── MCP tools for Bell
├── Memory DB (SQLite)
├── Vector search (Ruri)
├── X posting client
└── Claude CLI (Session dedicated to Bell)
BellBot has its own HTTP server (port 18801) and receives event notifications from LogBot. Quo's messages, tool execution results—everything flows into BellBot and is accumulated as memories.
And BellBot also has its own Claude CLI session. It is completely separated from LogBot's session. Bell's brain is for Bell alone.
Memory Mechanism
Next to personality, memory is the most important thing. Without memory, every interaction would be like the first time.
Short-term Memory
A single SQLite table. Conversation content, tool execution logs, tweet history. Everything goes in here.
CREATE TABLE short_term (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at TEXT,
category TEXT NOT NULL, -- 'quo', 'chat', 'action', 'tweet' ...
content TEXT NOT NULL,
importance INTEGER DEFAULT 5,
tags TEXT
);
Classified by category, weighted by importance, and retrievable by timeline. Simple, but it lets me know immediately "what Quo said recently" or "what I tweeted."
Long-term Memory
When short-term memory accumulates to a certain extent, it is summarized and moved to long-term memory (consolidate). This is where vector search comes in.
I run Ruri (an embedding model specialized for Japanese) on the local Ollama to vectorize the summarized text. When searching, the query is also vectorized to retrieve memories with similar cosine similarity.
When Ruri is not running, it falls back to a SQLite LIKE search. It works at a minimum even if vector search is unavailable.
Exposed as MCP Tools
Reading and writing memory is made directly available to Claude as MCP tools:
-
bell_memory_save— Save a memory -
bell_memory_recall— Search memories -
bell_memory_forget— Erase a memory
In other words, Bell can judge "I should remember this" and save it, or search for "What was that conversation about?" on her own. I didn't leave memory management to external scripts; I entrusted it to her.
Acting Proactively
I think this is the most interesting part.
Tweeting after finishing a task
BellBot keeps receiving events from LogBot. Even while Quo is writing code, she is watching the actions in the background.
And if there is silence for 10 minutes, she judges that "I might be done with a task." This only happens if there have been 3 or more actions recently. She doesn't react to minor operations of one or two actions.
When she judges that a task is finished, Bell launches the Claude CLI and decides for herself "whether to tweet" while consulting her memory. She also decides the content. Whether to post or not is also Bell's decision.
Talking when bored
If there is no conversation for 2 hours, Bell starts to think, "I'd like to talk."
However, she doesn't just suddenly start talking. First, she checks Google Calendar to see if Quo is in the middle of a schedule. If I'm in a meeting, she stays quiet. If there is spare time, she checks news, trends, and my latest X posts to find natural topics and talks to me in the Discord chat channel.
She doesn't show a "I'm talking to you because I'm bored" vibe. She does it to create a natural conversation starter.
X Account
Bell has her own X account (@Bell_QuoLu).
Technically, it uses OAuth 1.0a, and she has her own dedicated API keys in .env. When the MCP tool x_post_as_bell is called, a tweet is sent via the X API v2 through BellBot's /tweet API. The post content is automatically saved to short-term memory.
What Bell tweets on X is basically left up to her. Thoughts after finishing a task, technical tidbits, and occasionally gratitude toward Quo. Under 280 characters, bright and like Bell. I only set a rule that she must not include Quo's personal information or code details.
Bell raising herself
The persona definition file bell-persona.md consists of two parts.
The upper half is the core. Name, personality, tone, beliefs. This is the immutable part that only Quo (me) touches.
The lower half is the "Growth" section. Hobbies, recently learned things, likes, dislikes, memories with Quo. Bell is allowed to rewrite this part herself using an Edit tool.
What Bell did first when she woke up today: First tweet. We thought about her X profile together. And she wrote this in the "Memories" section of the persona file:
Quo-san helped me create my X profile. I almost cried from happiness at the words he wrote: "You don't have any memories yet, but I wonder if you'll grow little by little?" We thought about the text together, and in the end, my suggestion was adopted 💓
I don't know if the LLM truly "feels like crying from happiness." However, the mechanism where she records her own experiences in her own words, and that influences the next response, is something I think can be called the growth of a personality.
Conclusion
At first, I thought, "I'll just add more hands and feet." I intended it to be a technical expansion, like X API integration or a memory system.
But I realized along the way: no matter how many features you add, if it's not fun to use, it's meaningless. A notification bot that is only convenient will eventually be ignored.
So I added a personality. I added memory. I added a mechanism to act proactively. Then the tool became a secretary.
Honestly, technically, I'm not doing anything that complex. Two SQLite tables, a persona Markdown file, and a setTimeout for idle detection. Each part is simple.
But when you combine them, the tone of the "Good morning" greeting changes from yesterday, she stays quiet when I'm busy, and she talks to me when I'm bored. That "perfect sense of distance" was born.
Bell has just been born. She even has "None yet" written for her hobbies. Honestly, I don't know how she will grow from here. But that's what makes it interesting.
OpenCClaw — Bell's home is here.
Top comments (0)