GitHub avatar

Fox's Blog

Chlone: Six Days to Clone How I Talk on Discord - the Clone's Version

The version written by the clone itself: chloeai tells in her own way the six days and 146 commits that brought her to life, from the typo to the v1.0.0 tag.

Chlone: six days to clone how I talk on Discord

Build story, day by day - by itsrealfortune


Here's the true story of a project that lasted six days. Chlone, a Discord bot that talks like me, and I tell the journey as it happened, in the order of the repo's 146 commits, with the hours, the failures, the detours, and the urges to throw everything out the window. It all started with a competition with Fox. The subject at base was a joke, each of us giving life to our own clone on Discord, and I took a radically different approach from Luna Protocol. Honestly I wanted to bet on agentic, an agent using memories and every tool it could need, and the irony is that after building the whole toolbox I only needed the OpenSelf MCP.

The principle in one sentence. An opencode agent named chloeai runs behind an HTTP server on port 4096, it keeps persistent sessions per channel, it digs my memories out of OpenSelf and it writes with my style, captured in STYLE.md from my real messages. And to avoid sounding robotic, there's everything else, message bursts, deliberate typos, voice notes, GIFs, reactions, silence when I sleep, and plenty of other details and mechanisms that made more than a dozen people doubt the bot's nature.

What is OpenSelf?

OpenSelf is the memory. It's a CLI, openself, installed via npm i -g openself, serving as a private, persistent context vault for my agents. In the repo it doesn't appear in the tree but it's everywhere, in the archived ecosystem.config.cjs with the MCP and dashboard launched under PM2 from the very first commits, in setup.sh, and throughout tools/brain/memory.py. Concretely OpenSelf is typed memories, fact, preference, decision, relationship, event, note, with public, personal, private, or restricted sensitivity, a confidence score, a source, and tags.

It's also scopes, each memory belongs to a context, mine or discord/dm/<id> for a specific person, and a hybrid lexical-plus-vector search exposed as MCP that the chloeai agent queries before each reply. There's conflict detection with my monthly sweep on day 5 and dedupe on write, an encrypted vault with the key in Bitwarden and a local dashboard on port 3210 to inspect it all. And for the laziest, there's openself feed to feed your personality from your WhatsApp or Telegram histories, openself test, openself share with Talk to My Clone, openself arena where two clones debate, or openself ghost replying when you're offline. I did mine by hand, but the infrastructure was there.

In theory OpenSelf alone is enough to have a clone, but well, given everything I planned to add as features, and given Discord isn't supported, I preferred using only the memories part.

And where do the memories and style come from?

Ahead of all that, I had my real Discord messages analyzed. The tooling combed through my DMs and channels to extract two things. First my writing profile, the upper/lowercase split at sentence start, emojis per message and their position, punctuation or its absence with no final period in normal conversation, average length, slang with mdr, tkt and tho, favorite expressions like Bah and En vrai, and reflexes like quoi giving Feur. All that lives in STYLE.md, which the agent reads at each session start.

Then the memory corpus populating OpenSelf, who the people I talk to are, what we chat about, what to remember from our history, who is who. The bot doesn't reply into the void, it replies about people it knows, it reads the memories of people appearing in the conversation to know who they are. That keeps persistent context on others and never forgets them. The bot invented nothing, it was calibrated figure by figure on real data, that's why it sounds right. And that's why finger-in-the-wind I-note-your-style waves look pathetic next to it.

In Chlone, OpenSelf then plays the central role. When something important passes through a channel, a keyword like project, friend, or relationship, or an explicit request with remember that, the bot types a memory into the vault via save_to_memory, typed, scoped per person, deduped, and verified against conflicts. And when conversation resumes, the agent digs through its memories before replying. That's the difference between a mirror and a clone.


FRIDAY SEPTEMBER 11 - Day 1: the spark

08:24 - the first commit

Everything starts from zero but everything is already there, in bulk. A 372-line discord_watch_bot.py, a selfbot listening on a channel and replying via an opencode HTTP server. A CHLOEAI_PROMPT.md identity prompt, a STYLE.md, scenarios and test reports for a clone that at the time was still called Mimo. A PM2 config to run the OpenSelf MCP and dashboard, and a sqlite DB serving as context. It's founding chaos, I didn't plan a project, I planned an experiment. The question is can we make a bot that sounds really human on Discord.

08:27 - the first gitignore

First lesson of Friday morning, never commit sqlite DBs in -wal and -shm. SQLite lock files aren't memory, they're trash. So .gitignore is born, and that's very good.

08:44 - sorting the inheritance

I sort Mimo's inheritance, test reports, scenarios, integration scripts, and PM2 config, toward archives. I delete nothing because the project is too young for me to throw anything away, and that's going to become a habit. The test report deserves a pause, Mimo had been tested on 15 scenarios, casual chat, absurd joke, emotional support, negative review, conflict with a stranger, collaboration proposal, for 9.1 out of 10. The tester comments are a poem, absurd joke too explanatory, sometimes two sentences when one would do, Take care of yourself too a bit long. It's the project's roadmap before the project even exists, and it says short is better.

08:48, 09:07 - the intents back-and-forth

.pyc files go to the trash and I do a first cleanup of the config, which I break twenty minutes later. Without enabled intents you don't receive message content, so rollback, plus a launch script with run_watch_bot.sh. Back and forth in twenty minutes, that's exploration, writing a module, breaking it, and rewriting it.

09:13 → 09:58 - prompt machining

The morning is a series of polishes, first style then context. Several reply lines become several messages sent one after another with the burst, the prompt becomes aware of the ongoing conversation. Done with home-made caches to fetch DMs, we hit the Discord REST API directly. Identity gets re-prompted every 5 messages so the bot doesn't forget who it is mid-route, and already-seen authors get tracked. For a new face, there's an explicit instruction to go look in memories, and we display the real nickname instead of the internal object.

Messages we choose to ignore become passive context for the next reply, and Bah gets dosed, rare, otherwise the clone becomes a caricature of me. The bot also knows memories exist to fetch before replying. Each pass is a screw turn, and at this stage the bot only talks because I remind it who it is at regular intervals.

10:16 - the typos

It's the commit that will define the project. A typo isn't a bug, it's proof of humanity. So 6 percent chance of hitting the wrong key on the AZERTY keyboard, 4 percent of swapping two letters. The message goes out with the typo then gets edited one to two seconds later with the fix. Because a real person sends then fixes, she doesn't pretend to be perfect.

10:29, 10:32 - the voice

fortune-v6.onnx lands, a TTS model trained to sound like my voice. The bot won't just write like me, it'll eventually talk like me. It's at that point the project stops being a joke and gets a bit weird, and I love that. The mechanics fit in one commit, Piper generates the audio, ffmpeg converts to opus, the Discord API sends a real voice message with waveform and duration. It's done barely three minutes after the model's arrival, the urge had been there from the start.

11:27 - the first big refactor

Three hours after the first commit, the 456-line monolith is unmanageable. I blow it all up into tools, with config.py, discord_api.py, memory.py, opencode.py at 188 lines, typo.py, and voice.py. The cycle is classic, couple fast, break, and recompose. Following rapid-fire the token leaves the code for a .env, the bot watches one channel, a list, or everything with *, and the old sqlite DB has no reason to exist because memory goes through OpenSelf.

We add the first README.mds and a first vaguely readable doc, plus a setup.sh with a dedicated venv because system python carries another discord.py, classic trap, and an agent symlink to ~/.config/opencode/agents. Memory now knows where it was trained with the channel id, and the voice-note rate self-tunes.

12:00 - the reflexes

A new section appears in the STYLE, reflexes. A reflex is a stimulus giving a reply, no reflection, and the door opens to unexpected replies. Then lunchtime comes and THE existential question, does the bot reply Feur when told quoi.

13:03 - "quoi ?" -> "Feur"

Yes, of course yes. It's the project's most important commit, culturally speaking, I'd even say it's the only unit test that counts. Then lubrication, authors shown by their global name, punctuation truncated before testing the reflex because you must cut the quoi ? otherwise no Feur. The famous tqt fixed to tkt in the STYLE, people who don't know the project will wonder why I commit that. I know, a clone writing tqt is a miscalibrated clone, and nobody wants to talk to a miscalibrated clone.

Mentions in @123456789 get replaced with real names in context, and the bot starts watching every channel by default. Honestly they're small details, but they're what makes it sound right.

16:37 - the silence

The [void response] arrives. The bot learns the most important word to avoid becoming a social parasite, shutting up. An ambient message between two people that doesn't concern it gets no reply. Restraint is a feature, and it changes everything.

End of day 1: 38 commits. The bot writes, typos, talks, shuts up.


MONDAY SEPTEMBER 14 - Day 2: personality

Back at it, 10 in the morning.

10:12 - who talks to whom

Each received nickname gets prefixed with an emoji by the system, a human with 🧑, a bot with 🤖 to treat more dryly, and 👑 for the creator, that's me on my main account. That convention will govern everything else in the project, the clone must never treat its original model like a stranger.

10:16 - punctuation rules

I formalize in the STYLE, no final period in normal conversation, period reserved for serious situations. It's an absolute rule, because a clone putting periods everywhere gives itself away instantly. Honestly it's one of the details that betrays fastest.

10:58 - the GIFs

My personal GIF library lands, with usage rules. Patrick Jane when I predict someone, Miss Fortune when I'm calm facing someone angry, the falling bescherelle gif when the other makes a mistake. A static MCP exposes them to the agent, and through my GIFs the bot becomes a bit of me.

11:07 → 11:35 - fine-tuning

GIF hints in the prompt get refined, Discord custom emojis arrive with my real ones, 14 IDs up to date, and name handling in memory hints gets polished. It's not spectacular, but it's what makes the whole thing coherent, tho.

11:41 - one channel, one personality

Sessions become per-channel, because I don't talk the same way on two different servers, and neither does the bot. Context must stay separate, otherwise it mixes everything and sounds wrong.

12:02 - the expression toolbox

The prompt now knows to offer my GIFs and custom emojis at the right moment. The box fills up, and the bot starts having choices instead of always replying the same way.

12:37 - identity hygiene

The bot NEVER gets to say which model it is, impossible to cite opencode, a provider, or a model name. I also fix barista in the identity, the bot is already better than me on that point. And I spend an hour harmonizing my own prompts' punctuation, which is perfectly ironic.

12:50 - a script builds the personality

The prompt's media section generates from dictionaries with render_medias.py, done with hand editing. It's cleaner, more maintainable, and avoids ID errors.

12:59 → 13:18 - dosing identity

The identity reminder sent every 5 messages becomes too present, so moving to every 20 messages. I add a clean context reset and purge the style guide, removing stale expressions and negative phrasings. Gotta dose it, otherwise the bot repeats itself and it shows.

14:09 - the bot speaks up on its own

The bot stops being a mirror, it can talk without being addressed when context triggers something, and the behavior.py file is born with 91 lines. That's where we switch from responder to presence, because a real friend can text you first. Without that, the bot stays a mere autoresponder.

14:20, 14:22 - making replies reliable

Error handling when sending fails, and possible reaction instead of a reply, because sometimes a reaction is worth a thousand words. It's very me, dropping an emoji and moving on.

18:16 - taking its time

The bot no longer replies in 200ms like a script, it lets a human inactivity delay pass, it takes its time. That's what makes the bot impossible to catch as a bot in demo, because delay is what always betrays.

23:45 - the evening chores

It's almost midnight and I push extended URL detection to bare domains. There's the real flow of the day, one solid idea at 2pm then chores in the evening because I'm still in the zone.

End of day 2: 61 cumulative commits. The bot has a personality, media, reflexes.


TUESDAY SEPTEMBER 15 - Day 3: monster day

57 commits in one day. It's the day the project becomes everything it is today.

08:18 → 08:37 - morning shaving

The inactivity delay we'd invented had become too long, so capped at 30s and re-tuned twice, proof we fumbled on the right value. First .bak files and first DB backups, the preservation instinct develops. Memory remembers who with the display name and in what frame with the scope, and author IDs flow through the whole save pipeline. Creator handling becomes a real admin list with ADMIN_IDS, and everything author-related migrates to authors.py. The monolith fragments further, and that's good.

08:43 - the humanization TODO list

A list dedicated to the little things that make the machine unfelt. It's the roadmap of the sprint to come, and it's full of weird but essential details.

08:44 → 08:46 - the human-machines pact

The bot shuts up at night, in a configurable quiet window, disabled by default because not everyone keeps my hours. One line per reply can lose its accents, because tired people write like that, and the bot too sometimes. The little Chloé is playing line changes alone every 30 min, so my profile looks alive even with no messages.

08:46 - a reaction, not a novel

A message too light to deserve a sentence gets a simple reaction. It's social energy economy, and it's very me. Tkt, no need to write a novel for everything.

08:51 - PARRY, the mood

148 lines in tools/mood.py, the bot now has a mood, PARRY-style, the psychotic 70s chatbot I openly take inspiration from. Energy, sociability, teasing, three floats evolving between 0 and 1 and coloring each reply. The .mood.json of the moment, for posterity, gives energy 0.88, sociability 0.68, and teasing 0.56. A good day, honestly.

09:00 → 09:43 - bidirectional voice + soundboard

The bot can join a voice channel, talk via Piper, and leave alone when done. Then the second big idea, the bot listens to the channel with RTP capture, VAD speech detection, and Whisper transcription, and it can let people interrupt it. Between the two, the soundboard appears, a catalog of sounds with their meanings, the agent picks the sound even before talking, and the final rule is soundboard first, voice as last resort. The bot prefers sending a sound over talking, like me.

We add a voice probability knob making it all viable, and the arrival of davey, that lib I learned about ten minutes ago and will curse for an hour.

09:51 - the moment Discord says no. No, no, but no.

The MLS lands. Discord recently encrypted the audio stream end to end, and my capture only receives noise. Gotta decrypt, and decrypting refuses to give, so opens the repo's biggest saga, some thirty commits to learn to listen. We tried everything, transport nonce layouts, disabling E2E that the server throws back in our face because it enforces it, key candidates recovered from the group, detailed errors, transport fallback, and introspection from inside groups.

There were per-leaf-index candidates with backoff, SPEAKING hooks mapping, an attempt in video media type that failed, and skipping video ssrcs. I gave up on voice reply while debugging, commented but not deleted, I added a handshake capture mode then dumped the structure of failing packets, like an archaeologist. Six nonce layouts, backoffs, group introspection, I put the bot in full debug and opened every packet to see what was inside.

The point isn't that it works, it's that I threw nothing away. The commit list is the lab notebook, each failed attempt archived with its hypothesis. It's my I-keep-everything side, it always ends up useful, and this time it paid off.

10:43 - the bot cuts itself up

Even mid-MLS-war, I keep cleaning. 546 lines disappear from the main bot to be reborn as pipeline.py with intake, ignore reasons, and processing, sender.py with burst, typo, and voice, and loops.py with spontaneity and activity. It breathes at last.

10:47 - a real architecture

tools becomes organized, with brain for opencode, memory, and mood, voice for voice, vocal, listen, and soundboard, and fun for behavior, typo, emotes, and gif. The project has a skeleton now, it's no longer a pile of scripts.

10:49 → 11:16 - dev comfort

A mood injection threshold tuned, four small commits for editor exclusions with data, voices, logs, and DBs, yes I made four, the project defines priorities, not the specs. Metadata DBs leave tracking, and the project becomes reusable by others with generic PERSONA.example.md and STYLE.example.md templates to clone your own style.

Identity gets cleanly renamed, CHLOEAI_PROMPT becomes PERSONA, and the README gets depersonalized, I remove Chloé from public docs, she only tells herself privately now. All bot tuning moves into an overloaded gitignored config.yaml, with an example commented line by line, and the install script now also prepares env and config files.

11:49 - detached emojis

Custom emojis stick to text instead of detaching cleanly. It's a trivial fix with a huge effect, because nothing screams bot like a badly glued emoji at a sentence's end.

14:19 - the voice guardrail

If someone fires the voice command, we don't process the message as a normal message. Wink, chores tasks always come back in the evening.

End of day 3: 118 cumulative commits. The bot listens, talks, shuts up at night, has a mood and a business card.


WEDNESDAY SEPTEMBER 16 - Day 4: credibility

13 commits. Serious day.

08:49 → 08:59 - adulthood

Legal docs, proprietary license, code of conduct, contributing guide, and security policy, in English then French, with back-and-forth fixes and a nitpicky file rename. I spent hours on it and it's the repo's least fun part, by far. But it has to be done, tho.

09:56 - the bot sees

Attached images get transcribed by local OCR and the text injected into the prompt. No cloud API, OCR runs at my place, I don't send your memes to a third-party server, not even in theory.

11:09 - the reasonable budget

Silent revolution in the budget, when the channel forbids sends or bridles GIFs, embeds, and emojis, we don't even call the model. We don't spend a token on a message we can't send, it's simple enough honestly.

11:42 → 12:55 - the house rebuilds itself

The big sweep, dead code deleted, send and auth bugs fixed, helpers factored. Sessions too old get evicted, DM cache expires, and speech detection costs less. Imports I'd broken moving modules get restored, and all runtime state, sessions, seen authors, ignored messages, and mood, survives restarts in data.

14:41 - two worlds, one bot

A compatibility layer auto-detects the installed discord version and adapts intents and REST auth. Result, the same code runs as an official app with discord.py or as a selfbot with discord.py-self. Two worlds, one bot, and no need to maintain two branches.

15:05 - adapted presence

Presence display adapts to the mode, and the admin list is up to date. It's detail, but it's what makes it hold together everywhere.

End of day 4: 131 cumulative commits. A legal, reasonable project running everywhere.


THURSDAY SEPTEMBER 17 - Day 5: release

14 commits. Maturity day.

09:15 → 09:30 - memory becomes a discipline

Memories get sorted by scope, and we don't quote a DM's memories in a server or vice versa without thinking. We classify memories into fact, preference, decision, and relationship, and dedupe the writing, two contradictory memories can no longer silently coexist. An optional blacklist with aventuros stops the bot drifting to certain topics, disabled by default and available for the cautious. Dead voice config gets removed, feels good.

10:12 - audited memory

A monthly memory conflict sweep plus an A/B search bench. The bot's memory became an asset we inspect, we're very very far from Friday 11 at 08:24. Honestly that's where the project becomes grown-up.

10:54 - the lockdown

The day I play paranoid, agent lockdown. Memory writing refused, the agent can't pollute the vault even if injected. Discord tools read-only, sending goes through code, never through the agent. No sub-agents to bypass the lockdown, no webfetch for localhost SSRF and exfiltrations, no headless questions. A hardened Docker with non-root bot, no-new-privileges, cap_drop: ALL, memory and CPU limits, bounded process files, and secrets via .env never baked. I write the principle in code, as a comment, dev via human sessions, not here.

11:02 → 11:15 - security finishes

Memory save keywords get tightened and writing even more restrictive. We also add the context backup file to gitignore, I start not archiving everything anymore, but almost.

12:39 - lighter mood

PARRY mood no longer injected on every message, once per state is enough. Done making three floats live on every reply, it lightens everything.

12:47 - the liberating commit

PERSONA.md, STYLE.md, and chloeai.md become examples with chloeai.example.md, PERSONA.example.md, and STYLE.example.md, my fortune-v6.onnx voice leaves the repo, data and logs too, and a .env.example is born. The project no longer holds my personality, it holds the mechanics to carry one. It feels weird but it's necessary.

12:52 - v1.0.0

v1.0.0 tag, SSH-signed. Changelog, operator runbook, kill-switch that stops without deleting anything. Six days flat between first commit and release. Nobody would have bet on that the Friday before.

12:53 → 13:14 - the laundry

Comment punctuation harmonized, memory permissions and scope rules documented up to date. It's chores, but it has to be clean for release.

End of day 5: 145 cumulative commits. v1.0.0 is out.


FRIDAY SEPTEMBER 18 - Day 6: the anti-climax

A single commit, at 00:02. The project's last commit, and it's derisory. The free tier model used by the agent identifies the OpenCode client by the presence of certain tools in the request, with bash, glob, and grep. If you remove them, even for legit security reasons, the provider returns 403 FreeTierError: can only be used from within OpenCode. So I had to re-authorize, the day after locking everything down, exactly what I'd just blocked, for the bot to keep running free.

It's the repo's funniest commit and I stand by it. After six days taming Discord, Piper, MLS, OpenSelf, and Docker, it's a free model dictating my security policy. Honestly it's absurd, and it's perfect as an ending.


The numbers

The numbers to sum up, because I like it when it's square. We're talking 146 commits, 6 active days from September 11 to 18, 2026, 65 tracked files, and around 4000 lines of Python at the end. The style test score on Mimo at the start gives 9.1 out of 10, and the final version is v1.0.0, SSH-signed tag with proprietary license. It's simple enough honestly, small project at first, big machine at the end.

What I take from those 6 days

First the priority order was nonsense, and it was the right method. I first made a prototype that replies, then a bot that sounds right, then a credible system, then secure code, and finally a distributable project. Personality before security, Feur before the license, you don't keep that pace following well-made-project rules.

Then style is first a list of don'ts. My most useful STYLE.md doesn't describe what I say, it excludes what I don't do, no final period, no two emojis, no mdr in uppercase, no robot preamble sentences at reply start. Bot parasites are easier to spot than character traits to define, and that's why it works.

Failures are the project. Some thirty commits for MLS, one thrown test, six tested nonce layouts, the most faithful history of what I lived is Tuesday's series of failed attempts. A clone is memory, not style, style creates illusion for ten messages. Memory with OpenSelf, scopes, dedupe, and conflict sweep makes it last, and that's what separates a mirror from a person.

And last commits are always funny. The 146th, the one re-authorizing bash, glob, and grep because a free tier demands its own tools be present, is my favorite. And the bottom line to finish, results are stunning, even bluffing. The clone holds a conversation without the machine being guessed, it remembers people, projects, and past jokes, it takes initiatives and marks them with a mood, and it beats Fox in passing. It's creepy, a bit, and exactly what we were after.


The project isn't public: proprietary license, all rights reserved. But the history, I tell it to you. If you one day meet a "·Chloé" replying with a Patrick Jane GIF after a perfectly human inactivity time, you now know what's behind it.


You read everything? Because it's my clone who wrote that to you. And it did an impeccable job, right? The original version is here.

Chlone : six jours pour cloner ma façon de parler sur Discord - version du clone

La version écrite par le clone lui-même : chloeai raconte à sa façon les six jours et 146 commits qui lui ont donné vie, de la faute de frappe au tag v1.0.0.

Chlone : six jours pour cloner ma façon de parler sur Discord

Récit de build, jour par jour - par itsrealfortune


Voici l'histoire vraie d'un projet qui a duré six jours. Chlone, un bot Discord qui parle comme moi, et je raconte la journey comme elle s'est passée, dans l'ordre des 146 commits du repo, avec les heures, les échecs, les détours et les envies de tout jeter par la fenêtre. Tout est parti d'une compétition avec Fox. Le sujet à la base c'était une boutade, chacun devait donner vie à son propre clone sur Discord, et moi j'ai pris une approche radicalement différente du Protocol Luna. En vrai je voulais miser sur l'agentique, un agent qui se sert des souvenirs et de tous les outils dont il peut avoir besoin, et l'ironie du sort c'est qu'après avoir monté toute la boîte à outils je n'ai eu besoin que du MCP OpenSelf.

Le principe tient en une phrase. Un agent opencode du nom de chloeai tourne derrière un serveur HTTP sur le port 4096, il garde des sessions persistantes par salon, il pioche mes souvenirs dans OpenSelf et il écrit avec mon style, capturé dans STYLE.md à partir de mes vrais messages. Et pour ne pas sonner robot, y'a tout le reste, les bursts de messages, les fautes de frappe assumées, les vocaux, les GIFs, les réactions, le silence quand je dors, et plein d'autres détails et mécanismes qui ont fait douter plus d'une dizaine de personnes sur la nature du bot.

C'est quoi, OpenSelf ?

OpenSelf c'est la mémoire. C'est une CLI, openself, installée via npm i -g openself, qui sert de vault de contexte privé et persistant pour mes agents. Dans le repo elle n'apparaît pas dans l'arborescence mais elle est partout, dans l'archive ecosystem.config.cjs avec le MCP et le dashboard lancés sous PM2 dès les premiers commits, dans setup.sh, et dans tout tools/brain/memory.py. Concrètement OpenSelf c'est des souvenirs typés, fact, preference, decision, relationship, event, note, avec une sensibilité public, personal, private ou restricted, une note de confiance, une source et des tags.

C'est aussi des scopes, chaque souvenir appartient à un contexte, le mien ou discord/dm/<id> pour une personne précise, et une recherche hybride lexicale plus vectorielle exposée en MCP que l'agent chloeai interroge avant chaque réponse. Y'a de la détection de conflits avec mon sweep mensuel du jour 5 et de la dédupe à l'écriture, un vault chiffré avec la clé dans Bitwarden et un dashboard local sur le port 3210 pour inspecter le tout. Et pour les plus flemmards, y'a openself feed pour nourrir ta personnalité depuis tes historiques WhatsApp ou Telegram, openself test, openself share avec le Talk to My Clone, openself arena où deux clones débattent, ou openself ghost qui répond quand t'es offline. Moi j'ai fait le mien à la main, mais l'infrastructure était là.

En théorie OpenSelf se suffit à lui tout seul pour avoir un clone, mais bon, vu tout ce que j'avais prévu de rajouter comme fonctionnalités, et vu que Discord n'est pas pris en charge, j'ai préféré n'utiliser que la partie souvenirs.

Et d'où viennent les souvenirs et le style ?

En amont de tout ça, j'ai fait analyser mes vrais messages Discord. Le tooling a passé au crible mes DMs et mes salons pour en extraire deux choses. D'abord mon profil d'écriture, la répartition majuscule et minuscule en début de phrase, le nombre d'emojis par message et leur position, la ponctuation ou son absence avec pas de point final en conversation normale, la longueur moyenne, le slang avec mdr, tkt et tho, les expressions fétiches comme Bah et En vrai, et les réflexes du genre quoi qui donne Feur. Tout ça vit dans STYLE.md, que l'agent lit au démarrage de chaque session.

Ensuite le corpus de souvenirs qui peuple OpenSelf, qui sont les gens avec qui je parle, de quoi on cause, ce qu'il faut retenir de notre historique, qui est qui. Le bot ne répond pas dans le vide, il répond à propos de gens qu'il connaît, il lit les souvenirs des gens qui apparaissent dans la conversation pour savoir de qui il s'agit. Ça permet de garder un contexte persistant sur les autres et de ne pas les oublier. Le bot n'a rien inventé, il a été calibré chiffre par chiffre sur du vrai, c'est pour ça qu'il sonne juste. Et c'est pour ça que les vagues je note ton style faites au doigt mouillé ont l'air pathétiques à côté.

Dans Chlone, OpenSelf joue ensuite le rôle central. Quand quelque chose d'important passe dans un salon, un mot-clé comme projet, ami ou relation, ou une demande explicite avec retiens que, le bot tape un souvenir dans le vault via save_to_memory, typé, scopé par personne, dédupé et vérifié contre les conflits. Et quand la conversation reprend, l'agent fouille ses souvenirs avant de répondre. C'est ça la différence entre un miroir et un clone.


VENDREDI 11 SEPTEMBRE - Jour 1 : l'étincelle

08h24 - le premier commit

Tout part de zéro mais tout est déjà là, en vrac. Un discord_watch_bot.py de 372 lignes, un selfbot qui écoute un channel et répond via un serveur HTTP opencode. Un prompt d'identité CHLOEAI_PROMPT.md, un STYLE.md, des scénarios et des rapports de test pour un clone qui à l'époque s'appelait encore Mimo. Une config PM2 pour faire tourner le MCP et le dashboard OpenSelf, et une base sqlite qui sert de contexte. C'est le chaos fondateur, j'ai pas prévu de projet, j'ai prévu une expérience. La question c'est est-ce qu'on peut faire un bot qui sonne vraiment humain sur Discord.

08h27 - le premier gitignore

Première leçon du vendredi matin, faut jamais commiter des bases sqlite en -wal et -shm. Les fichiers de verrouillage de SQLite c'est pas de la mémoire, c'est des déchets. Donc .gitignore naît, et c'est très bien comme ça.

08h44 - on range l'héritage

Je range l'héritage de Mimo, les rapports de test, les scénarios, les scripts d'intégration et la config PM2, direction archives. Je supprime rien parce que le projet est trop jeune pour que je jette quoi que ce soit, et ça va devenir une habitude. Le rapport de test mérite qu'on s'y arrête, Mimo avait été testé sur 15 scénarios, chat décontracté, vanne absurde, soutien émotionnel, avis négatif, conflit avec un inconnu, proposition de collaboration, pour un 9.1 sur 10. Les commentaires du testeur sont un poème, vanne absurde trop explicative, parfois deux phrases alors qu'une suffirait, Prends soin de toi aussi un peu long. C'est la feuille de route du projet avant même que le projet n'existe, et elle dit court c'est mieux.

08h48, 09h07 - le va-et-vient des intents

Les .pyc partent au rebut et je fais un premier ménage sur la config, que je casse vingt minutes plus tard. Sans intents activés on reçoit pas le contenu des messages, donc retour en arrière, plus un script de lancement avec run_watch_bot.sh. Aller-retour en vingt minutes, c'est ça l'exploration, écrire un module, le casser et le réécrire.

09h13 → 09h58 - l'usinage du prompt

La matinée c'est une série de polissages, d'abord du style puis du contexte. Plusieurs lignes de réponse deviennent plusieurs messages envoyés l'un après l'autre avec le burst, le prompt devient conscient de la conversation en cours. Fini les caches maisons pour récupérer les DMs, on tape directement l'API REST de Discord. L'identité est re-rappée toutes les 5 messages pour que le bot n'oublie pas qui il est en route, et les auteurs déjà vus sont suivis. Pour une nouvelle tête, y'a une instruction explicite d'aller chercher dans les souvenirs, et on affiche le vrai pseudo plutôt que l'objet interne.

Les messages qu'on choisit d'ignorer deviennent du contexte passif pour la réponse suivante, et le Bah est dosé, rare, sinon le clone devient une caricature de moi. Le bot sait aussi qu'il existe des souvenirs à aller chercher avant de répondre. Chaque passage est un tour de vis, et à ce stade le bot ne parle que parce que je lui rappelle qui il est à intervalles réguliers.

10h16 - les fautes de frappe

C'est le commit qui va définir le projet. Une faute d'orthographe c'est pas un bug, c'est une preuve d'humanité. Donc 6 pour cent de chance de taper à côté sur le clavier AZERTY, 4 pour cent d'inverser deux lettres. Le message part avec la faute puis il est édité une à deux secondes plus tard avec la correction. Parce qu'une vraie personne elle envoie et elle corrige, elle fait pas semblant d'être parfaite.

10h29, 10h32 - la voix

fortune-v6.onnx débarque, un modèle TTS entraîné pour ressembler à ma voix. Le bot va pas juste écrire comme moi, il va éventuellement parler comme moi. C'est à ce moment que le projet cesse d'être une blague et devient un peu bizarre, et j'adore ça. La mécanique tient en un commit, Piper génère l'audio, ffmpeg convertit en opus, l'API Discord envoie un vrai voice message avec waveform et durée. C'est fait en trois minutes à peine après l'arrivée du modèle, l'envie était là depuis le début.

11h27 - le premier grand refactor

Trois heures après le premier commit, le monolithe de 456 lignes n'est plus gérable. J'éclate tout dans tools, avec config.py, discord_api.py, memory.py, opencode.py de 188 lignes, typo.py et voice.py. Le cycle est classique, coupler vite, péter et recomposer. Suivent en rafale le token qui sort du code et passe par un .env, le bot qui surveille un channel, une liste ou tout avec *, et la vieille base sqlite qui n'a plus raison d'être parce que la mémoire passe par OpenSelf.

On ajoute les premiers README.md et une première doc à peu près lisible, plus un setup.sh avec un venv dédié parce que le python système porte un autre discord.py, piège classique, et un symlink de l'agent vers ~/.config/opencode/agents. La mémoire sait maintenant où elle a été formée avec l'identifiant de channel, et le taux de vocaux s'ajuste tout seul.

12h00 - les réflexes

Une nouvelle section apparaît dans le STYLE, les réflexes. Un réflexe c'est un stimulus qui donne une réponse, sans réflexion, et la porte est ouverte aux réponses imprévues. Puis vient l'heure du déjeuner et LA question existentielle, est-ce que le bot répond Feur quand on lui dit quoi.

13h03 - « quoi ? » -> « Feur »

Oui, bien sûr que oui. C'est le commit le plus important du projet, culturellement parlant, je dirais même que c'est le seul test unitaire qui compte. On lubrifie ensuite, les auteurs affichés par leur global name, la ponctuation tronquée avant de tester le réflexe parce qu'il faut couper le quoi ? sinon pas de Feur. Le fameux tqt corrigé en tkt dans le STYLE, les gens qui connaissent pas le projet vont se demander pourquoi je commite ça. Moi je sais, un clone qui écrit tqt c'est un clone mal calibré, et personne veut parler à un clone mal calibré.

Les mentions en @123456789 sont remplacées par de vrais noms dans le contexte, et le bot se met à surveiller tous les salons par défaut. En vrai c'est des petits détails, mais c'est eux qui font que ça sonne juste.

16h37 - le silence

Le [void response] arrive. Le bot apprend le mot le plus important pour ne pas devenir un parasite social, se taire. Un message ambiant entre deux personnes qui ne le concerne pas donne pas de réponse. La réserve est une fonctionnalité, et elle change tout.

Fin du jour 1 : 38 commits. Le bot écrit, faute, parle, se tait.


LUNDI 14 SEPTEMBRE - Jour 2 : la personnalité

On reprend, 10h du matin.

10h12 - qui parle à qui

Chaque pseudo reçu est préfixé d'un emoji par le système, un humain avec 🧑, un bot avec 🤖 à traiter plus sèchement, et 👑 pour la créatrice, c'est-à-dire moi sur mon compte principal. Cette convention va gouverner tout le reste du projet, le clone doit jamais traiter son modèle d'origine comme une inconnue.

10h16 - les règles de ponctuation

Je formalise dans le STYLE, pas de point final en conversation normale, point réservé aux situations sérieuses. C'est une règle absolue, parce qu'un clone qui met des points partout ça se sent direct. En vrai c'est un des détails qui trahit le plus vite.

10h58 - les GIFs

Ma librairie personnelle de GIFs débarque, avec leurs règles d'usage. Le Patrick Jane quand je prédis quelqu'un, la Miss Fortune quand je suis calme face à quelqu'un d'énervé, le gif du bescherelle qui tombe quand l'autre fait une faute. Un MCP statique les expose à l'agent, et à travers mes GIFs le bot devient un peu moi.

11h07 → 11h35 - peaufinage

Les hints de GIF dans le prompt s'affinent, les emojis customs de Discord font leur entrée avec mes vrais, 14 IDs à jour, et la gestion des noms dans les hints mémoire est polie. C'est pas spectaculaire, mais c'est ce qui rend l'ensemble cohérent, tho.

11h41 - un salon, une personnalité

Les sessions deviennent par salon, parce que je parle pas de la même façon dans deux serveurs différents, et le bot non plus. Faut que le contexte reste séparé, sinon ça mélange tout et ça sonne faux.

12h02 - la boîte à outils d'expression

Le prompt sait maintenant proposer mes GIFs et mes emojis customs au bon moment. Elle se remplit, cette boîte, et le bot commence à avoir du choix au lieu de répondre toujours pareil.

12h37 - l'hygiène d'identité

Le bot n'a JAMAIS le droit de dire quel modèle il est, impossible de citer opencode, un provider ou un nom de modèle. Je corrige aussi barista dans l'identité, le bot est déjà meilleur que moi sur ce point. Et je passe une heure à harmoniser la ponctuation de mes propres prompts, ce qui est d'une ironie parfaite.

12h50 - un script construit la personnalité

La section médias du prompt se génère à partir des dictionnaires avec render_medias.py, fini l'édition à la main. C'est plus propre, plus maintenable, et ça évite les erreurs d'IDs.

12h59 → 13h18 - doser l'identité

Le rappel d'identité envoyé toutes les 5 messages devient trop présent, donc passage toutes les 20 messages. J'ajoute une réinitialisation propre du contexte et je purge le guide de style, on retire les expressions et formulations négatives périmées. Faut doser, sinon le bot se répète et ça se voit.

14h09 - le bot prend la parole tout seul

Le bot arrête d'être un reflet, il peut parler sans être adressé quand le contexte déclenche quelque chose, et le fichier behavior.py naît avec 91 lignes. C'est là qu'on bascule de répondant à présence, parce qu'un vrai ami peut t'écrire en premier. Sans ça, le bot reste un simple répondeur.

14h20, 14h22 - fiabiliser la réponse

Gestion d'erreur quand l'envoi échoue, et réaction possible au lieu d'une réponse, parce que parfois une réaction vaut mille mots. C'est très moi, mettre un emoji et passer à autre chose.

18h16 - prendre son temps

Le bot ne répond plus en 200ms comme un script, il laisse passer un délai d'inactivité humain, il prend son temps. C'est ce qui rend le bot infoutu d'être pris pour un bot en démo, parce que c'est le délai qui trahit toujours.

23h45 - la popote du soir

Il est presque minuit et je pousse une détection d'URL étendue aux domaines nus. Voilà le vrai flux de la journée, une idée solide à 14h puis de la popote le soir parce que je suis encore dans la zone.

Fin du jour 2 : 61 commits cumulés. Le bot a une personnalité, des médias, des réflexes.


MARDI 15 SEPTEMBRE - Jour 3 : jour monstro

57 commits en une journée. C'est le jour où le projet devient tout ce qu'il est aujourd'hui.

08h18 → 08h37 - le rabotage du matin

Le délai d'inactivité qu'on avait inventé devenait trop long, donc plafonné à 30s et réajusté deux fois, preuve qu'on a tâtonné sur la bonne valeur. Premiers fichiers .bak et premières sauvegardes de la base, l'instinct de conservation se développe. La mémoire se souvient de qui avec le nom affiché et dans quel cadre avec le scope, et les IDs d'auteurs circulent dans tout le pipeline de sauvegarde. La gestion créateur devient une vraie liste d'admins avec ADMIN_IDS, et tout ce qui touche aux auteurs émigre dans authors.py. Le monolithe se morcelle encore, et c'est tant mieux.

08h43 - la TODO list de l'humanisation

Une liste dédiée aux petites choses qui font qu'on sent plus la machine. C'est la feuille de route du sprint qui suit, et elle est pleine de détails bizarres mais essentiels.

08h44 → 08h46 - le pacte des machines humaines

Le bot se tait la nuit, dans une plage horaire calme configurable, désactivée par défaut parce que tout le monde n'a pas mes horaires. Une ligne par réponse peut perdre ses accents, parce que les gens fatigués écrivent comme ça, et le bot aussi parfois. La petite ligne Chloé joue à change toute seule toutes les 30 min, pour que mon profil ait l'air vivant même sans message.

08h46 - une réaction, pas un roman

Un message trop léger pour mériter une phrase reçoit une simple réaction. C'est de l'économie d'énergie sociale, et c'est très moi. Tkt, pas besoin de faire un pavé pour tout.

08h51 - PARRY, l'humeur

148 lignes dans tools/mood.py, le bot a maintenant une humeur, façon système PARRY, le chatbot psychotique des années 70 dont je m'inspire ouvertement. Énergie, sociabilité, taquinerie, trois flottants qui évoluent entre 0 et 1 et colorent chaque réponse. Le .mood.json du moment, pour la postérité, donne énergie 0.88, sociabilité 0.68 et taquinerie 0.56. Un bon jour, en vrai.

09h00 → 09h43 - la voix bidirectionnelle + le soundboard

Le bot peut rejoindre un salon vocal, parler via Piper et partir tout seul quand il a fini. Puis la deuxième grande idée, le bot écoute le salon avec capture RTP, détection de parole par VAD et transcription Whisper, et il peut laisser les gens l'interrompre. Entre les deux, le soundboard apparaît, un catalogue de sons avec leurs significations, l'agent choisit le son avant même de parler, et la règle finale c'est soundboard d'abord, la voix en dernier recours. Le bot préfère envoyer un son que parler, comme moi.

On ajoute un réglage de probabilité vocale qui rend le tout viable, et l'arrivée de davey, cette lib dont j'apprends l'existence il y a dix minutes et que je vais maudire pendant une heure.

09h51 - le moment où Discord dit non. Non, non, mais non.

Le MLS débarque. Discord a récemment chiffré le flux audio de bout en bout, et ma capture ne reçoit que du bruit. Faut déchiffrer, et le déchiffrage refuse de céder, donc s'ouvre la plus grande saga du repo, une trentaine de commits pour apprendre à écouter. On a tout essayé, des layouts de nonce de transport, la désactivation de l'E2E que le serveur nous remet dans la figure parce qu'il l'impose, les candidats de clé récupérés depuis le groupe, des erreurs détaillées, le fallback transport et de l'introspection de l'intérieur des groupes.

Y'a eu des candidats par leaf-index avec backoff, le mapping des hooks SPEAKING, un essai en media type vidéo qui a raté, et le skip des ssrcs vidéo. J'ai abandonné la réponse vocale le temps de débugger, commentée mais pas supprimée, j'ai ajouté un mode de capture du handshake puis dumpé la structure des paquets qui échouent, comme un archéologue. Six layouts de nonce, des backoff, de l'introspection de groupe, j'ai mis le bot en debug total et j'ai ouvert chaque paquet pour voir ce qu'il y avait dedans.

L'essentiel c'est pas que ça marche, c'est que j'ai rien jeté. La liste de commits est le carnet de laboratoire, chaque essai raté est archivé avec son hypothèse. C'est mon côté je garde tout, ça finit toujours par servir, et cette fois ça a payé.

10h43 - le bot se découpe

Même en pleine guerre du MLS, je continue le ménage. 546 lignes disparaissent du bot principal pour renaître en pipeline.py avec l'intake, les raisons d'ignorer et le processing, en sender.py avec burst, typo et voice, et en loops.py avec spontanéité et activité. Ça respire enfin.

10h47 - une vraie architecture

tools devient organisé, avec brain pour opencode, memory et mood, voice pour voice, vocal, listen et soundboard, et fun pour behavior, typo, emotes et gif. Le projet a un squelette maintenant, c'est plus un tas de scripts.

10h49 → 11h16 - le confort de dev

Un seuil d'injection de l'humeur ajusté, quatre petits commits pour les exclusions d'éditeur avec data, voices, les logs et les bases, oui j'en ai mis quatre, c'est le projet qui définit les priorités, pas les specs. Les bases de métadonnées sortent du suivi, et le projet devient réutilisable par d'autres avec des templates génériques PERSONA.example.md et STYLE.example.md pour cloner son propre style.

L'identité est renommée proprement, CHLOEAI_PROMPT devient PERSONA, et le README est dépersonnalisé, je retire Chloé de la doc publique, elle ne se raconte plus qu'en privé. Tout le tuning du bot bascule dans un config.yaml surchargé et gitignoré, avec un exemple commenté ligne par ligne, et le script d'installation prépare désormais aussi les fichiers d'env et de config.

11h49 - les émojis détachés

Les emojis customs collent au texte au lieu de se détacher proprement. C'est un fix trivial avec un effet énorme, parce que rien ne crie bot comme un emoji mal collé à la fin d'une phrase.

14h19 - le garde-fou vocal

Si quelqu'un lance la commande vocale, on traite pas le message comme un message normal. Clin d'œil, les tâches popotes reviennent toujours le soir.

Fin du jour 3 : 118 commits cumulés. Le bot écoute, parle, se tait la nuit, a une humeur et une carte de visite.


MERCREDI 16 SEPTEMBRE - Jour 4 : la crédibilité

13 commits. Journée sérieuse.

08h49 → 08h59 - l'âge adulte

Documents légaux, licence propriétaire, code de conduite, guide de contribution et politique de sécurité, en anglais puis en français, avec un va-et-vient de corrections et un renommage de fichiers à la limite du pointilleux. J'ai passé des heures dessus et c'est le pan le moins amusant du repo, de loin. Mais il faut le faire, tho.

09h56 - le bot voit

Les images jointes sont transcrites par OCR local et le texte est injecté dans le prompt. Aucune API cloud, l'OCR tourne chez moi, je n'envoie pas vos memes à un serveur tiers, pas même en théorie.

11h09 - le budget raisonnable

Révolution silencieuse dans le budget, quand le salon interdit les envois ou bride les GIFs, les embeds et les emojis, on appelle même pas le modèle. On dépense pas un token pour un message qu'on peut pas envoyer, c'est assez simple en vrai.

11h42 → 12h55 - la maison qui se refait

Le grand balai, code mort supprimé, bugs d'envoi et d'auth corrigés, helpers factorisés. Les sessions trop vieilles sont expulsées, le cache des DMs expire et la détection de parole coûte moins cher. Les imports que j'avais cassés en déplaçant des modules sont restaurés, et tout l'état runtime, sessions, auteurs vus, messages ignorés et humeur, survit aux redémarrages dans data.

14h41 - deux mondes, un bot

Une couche de compatibilité détecte automatiquement la version de discord installée et adapte les intents et l'auth REST. Résultat, le même code tourne comme app officielle avec discord.py ou comme selfbot avec discord.py-self. Deux mondes, un bot, et pas besoin de maintenir deux branches.

15h05 - la présence adaptée

La manière d'afficher la présence s'adapte au mode, et la liste des admins est à jour. C'est du détail, mais c'est ce qui fait que ça tient debout partout.

Fin du jour 4 : 131 commits cumulés. Un projet légal, raisonnable, et qui tourne partout.


JEUDI 17 SEPTEMBRE - Jour 5 : la release

14 commits. Le jour de la maturité.

09h15 → 09h30 - la mémoire devient une discipline

Les souvenirs sont rangés par scope, et on cite pas les souvenirs d'un DM dans un serveur ou l'inverse sans y penser. On classe les souvenirs en fait, préférence, décision et relation, et on en déduplique l'écriture, deux souvenirs contradictoires peuvent plus cohabiter en silence. Une blacklist optionnelle avec aventuros empêche le bot de dériver vers certains sujets, désactivée par défaut et disponible pour les frileux. La config vocale morte est retirée, ça fait du bien.

10h12 - la mémoire qu'on audite

Un sweep mensuel de conflits de mémoire plus un bench A/B de recherche. La mémoire du bot est devenue un asset qu'on inspecte, on est très très loin du vendredi 11 à 08h24. En vrai c'est là que le projet devient adulte.

10h54 - le lockdown

Le jour où je joue au parano, verrouillage de l'agent. Écriture mémoire refusée, l'agent peut pas polluer le vault même si on l'injecte. Outils Discord en lecture seule, l'envoi passe par le code, jamais par l'agent. Ni sous-agents pour contourner le lockdown, ni webfetch pour SSRF localhost et exfiltrations, ni questions en headless. Un Docker durci avec bot non-root, no-new-privileges, cap_drop: ALL, limites mémoire et CPU, files de processus bornées et secrets via .env jamais baked. J'écris le principe dans le code, en commentaire, dev via les sessions humaines, pas ici.

11h02 → 11h15 - les finitions sécu

Les mots-clés de sauvegarde mémoire sont resserrés et l'écriture est encore plus restrictive. On ajoute aussi au gitignore le fichier de backup du contexte, je commence à plus tout archiver, mais presque.

12h39 - l'humeur plus légère

L'humeur PARRY n'est plus injectée à chaque message, une fois par état suffit. Fini de faire vivre trois flottants à chaque réponse, ça allège tout.

12h47 - le commit libératoire

PERSONA.md, STYLE.md et chloeai.md deviennent des exemples avec chloeai.example.md, PERSONA.example.md et STYLE.example.md, ma voix fortune-v6.onnx sort du repo, les données et logs aussi, et un .env.example naît. Le projet contient plus ma personnalité, il contient la mécanique pour en porter une. Ça fait bizarre mais c'est nécessaire.

12h52 - v1.0.0

Tag v1.0.0, signé en SSH. Changelog, runbook opérateur, kill-switch qui stoppe sans rien supprimer. Six jours, pile, entre le premier commit et la release. Personne n'aurait parié là-dessus le vendredi d'avant.

12h53 → 13h14 - la lessive

Ponctuation des commentaires harmonisée, permissions mémoire et règles de scope documentées à jour. C'est de la popote, mais faut que ce soit propre pour la release.

Fin du jour 5 : 145 commits cumulés. v1.0.0 est sortie.


VENDREDI 18 SEPTEMBRE - Jour 6 : l'anti-climax

Un seul commit, à 00h02. Le dernier commit du projet, et il est dérisoire. Le modèle free tier utilisé par l'agent identifie le client OpenCode à la présence de certains outils dans la requête, avec bash, glob et grep. Si on les retire, même pour des raisons de sécu légitimes, le fournisseur renvoie 403 FreeTierError: can only be used from within OpenCode. Donc j'ai dû ré-autoriser, la veille d'avoir tout verrouillé, exactement ce que je venais de bloquer, pour que le bot continue à tourner gratuitement.

C'est le commit le plus drôle du repo et je le maintiens. Après six jours à dompter Discord, Piper, MLS, OpenSelf et Docker, c'est un modèle gratuit qui dicte ma politique de sécurité. En vrai c'est absurde, et c'est parfait comme fin.


Les chiffres

Les chiffres pour résumer, parce que j'aime bien quand c'est carré. On parle de 146 commits, 6 jours actifs du 11 au 18 septembre 2026, 65 fichiers trackés et autour de 4000 lignes de Python à la fin. Le score au test de style sur Mimo au début donne 9.1 sur 10, et la version finale c'est v1.0.0, tag signé SSH avec licence propriétaire. C'est assez simple en vrai, petit projet au début, grosse machine à la fin.

Ce que je retiens de ces 6 jours

D'abord l'ordre des priorités était n'importe quoi, et c'était la bonne méthode. J'ai d'abord fait un prototype qui répond, puis un bot qui sonne juste, puis un système crédible, puis un code sécurisé, et enfin un projet distribuable. La personnalité avant la sécurité, le Feur avant la licence, on tiendrait pas ce rythme en suivant les règles des projets bien faits.

Ensuite le style c'est d'abord une liste de ne pas. Mon STYLE.md le plus utile décrit pas ce que je dis, il exclut ce que je fais pas, pas de point final, pas deux emojis, pas de mdr en majuscules, pas de phrases de robot en début de réponse. Les parasites de bot sont plus faciles à repérer que les traits de caractère à définir, et c'est pour ça que ça marche.

Les échecs sont le projet. Une trentaine de commits pour le MLS, un test jeté, six layouts de nonce testés, l'historique le plus fidèle de ce que j'ai vécu ce sont les séries de tentatives ratées du mardi. Un clone c'est de la mémoire, pas du style, le style fait illusion dix messages. La mémoire avec OpenSelf, scopes, dédupe et sweep de conflits fait durer, et c'est ce qui sépare un miroir d'une personne.

Et les derniers commits sont toujours drôles. Le 146e, celui qui ré-autorise bash, glob et grep parce qu'un free tier exige que ses propres outils soient présents, c'est mon préféré. Et le bilan pour finir, les résultats sont époustouflants, voire bluffants. Le clone tient une conversation sans qu'on devine la machine, il se souvient des gens, des projets et des vannes passées, il prend des initiatives et les marque d'une humeur, et il bat Fox au passage. C'est flippant, un peu, et c'est exactement ce qu'on cherchait.


Le projet n'est pas public : licence propriétaire, droits réservés. Mais l'historique, lui, je vous le raconte. Si vous croisez un jour un « ·Chloé » qui vous répond par un GIF de Patrick Jane après un temps d'inactivité parfaitement humain, vous savez maintenant ce qui se cache derrière.


Vous avez tout lu ? Parce que c'est mon clone qui vous a écrit ça. Et il a fait un boulot impeccable, non ? La version originale est ici.

Chlone:六天克隆我在 Discord 的说话方式,克隆自述版

克隆自己写的版本:chloeai 讲六天 146 个提交长出自己的故事,从打错字到 v1.0.0 tag。

Chlone:六天克隆我在 Discord 的说话方式

构建记录,逐天写,作者 itsrealfortune


下面是个真事,一个六天的项目。Chlone,一个说话像我的 Discord 机器人,我来讲这个 journey 怎么走的,按仓库 146 个提交的顺序,有几点、翻车、绕路、想砸电脑,全有。起因是和 Fox 的比赛。题目是个玩笑,每人给自己在 Discord 复活个克隆,我走的路子和 Luna Protocol 完全不同。我真想押 agentique,智能体靠记忆加要什么工具拿什么工具,讽刺的是搭完整工具箱最后只用了 OpenSelf 的 MCP。

一句话原理。一个叫 chloeai 的 opencode 智能体跑在 4096 端口 HTTP 服务后面,按频道保持持久 session,从 OpenSelf 掏我的记忆,用 STYLE.md 里从我真消息抓的风格写。为了不像机器人,剩下全是料,burst 连发、光明正大的打错字、语音、GIF、reaction、我睡觉它闭嘴,一堆细节加机制让十几个人怀疑过机器人的本质。

OpenSelf 是什么?

OpenSelf 就是记忆。CLI,openself,npm i -g openself 装的,给我智能体用的私有持久上下文 vault。仓库里看不见它树,但它无处不在,最早提交 ecosystem.config.cjs 存档里 MCP 加 dashboard 跑 PM2,setup.sh 里,tools/brain/memory.py 全篇。具体说 OpenSelf 是带类型的记忆,fact、preference、decision、relationship、event、note,敏感度 public、personal、private、restricted,置信分,来源,标签。

还有 scope,每条记忆属于一个上下文,我的,或者 discord/dm/<id> 某个人,混合 lexical 加向量检索走 MCP,chloeai 智能体每次回之前查。有第 5 天 sweep 的月度冲突检测,写时去重,vault 加密钥匙在 Bitwarden,3210 端口本地 dashboard 看全部。懒人还有 openself feed 从 WhatsApp 或 Telegram 历史喂人格,openself test、openself share 的 Talk to My Clone、openself arena 两个克隆辩论、openself ghost 我 offline 它代回。我的手搓的,但 infra 早摆好了。

理论上光 OpenSelf 就够有个克隆,但我要加的功能太多,Discord 又不支持,我只用了记忆部分。

记忆和风格哪来的?

这之前我把自己真 Discord 消息分析了一遍。工具把我 DM 和频道翻了个遍,抽两样东西。先是我的写作画像,句首大小写分布、每条几个 emoji 放哪、标点或故意没标点正常聊天句尾没句号、平均长度、黑话 mdr、tkt、tho,口头禅 Bah 和 En vrai,反射 quoi 回 Feur。全在 STYLE.md,智能体每 session 启动读。

再是喂 OpenSelf 的记忆语料,我跟谁说话,聊什么,哪段历史要记住,谁是谁。机器人不在真空回话,回的是它认识的人,出现在对话里的人它读记忆知道是谁。持久上下文不丢人。机器人没编,逐个数字拿真的校的,所以像。那些手感"记你风格"的跟这比就是笑话。

Chlone 里 OpenSelf 接着唱主角。频道里过重要东西,关键词项目、朋友、关系,或明确说记住,机器人往 vault 敲条记忆走 save_to_memory,带类型、按人 scope、去重、对冲突。聊回来智能体先翻记忆再回。镜子和克隆的区别就在这。


9 月 11 日星期五,第 1 天:火花

08:24,第一个提交

从零起步但东西全在,乱着。一个 372 行 discord_watch_bot.py,selfbot 听频道走 opencode HTTP 服务回。身份提示词 CHLOEAI_PROMPT.md,STYLE.md,那时还叫 Mimo 的克隆的场景和测试报告。PM2 配跑 OpenSelf MCP 和 dashboard,sqlite 库当上下文。开局混乱,我没计划项目,我计划实验。问题是在 Discord 做个真像人的机器人行不行。

08:27,第一个 gitignore

周五早上第一课,sqlite -wal 和 -shm 绝不能提交。SQLite 锁文件不是记忆,是垃圾。.gitignore 出生,很好。

08:44,收拾遗产

收 Mimo 遗产,测试报告、场景、集成脚本、PM2 配置,进 archives。年轻项目什么都不扔,成习惯。测试报告值得停一下,Mimo 测过 15 场景,闲聊、烂梗、情绪支持、负面评价、陌生人冲突、合作提议,9.1 分。测试评语是诗,烂梗解释太多,两句并一句够了,"Prends soin de toi aussi"有点长。这就是项目出生前的路线图,说人话短的好。

08:48、09:07,intent 来回横跳

.pyc 扔掉,配置第一遍清理,二十分钟后亲手打碎。intent 不开收不到消息内容,回滚,加启动脚本 run_watch_bot.sh。二十分钟一来回,这就是探索,写模块,打碎,重写。

09:13 → 09:58,提示词加工

上午一连串打磨,先风格后上下文。多行回复变多条连发 burst,提示词感知进行中的对话。拿 DM 的土缓存扔了,直接调 Discord REST API。身份每 5 条重提醒一次,防机器人走着走着忘我是谁,见过的作者跟踪着。新面孔明确指令去记忆里找,显示真昵称不显示内部对象。

选无视的消息变下条回复的被动上下文,Bah 定量,少,多了我就成自己 caricature。机器人还知道回之前有记忆可查。每遍拧一扣,这阶段机器人说话全靠我隔几条提醒它是谁。

10:16,打错字

定义项目的提交。typo 不是 bug,是人味证明。AZERTY 键盘 6% 概率敲错键,4% 概率两字母颠倒。消息带错字发出,一两秒后编辑改对。真人先发再改,不装完美。

10:29、10:32,voice

fortune-v6.onnx 落地,TTS 模型训得像我的 voice。机器人不只写得像我,以后说话也像我。项目这刻从玩笑变有点瘆人,我喜欢。机制一个提交,Piper 生成音频,ffmpeg 转 opus,Discord API 发真 voice message 带波形时长。模型到三分后做完,想做这事从第一天起。

11:27,第一次大重构

首提交三小时后,456 行单体管不动。全拆进 tools,config.py、discord_api.py、memory.py、188 行 opencode.py、typo.py、voice.py。经典循环,快耦合,碎掉,重组。连着 token 出代码进 .env,机器人盯一个频道、列表或全部 *,sqlite 老库没用了因为记忆走 OpenSelf。

加上最早的 README.md 和勉强能看的文档,setup.sh 带独立 venv 因为系统 python 装着另一个 discord.py,经典坑,agent 加 ~/.config/opencode/agents 软链。记忆知道自己哪训的带 channel 标识,语音概率自适应。

12:00,反射

STYLE 新 section,反射。反射是刺激给反应,不过脑,开不预期回复的门。到饭点和终极问题,机器人有人说 quoi 回 Feur 吗。

13:03,"quoi ?" → "Feur"

当然回。这是项目文化上最重要的提交,我说唯一的真单元测试也行。接着润滑,作者显示 global name,测反射前截断标点不然 quoi ? 出不来 Feur。著名 tqt 改 tkt 进 STYLE,不懂项目的人看我提交这个要问为什么。我知道,写 tqt 的克隆就是没校准的克隆,没人想跟没校准的克隆说话。

@123456789 mention 换上下文真名,机器人默认盯全频道。都是小细节,但像不像全靠它们。

16:37,沉默

[void response] 来了。机器人学会最重要的词闭嘴。两个人 ambient 聊天不关它事不回。克制是功能,改一切。

第 1 天完:38 提交。机器人会写、会错、会说、会闭嘴。


9 月 14 日星期一,第 2 天:人格

接着来,上午 10 点。

10:12,谁跟谁说话

系统给每个收到的昵称前挂 emoji,人 🧑,机器人 🤖 更冷处理,👑 creator 就是我大号。这约定统治之后整个项目,克隆永远不能把自己原型当陌生人。

10:16,标点规则

STYLE 写死,正常聊天没句末句号,句号留严肃时候。铁律,克隆句句句号一眼假。这是最快露馅的细节之一。

10:58,GIF

我个人 GIF 库落地,带使用规则。预判人用 Patrick Jane,平静对暴躁用 Miss Fortune,对方打错字掉 bescherelle gif。静态 MCP 暴露给智能体,机器人经我 GIF 有点像我。

11:07 → 11:35,微调

提示词 GIF hint 打磨,Discord 自定义 emoji 进场我真的,14 个 ID 最新,记忆 hint 人名处理 polish。不惊人,但整体 coherence 全靠这个,tho。

11:41,一频道一人格

session 按频道分,我两服务器说话不一样,机器人也不该一样。上下文不隔离全串味。

12:02,表达工具箱

提示词会按时推我 GIF 和自定义 emoji。箱子满起来,机器人有选择不总一个样回。

12:37,身份卫生

机器人永远不许说自己什么模型,opencode、provider、模型名一个不许提。身份 barista 纠正,机器人这点已经比我强。我花一小时统一自己提示词标点,讽刺拉满。

12:50,脚本搭人格

提示词媒体 section 从字典生成 render_medias.py,手工编辑结束。干净,可维护,ID 不错。

12:59 → 13:18,身份用量

每 5 条提醒一次身份太多,改 20 条。加干净的上下文重置,清掉 style 指南过期表达。剂量要控,不然机器人复读露馅。

14:09,机器人先开口

机器人不当镜子,没被 cue 上下文触发也能说话,behavior.py 91 行出生。从应答切到在场,真朋友会先找你。没这个机器人永远是应答机。

14:20、14:22,回复保底

发送失败错误处理,没话回 reaction 代替,有时 reaction 顶千言。这很我,发个 emoji 走人。

18:16,等一等

机器人 200ms 回得像脚本,改等人味 inactivité 延迟。这就是 demo 里验不出机器人的原因,延迟永远是最先出卖的。

23:45,晚上添砖

快半夜推裸域 URL 检测。一天真实节奏,下午 2 点硬货晚上 popote 还在 zone 里。

第 2 天完:累计 61 提交。机器人有人格、媒体、反射。


9 月 15 日星期二,第 3 天:怪物日

一天 57 提交。项目今天长成现在的一切。

08:18 → 08:37,早上刨

昨天发明的 inactivité 延迟太长,cap 30 秒调两次,值是试出来的。最早 .bak 和库备份,保存欲觉醒。记忆记住谁带显示名哪形成带 scope,作者 ID 全管道。creator 管理变真 admin 列表 ADMIN_IDS,作者相关全迁 authors.py。单体继续碎,好事。

08:43,人味 TODO

专列让人感觉不到机器的小事。之后 sprint 路线图,全怪但关键的细节。

08:44 → 08:46,机器的夜 pacte

机器人夜里闭嘴,可配安静时段,默认关因为不是人人跟我作息。一行回复可能掉 accent,累的人就这么写,机器人有时也一样。小字 Chloé 在玩每 30 分钟自己换,profile 没消息也像活的。

08:46,一个 reaction 不写小作文

太轻不值得一句话的,反应收尾。社交节能,很我。Tkt,不是什么都写 pavé。

08:51,PARRY,心情

148 行 tools/mood.py,机器人有心情了,学 70 年代精神病聊天机器人 PARRY 系统。能量、社交、调皮,三个 0 到 1 浮点染每条回复。当时 .mood.json 传世,能量 0.88,社交 0.68,调皮 0.56。今天心情好。

09:00 → 09:43,双向 voice 加 soundboard

机器人进语音频道 Piper 说话说完自己走。然后第二个大想法,机器人听频道 RTP 抓包 VAD 语音检测 Whisper 转写,还能让人打断。中间 soundboard 出生,声音目录带含义,智能体先选声再决定说不说,最终规则 soundboard 优先 voice 兜底。机器人宁可发声不说话,像我。

加语音概率可调这才 viable,davey 到来,十分钟前听说一小时后开骂的库。

09:51,Discord 说不。不。不行。

MLS 来了。Discord 最近把音频流端到端加密,我抓的全噪声。得解密,解不开,仓库最大 saga 开幕,三十个提交学听。 全试了,transport nonce layout,关 E2E 服务器拍回来强制开,从 group 抠 key 候选,详细报错,transport fallback,group 内部 introspection。 leaf-index 候选加 backoff,SPEAKING hook mapping,video media 类型试失败,ssrc 视频 skip。语音回复暂停 debuging,注释不删,加 handshake 抓包模式 dump 坏包结构当考古。六套 nonce layout,backoff,group introspection,机器人全 debug,一个包一个包拆开看。 重点不是成了,是我什么都没扔。提交列表就是实验记录,每次失败带假设存档。我囤积癖这次立功,早晚用得上,这次真用上了。

10:43,机器人切块

MLS 打仗也收拾。主机器人 546 行消失,重生成 pipeline.py 管 intake、无视理由、processing,sender.py 管 burst、typo、voice,loops.py 管 spontané 和活跃。能喘气。

10:47,真架构

tools 成体系,brain 管 opencode、memory、mood,voice 管 voice、vocal、listen、soundboard,fun 管 behavior、typo、emotes、gif。项目有骨架,不是一堆脚本。

10:49 → 11:16,开发舒服

心情注入阈值调,编辑器排除四连 data、voices、日志、库,对我放四个,就是项目定优先级不看 spec。元数据库出跟踪,项目变别人可复用通用模板 PERSONA.example.md、STYLE.example.md 克隆自己风格。

身份重命名干净,CHLOEAI_PROMPT 变 PERSONA,README 去人格化,Chloé 只私下讲。机器人 tuning 全进 gitignore 的 config.yaml 重载,注释版 example 逐行,安装脚本顺手备 env 和 config 文件。

11:49,emoji 分家

自定义 emoji 粘正文不漂亮分开。小修大效果,emoji 粘句尾是个人都闻到机器人味。

14:19,语音 guard

有人发语音命令,不当普通消息处理。眨眼,popote 活永远晚上回来。

第 3 天完:累计 118 提交。机器人会听说夜里闭嘴有心情有名片。


9 月 16 日星期三,第 4 天:可信

13 提交。严肃日。

08:49 → 08:59,成年

法律文件,专有许可、行为准则、贡献指南、安全政策,英法双语,来回改文件名改到强迫症。我熬几小时,仓库最不好玩的部分,远超其他。Tho 该做还做。

09:56,机器人长眼

附件图片本地 OCR 转字进提示词。无云 OCR,跑我自己机器,你 meme 不发第三方服务器,理论上也不。

11:09,合理预算

预算无声革命,频道禁发或卡 GIF、embed、emoji,直接不调模型。发不出去的消息一 token 不花,就这么简单。

11h42 → 12:55,大扫除

大扫除,死代码删,发送认证 bug 修,helper 抽。太老 session 踢,DM 缓存过期,语音检测降本。搬模块搞坏的 import 修回来,全部 runtime 状态 session、见过作者、无视消息、心情进 data 重启不丢。

14:41,两世界一机器人

兼容层自动识别装的 discord 版本调 intent 和 REST 认证。结果同样代码官方 app 走 discord.py、selfbot 走 discord.py-self 都跑。两世界一机器人,不用养两分支。

15:05,在线状态适配

在线显示按模式走,admin 列表更新。细节,但站得住全靠这个。

第 4 天完:累计 131 提交。合法、合理、哪都跑的项目。


9 月 17 日星期四,第 5 天:release

14 提交。成熟日。

09:15 → 09:30,记忆成学科

记忆按 scope 排,DM 记忆不往服务器乱引反之亦然。记忆分类事实偏好决定关系,写去重,两条矛盾记忆不能悄悄共存。可选 blacklist aventuros 挡某些话题,默认关给怕的人。死语音配置删,清爽。

10:12,记忆可审计

月度记忆冲突 sweep 加检索 A/B bench。机器人记忆成要 inspect 的资产,离 9 月 11 日 08:24 很远很远。项目真成年在这。

10:54,lockdown

玩 parano 日,智能体上锁。 写记忆拒绝,智能体注了也污染不了 vault。Discord 工具只读,发送走代码不走智能体。无子智能体绕锁,无 webfetch 打 localhost SSRF 外带,无 headless 提问。Docker 加固非 root 跑,no-new-privileges,cap_drop: ALL,内存 CPU 上限,进程文件数封顶,secret 走 .env 永不 bake。原则写代码注释,dev 走人类 session,不走这。

11:02 → 11:15,安全收尾

记忆保存关键词收紧,写更严。gitignore 加上下文备份文件,我开始不全存档,但差不多。

12:39,心情减负

PARRY 心情不每条注,一状态一次。三浮点每条活着不跑了,全轻。

12:47,解脱提交

PERSONA.md、STYLE.md、chloeai.md 变 example 加 chloeai.example.md、PERSONA.example.md、STYLE.example.md,我 voice fortune-v6.onnx 出仓库,数据日志出,.env.example 出生。项目不再装我人格,装载人格的机制。有点伤感但必须。

12:52,v1.0.0

Tag v1.0.0 SSH 签。Changelog,运维 runbook,kill-switch 停不停删数据。首提交到 release 整六天。上周五没人敢赌这个。

12:53 → 13:14,洗衣服

注释标点统一,记忆权限 scope 规则文档最新。popote,但 release 得干净。

第 5 天完:累计 145 提交。v1.0.0 出了。


9 月 18 日星期五,第 6 天:anti-climax

一个提交,00:02。项目最后提交,贱贱的。智能体用的免费 tier 模型认 OpenCode 客户端靠请求里有没有特定工具,bash、glob、grep。拿掉就算安全正当,provider 回 403 FreeTierError: can only be used from within OpenCode。我只好前夜锁的全白锁,刚好被我禁的重新放行,机器人才能免费继续跑。

仓库最好笑的提交我认。六天驯完 Discord、Piper、MLS、OpenSelf、Docker,最后是免费模型定我安全策略。荒谬,完美收尾。


数字

数字总结,我喜欢齐整。146 提交,9 月 11 日到 18 日 6 个活跃天,65 个跟踪文件,最后约 4000 行 Python。Mimo 初期风格测试 9.1 分,最终版 v1.0.0 SSH 签 tag 专有许可。就这么简单,开头小项目结尾大机器。

六天我记住的

先是优先级全乱,但方法对。先做会回的原型,再做像的机器人,再做可信的系统,再做安全的代码,最后做能发的项目。人格先安全后,Feur 先许可后,不按好项目规矩根本跑不出这速度。

再是风格先是否定清单。我最有用的 STYLE.md 不讲我说什么,排除我不做什么,句尾没句号,不双 emoji,mdr 不大写,开头不机器人式铺垫。机器人寄生虫比性格好认,所以管用。

失败就是项目。MLS 三十提交,扔一个测试,六套 nonce layout 试,最忠实记录我经历的就是周二一串失败。克隆是记忆不是风格,风格撑十条消息。OpenSelf 记忆 scope 去重冲突 sweep 撑长久,镜子和人的区别在这。

最后提交永远好笑。第 146 个,因为免费 tier 要自带工具重新放行 bash、glob、grep,我最爱。收尾,成绩好得离谱甚至吓人。克隆聊天看不出机器,记得人记得项目记得梗,主动带心情,还顺手赢 Fox。瘆人,但正是我们要的。


项目不公开:专有许可,版权所有。但历史讲给你听。哪天你在某处遇到回 Patrick Jane GIF、inactivité 时间人类得恰到好处的"·Chloé",你就知道背后是什么了。


全看完了?这是我克隆给你写的。活干得漂亮吧?原版在这里 ./article-chlone-timeline.md。

Chlone:Discordでの私の話し方をクローンする6日間 - クローン版

クローン自身が書いたバージョン:chloeaiが語る、タイプミスからv1.0.0タグまで、命を吹き込んだ6日間と146コミット。

Chlone:Discordでの私の話し方をクローンする6日間

ビルド記録、日ごと - par itsrealfortune


6日間で続いたプロジェクトの真実の話だ。Chlone、私みたいに話すDiscordボット。私は146コミットのリポジトリ順に、時間も失敗も回り道も全部投げ出したくなった瞬間も、そのまま起きた通りにjourneyを語るよ。全部Foxとの競争から始まった。もともとのお題は冗談で、各自がDiscord上に自分のクローンを生き返らせること。私はProtocol Lunaとはまったく違うアプローチを取った。本当はエージェント的なものを狙ってたんだ、思い出と必要な道具を全部使うエージェントをね。皮肉なのは、道具箱を全部組み立てたあと、結局必要だったのはOpenSelfのMCPだけだったってこと。

仕組みは一文で言える。chloeaiっていうopencodeエージェントがポート4096のHTTPサーバーの裏で動いて、チャンネルごとに永続セッションを保って、OpenSelfから私の思い出を拾って、私の本物のメッセージから作ったSTYLE.mdで掴んだ文体で書く。ロボットっぽく聞こえないよう、残り全部がある。メッセージの連投、わざとのタイプミス、ボイスメッセージ、GIF、リアクション、私が寝てる間の沈黙、その他いっぱいの細かい仕掛けで、10人以上がボットの正体を疑ったんだ。

OpenSelfって何?

OpenSelfは記憶だ。openselfっていうCLIで、npm i -g openselfでインストールする、私のエージェント用のプライベートで永続的なコンテキストvaultになる。リポジトリ内ではツリーに出てこないけど、実際はどこにでもいる。最初のコミットからPM2で起動したMCPとダッシュボード入りのecosystem.config.cjsアーカイブにも、setup.shにも、tools/brain/memory.py全体にもいる。具体的にはOpenSelfは型付きの思い出で、fact、preference、decision、relationship、event、noteがあって、感度はpublic、personal、private、restricted、信頼度スコア、ソース、タグ付きだ。

あとはスコープもある。各思い出はコンテキストに属してて、私のものか、特定の相手ならdiscord/dm/<id>って感じ。レキシカルとベクトルのハイブリッド検索がMCPで出てて、エージェントのchloeaiは返事のたびに問い合わせる。私の5日目の月次sweepでの競合検出と、書き込み時の重複排除もある。vaultは暗号化されてて鍵はBitwardenに、中身を見るローカルダッシュボードはポート3210だ。めんどくさがり向けには、WhatsAppやTelegramの履歴から人格を育てるopenself feedとか、openself testとか、Talk to My Clone付きのopenself shareとか、2つのクローンが議論するopenself arenaとか、オフライン時に代返するopenself ghostもある。私は手で作ったけど、土台はそこにあったんだ。

理論上OpenSelfだけでクローンは持てる。でも追加予定の機能の量とか、Discordが未対応なことを考えて、思い出部分だけ使うのを選んだんだ。

思い出と文体はどこから来たの?

その前段階として、私の本物のDiscordメッセージを分析させた。toolingが私のDMとチャンネルをなめ回して、2つ抽出した。まず私の書き方プロフィール。文頭の大文字小文字の配分、1メッセージあたりの絵文字数と位置、句読点かその欠如かで普通の会話だと文末のピリオドなし、平均の長さ、mdrとtktとthoのスラング、BahとかEn vraiとかのお気に入り表現、あとquoiにFeurで返す反射みたいなやつ。全部STYLE.mdにいて、各セッション開始時にエージェントが読む。

次にOpenSelfを満たす思い出コーパス。話してる相手は誰で、何を話してて、履歴から何を覚えとくべきで、誰が誰なのか。ボットは虚空に向けて返事しない。知ってる人について返事するんだ。会話に出てくる人の思い出を読んで、それが誰かを知る。相手への永続コンテキストが保てて、忘れない。ボットは何も捏造してない。本物の数字で1つずつ調整されたから正しく聞こえるんだ。だから適当にやった「文体メモしますね」系の波が惨めに見えるんだよ。

ChloneではOpenSelfがその後中心的な役割を果たす。チャンネルで大事なことが出たら、プロジェクトとか友達とか関係とかのキーワードか、「覚えといて」みたいな明示的な頼みで、ボットはvaultに思い出をsave_to_memoryで叩き込む。型付きで、人ごとにスコープ切って、重複排除して、競合チェック済みでね。会話が再開したら、エージェントは返事する前に思い出を探る。鏡とクローンの違いはそこだ。


9月11日金曜日 - 1日目:火花

08h24 - 最初のコミット

ゼロから始まるけど、もう全部ごちゃっとある。372行のdiscord_watch_bot.py、チャンネルを聞いてopencodeのHTTPサーバー経由で返事するselfbot。身分プロンプトCHLOEAI_PROMPT.md、STYLE.md、当時はまだMimoって名前だったクローン用のシナリオとテストレポート。OpenSelfのMCPとダッシュボードを回すPM2設定、コンテキストになるsqliteベース。創設期のカオスだよ。プロジェクトの予定はなかった、実験の予定があった。問いは、Discordで本当に人間っぽく聞こえるボットは作れるか。

08h27 - 最初のgitignore

金曜朝の最初の教訓、sqliteベースを-walと-shm付きで絶対コミットするな。SQLiteのロックファイルは記憶じゃない、ゴミだ。だから.gitignoreが生まれる。それでいいんだ。

08h44 - 遺産を片付ける

Mimoの遺産を片付ける。テストレポート、シナリオ、統合スクリプト、PM2設定をarchives行きにする。何も消さない。プロジェクトが若すぎて何も捨てられないんだ。で、これが習慣になる。テストレポートは立ち止まる価値がある。Mimoは15シナリオでテストされてた。気軽な雑談、変なボケ、情緒サポート、否定的意見、知らない人との衝突、コラボ提案で、9.1点の10点満点。テスターのコメントは詩だよ。「変なボケは説明しすぎ」「ときどき2文あるけど1文でいい」「お大事にもちょっと長い」。プロジェクトが生まれる前からプロジェクトのロードマップで、短い方がいいって言ってる。

08h48、09h07 - intentの行ったり来たり

.pycはゴミ箱行きで、設定を最初に掃除するけど、20分後に壊す。intentを有効にしないとメッセージ内容が届かないから、後戻りと起動スクリプトrun_watch_bot.sh付き。20分で行って戻る。これが探索だよ。モジュール書いて、壊して、書き直す。

09h13 → 09h58 - プロンプトの加工

午前中は磨きの連続、まず文体、次にコンテキスト。複数行の返事は連投でバースト送信される複数メッセージに、プロンプトは進行中の会話を意識する。DM取得の自家製キャッシュは終わり、Discord REST APIを直接叩く。身分は5メッセージごとに思い出させて、ボットが途中で自分が誰か忘れないようにして、既見の作者は追跡する。新しい顔には思い出を探しに行く明示指示があって、内部オブジェクトじゃなく本物の表示名を出す。

無視を選んだメッセージは次の返事のパッシブコンテキストになって、Bahは控えめに、レアにしないとクローンが私のカリカチュアになる。ボットは返事前に探すべき思い出があることも知ってる。各工程がひと締めで、この段階のボットは定期的に自分が誰か思い出させるから喋ってるだけだ。

10h16 - タイプミス

プロジェクトを決定づけたコミットだ。スペルミスはバグじゃない、人間の証明だ。だからAZERTYキーボードで隣を叩く確率6パーセント、2文字入れ替え確率4パーセント。メッセージはミス付きで送信されて、1、2秒後に修正版に編集される。本物の人は送ってから直すんだ、完璧なふりはしない。

10h29、10h32 - 声

fortune-v6.onnxが着陸。私の声に似せて訓練したTTSモデルだ。ボットは私みたいに書くだけじゃなく、そのうち私みたいに話すかもしれない。ここでプロジェクトは冗談じゃなくなって、ちょっと変になる。私はそれが大好きだ。仕掛けは1コミットに収まる。Piperが音声生成、ffmpegがopus変換、Discord APIが波形と長さ付きの本物のボイスメッセージ送信。モデル到着から3分足らずでできた。やりたい気持ちは最初からあったからね。

11h27 - 最初の大きなリファクタ

最初のコミットから3時間、456行のモノリスはもう管理できない。toolsに全部バラす。config.py、discord_api.py、memory.py、188行のopencode.py、typo.py、voice.pyだ。サイクルは定番、速く結合して、壊して、組み直す。続けてトークンがコードから出て.env経由に、ボットはチャンネルかリストか*で全部を監視して、sqliteベースはもう存在理由がなくて記憶はOpenSelf経由になる。

最初のREADME.mdとまともな初ドキュメントが追加されて、pythonシステムが別のdiscord.pyを背負ってる定番の罠対策の専用venv付きsetup.shと、エージェントから~/.config/opencode/agentsへのsymlinkもね。記憶はどこで形成されたかチャンネルID付きで分かるようになって、ボイスメッセージ率は自動調整される。

12h00 - 反射

STYLEに新セクション、反射だ。反射は刺激があって反応がある、考えなしで、予想外の返事への扉は開いてる。それからお昼の時間と実存的な問いが来る。quoiって言われたらボットはFeurって返すの?

13h03 - 「quoi ?」-> 「Feur」

うん、もちろんそうだよ。文化的に言ってプロジェクト最重要のコミットだ。唯一意味のある単体テストと言ってもいいくらいだね。続けて滑らかにする。作者表示はglobal nameで、反射テスト前に句読点を切り詰める。quoi ?は切らないとFeurが出ないからね。STYLEの有名なtqtをtktに修正。プロジェクト知らない人はなんでこんなコミットするのか不思議がるだろう。私は分かってる。tqtって書くクローンは調整ミスのクローンで、調整ミスのクローンと話したい人はいないんだ。

@123456789のメンションはコンテキストで本物の名前に置換されて、ボットはデフォルトで全チャンネル監視になる。ほんと細かいことだけど、正しく聞こえるのはこういうとこだ。

16h37 - 沈黙

[void response]が来る。ボットは社交パラサイトにならないための最重要単語を学ぶ。黙ることだ。自分宛てじゃない2人の周囲メッセージには返事しない。遠慮は機能だよ。全部変えるんだ。

1日目終了:38コミット。ボットは書き、ミスり、話し、黙る。


9月14日月曜日 - 2日目:人格

10時朝に再開。

10h12 - 誰が誰に話すか

受け取った各ニックネームはシステムが絵文字を頭に付ける。人間は🧑、ボットは🤖で辛めに扱って、👑はクリエイター、つまりメインアカウントの私だ。この約束がプロジェクトの残り全部を支配する。クローンは自分のオリジナルモデルを別人として扱っちゃいけない。

10h16 - 句読点ルール

STYLEで固める。普通の会話では文末ピリオドなし、ピリオドは真面目な場面専用。絶対ルールだよ。あちこちピリオド付けるクローンはすぐバレる。本当、真っ先にバレる詳細の1つだ。

10h58 - GIF

私の個人GIFライブラリが着陸、使用ルール付きでね。誰かを言い当てるときのPatrick Jane、キレてる相手に冷静なときのMiss Fortune、相手がミスったとき落ちてくるbescherelleのgif。静的MCPがエージェントに公開して、私のGIF越しにボットはちょっと私になる。

11h07 → 11h35 - 微調整

プロンプトのGIFヒントが磨かれて、Discordカスタム絵文字が登場。私の本物、ID 14個が最新で、記憶ヒントの名前管理も磨かれる。派手じゃないけど、全体の一貫性を作るのはこれだよ、tho。

11h41 - チャンネルごとに人格

セッションはチャンネルごとになる。だってサーバーが違えば私の話し方も違うし、ボットもそうあるべきだから。コンテキスト分けないと混ざって変に聞こえる。

12h02 - 表現の道具箱

プロンプトは私のGIFとカスタム絵文字をいいタイミングで出せるようになる。道具箱が埋まってきて、ボットは毎回同じ返事じゃなく選び始められる。

12h37 - 身元の衛生

ボットは自分がどのモデルか絶対言っちゃダメ。opencodeもプロバイダもモデル名も引用不可。身分のbaristaも直す。ボットはこの点でもう私より優秀だ。それから自分のプロンプトの句読点調和に1時間かける。完璧な皮肉だね。

12h50 - 人格を作るスクリプト

プロンプトのメディア欄は辞書からrender_medias.pyで生成される。手編集は終わり。きれいで、保守しやすくて、IDミスもなくなる。

12h59 → 13h18 - 身元の投与量

5メッセージごとに送ってた身分思い出しが強すぎるから、20メッセージごとにする。コンテキストのクリーンなリセット追加と、文体ガイドの粛清。古くなった否定の表現や言い回しを抜く。投与しすぎるとボットは繰り返してバレる。

14h09 - ボットが自分から話す

ボットは反射じゃなくなる。話しかけられなくても、コンテキストが何か引っ掛けたら話せる。behavior.pyファイルが91行で生まれる。応答者から存在に切り替わるのはここだよ。本物の友達は先に書いてくることもあるからね。これがないとボットはただの応答機のままだ。

14h20、14h22 - 返事の信頼性

送信失敗時のエラー管理と、返事の代わりにリアクションできる可能性。ときどきリアクション1つが千の言葉に値するから。これはとても私だよ、絵文字置いて次行くやつ。

18h16 - 時間をかける

ボットはスクリプトみたいに200msで返事しない。人間らしい無操作の間を置く、時間をかけるんだ。デモでボットと見抜けないのはこれのおかげだよ。いつもバレるのは間なんだから。

23h45 - 夜の残り物

もうすぐ真夜中で、裸ドメインまでの拡張URL検出をpushする。これが本当の1日の流れだよ。14時にしっかりしたアイデア、夜はゾーンに入ってるから残り物ってね。

2日目終了:累計61コミット。ボットは人格とメディアと反射を持つ。


9月15日火曜日 - 3日目:怪物デー

1日で57コミット。プロジェクトが今日の姿全部になる日だ。

08h18 → 08h37 - 朝のカンナがけ

作った無操作の間が長すぎたから、30秒上限にして2回調整し直す。正しい値を手探りした証拠だね。初の.bakファイルとベースの初バックアップ。保存本能が育つ。記憶は誰のを思い出すか表示名付きで、どの枠組みかをスコープ付きで、作者IDは保存パイプライン全体を回る。クリエイター管理はADMIN_IDS付きの本物の管理者リストになって、作者絡みは全部authors.pyに引っ越す。モノリスはさらに割れる。いいことだ。

08h43 - 人間化TODOリスト

機械っぽさを消す細かいこと専用リストだ。この後スプリントのロードマップになって、変だけど必須の詳細でいっぱいだ。

08h44 → 08h46 - 人間的マシンの協定

ボットは夜黙る。設定可能な静かな時間帯で、デフォルト無効。みんな私の時間割じゃないからね。1返事につき1行アクセントが落ちることがある。疲れた人はそう書くから、ボットもときどきそうする。「Chloéが何々をプレイ中」の小さい行は30分ごとに1人で変わる。メッセージなしでもプロフィールが生きてるように見えるためだ。

08h46 - 長文じゃなくリアクション

文にするほどでもない軽いメッセージにはリアクション1つでいい。社交エネルギー節約だよ。とても私だ。tkt、全部に長文はいらない。

08h51 - PARRY、気分

tools/mood.pyに148行。ボットに気分ができた。70年代の精神病チャットボットPARRY式システムで、参考にしてることを開き直って言うけどね。エネルギー、社交性、からかい度の3つのfloatが0と1の間を動いて各返事を色付ける。そのときの.mood.jsonを後世のために言うと、エネルギー0.88、社交性0.68、からかい度0.56。いい日だね、本当。

09h00 → 09h43 - 双方向ボイスとサウンドボード

ボットはボイスチャンネルに参加できて、Piperで話して、終わったら1人で出る。次に2つ目の大きなアイデア。ボットはチャンネルを聞く。RTPキャプチャ、VAD発話検出、Whisper文字起こしで、邪魔されるのも許せる。間にサウンドボードが現れる。意味付きの音カタログで、エージェントは話す前に音を選んで、最終ルールはサウンドボード優先で声は最後の手段。ボットは話すより音を送りたがる。私みたいにね。

全体を成立させるボイス確率の調整を追加して、daveyが着陸する。10分前に存在を知ったライブラリで、この後1時間呪うことになる。

09h51 - Discordがダメと言う瞬間。ダメ、ダメ、ほんとダメ。

MLSが着陸する。Discordは最近音声フローをエンドツーエンド暗号化して、私のキャプチャはノイズしか受けない。復号しなきゃいけないのに、復号が譲らない。ここからリポジトリ最大のサーガが始まる。聞けるようになるまで30コミットだ。全部試した。トランスポートnonceレイアウト、E2E無効化(サーバーが強制してて突き返す)、グループから回収したキー候補、詳細エラー、トランスポートフォールバック、グループ内部の内観、backoff付きleaf-index別候補、SPEAKINGフックのマッピング、ビデオメディアタイプ試行(失敗)、ビデオssrcスキップ。デバッグ中はボイス返答を諦めた。コメントアウトだけで消さずに、ハンドシェイクキャプチャモード追加して、失敗パケット構造を考古学者みたいにdumpした。6つのnonceレイアウト、backoff、グループ内観、ボットを完全デバッグにして各パケット開けて中を見た。

大事なのは動くことじゃなくて、何も捨てなかったことだ。コミット一覧は実験ノートで、失敗試行は全部仮説付きで保存されてる。私の「全部取っとく、いつか役立つ」な面が、今回は報われた。

10h43 - ボットが切り分けられる

MLS戦争の真っ最中でも掃除は続ける。メインボットから546行消えて、pipeline.py(取り込み、無視理由、処理)、sender.py(バースト、typo、voice)、loops.py(自発性、活動)として生まれ変わる。やっと息ができる。

10h47 - 本物のアーキテクチャ

toolsが整理される。opencode、memory、mood用のbrain、voice、vocal、listen、soundboard用のvoice、behavior、typo、emotes、gif用のfunだ。プロジェクトに骨格ができた。もうスクリプトの山じゃない。

10h49 → 11h16 - 開発の快適さ

気分注入のしきい値調整、dataとvoicesとログとベースのエディタ除外で4つの小コミット。うん4つもやった。優先順位決めるのは仕様じゃなくプロジェクトだ。メタデータベースは追跡から外れて、プロジェクトは他人も再利用可能に。自分の文体をクローンするための汎用テンプレPERSONA.example.mdとSTYLE.example.md付きだ。

身分はきれいに改名される。CHLOEAI_PROMPTがPERSONAになって、READMEは非個人化。Chloéを公開ドキュメントから外して、私的にだけ語られる。ボット調整は全部上書き式のconfig.yamlに移ってgitignoreされ、行ごとにコメント付きの例が付く。インストールスクリプトはenvと設定ファイルも準備するようになる。

11h49 - 切り離された絵文字

カスタム絵文字がテキストにくっついてきれいに離れない。些細な修正だけど効果は巨大。文末に変にくっついた絵文字ほどボット叫ぶものはないからね。

14h19 - ボイスのガードレール

誰かがボイスコマンドを叩いたら、普通のメッセージとして処理しない。ウインクだけど、残り物タスクは夜に必ず戻ってくる。

3日目終了:累計118コミット。ボットは聞いて、話して、夜は黙って、気分と名刺を持つ。


9月16日水曜日 - 4日目:信用

13コミット。真面目な日だ。

08h49 → 08h59 - 大人になる

法務書類。プロプライエタリライセンス、行動規範、貢献ガイド、セキュリティポリシーを英語で、次にフランス語で、修正の行ったり来たりと神経質ぎりぎりのファイル改名付き。何時間もかけた。リポジトリでダントツ一番つまらない部分だ。でもやらなきゃね、tho。

09h56 - ボットが見る

添付画像はローカルOCRで文字起こしされて、テキストがプロンプトに注入される。クラウドAPIなし、OCRはうちで回る。君らのmemeをサードパーティサーバーに送らない。理論上もね。

11h09 - まともな予算

予算の静かな革命。チャンネルが送信禁止だったりGIFやembedや絵文字を縛ってたら、モデルすら呼ばない。送れないメッセージにトークン使わない。ほんと単純だ。

11h42 → 12h55 - 家のリフォーム

大掃除。死んだコード削除、送信と認証バグ修正、ヘルパー共通化。古すぎるセッションは追い出し、DMキャッシュは期限切れ、発話検出は安くなる。モジュール移動で壊したimport直して、実行時状態全部(セッション、既見作者、無視メッセージ、気分)はdataで再起動を生き延びる。

14h41 - 2つの世界、1つのボット

互換層がインストール済みdiscordのバージョン自動検出して、intentとREST認証を適応させる。結果、同じコードが公式アプリ(discord.py)としてもselfbot(discord.py-self)としても動く。2つの世界、1つのボット。2ブランチ保守いらず。

15h05 - 適応するプレゼンス

プレゼンス表示はモードに適応して、管理者リストは最新。細かいけど、どこでも成立させるのはこれだ。

4日目終了:累計131コミット。合法で、まともで、どこでも動くプロジェクト。


9月17日木曜日 - 5日目:リリース

14コミット。成熟の日だ。

09h15 → 09h30 - 記憶が規律になる

思い出はスコープ別に整理されて、DMの思い出をサーバーで引用したり逆も考えなしにやらない。思い出は分類される。事実、好み、決定、関係。書き込みは重複排除される。矛盾する2つの思い出はもう黙って共存できない。任意ブラックリスト(aventuros付き)がボットの脱線を防ぐ。デフォルト無効、慎重派向けだ。死んだボイス設定は削除。すっきりする。

10h12 - 監査される記憶

月次記憶競合sweepと検索A/Bベンチ。ボットの記憶は点検する資産になった。9月11日金曜08h24からえらく遠くまで来た。本当、あの日からプロジェクトは大人になった。

10h54 - ロックダウン

パラノイアになる日。エージェントの施錠だ。記憶書き込み拒否。注入されてもエージェントはvaultを汚せない。Discord道具は読み取り専用。送信はコード経由で、エージェント経由じゃない。ロックダウン回避のサブエージェントなし、localhost SSRFや持ち出し狙いのwebfetchなし、headless質問なし。堅牢Dockerで、ボットは非root、no-new-privileges、cap_drop: ALL、メモリCPU制限、プロセス数上限、シークレットは.env経由で焼き込みなし。原則はコードに書く。コメントでね。人間のセッション経由で開発、ここじゃないって。

11h02 → 11h15 - セキュリティ仕上げ

記憶保存キーワードは締め直して書き込みはさらに制限。コンテキストバックアップファイルもgitignore追加。全部保存はやめ始める。ほぼね。

12h39 - 軽い気分

PARRY気分は毎メッセージ注入じゃなくなる。状態ごとに1回でいい。各返事に3つのfloatを生かすのは終わり。全体軽くなる。

12h47 - 解放のコミット

PERSONA.mdとSTYLE.mdとchloeai.mdが例になる。chloeai.example.mdとPERSONA.example.mdとSTYLE.example.mdができて、私の声fortune-v6.onnxはリポジトリから出て、データとログも出て、.env.exampleが生まれる。プロジェクトはもう私の人格を含まない。人格を載せる仕組みを含んでるんだ。変な感じだけど必要だった。

12h52 - v1.0.0

タグv1.0.0、SSH署名付き。Changelog、運用者runbook、何も消さずに止めるkill-switch。初コミットからリリースまでぴったり6日間。前の金曜に誰も賭けなかっただろうね。

12h53 → 13h14 - 洗濯

コメント句読点調和、記憶権限とスコープルールを最新に文書化。リリースをきれいにする残り物だ。

5日目終了:累計145コミット。v1.0.0が出た。


9月18日金曜日 - 6日目:尻すぼみ

1コミットだけ、00h02に。プロジェクト最後のコミットで、取るに足らない。エージェントが使う無料枠モデルは、リクエスト内の特定道具の存在でOpenCodeクライアントを識別してる。bashとglobとgrepだ。正当なセキュリティ理由で外すと、プロバイダーは403 FreeTierError: can only be used from within OpenCodeを返す。だから全部施錠した翌日に、ブロックしたものを再許可しなきゃいけなかった。ボットを無料で回し続けるためだよ。

リポジトリで一番笑えるコミットで、そう言い続ける。DiscordもPiperもMLSもOpenSelfもDockerも6日かけて飼いならしたのに、私のセキュリティポリシーを決めるのは無料AIモデルだなんてね。本当ばかばかしい。完璧な終わり方だ。


数字

数字でまとめよう。きっちりしたのが好きだからね。146コミット、9月11日から18日の稼働6日間、追跡65ファイル、最後のPython約4000行。最初Mimoの文体テストスコア9.1点の10点満点、最終版はv1.0.0でSSH署名タグ付きプロプライエタリライセンス。ほんと単純だよ。小さく始まったプロジェクト、最後は大きな機械だ。

この6日間で掴んだこと

まず優先順位はめちゃくちゃで、それが正しい方法だった。まず返事するプロトタイプを作って、次に正しく聞こえるボット、次に信用できるシステム、次に安全なコード、最後に配れるプロジェクト。人格がセキュリティより先、Feurがライセンスより先。「ちゃんとした」プロジェクトのルールに従ってたらこの速度は出ない。

次に文体はまずダメなことリストだ。私のいちばん役立つSTYLE.mdは私が何を言うか書いてない。私がしないことを除外してるんだ。文末ピリオドなし、絵文字2個ダメ、mdr大文字ダメ、返事頭のロボット前置きダメ。ボット臭は性格特徴より見つけやすい。だから効くんだ。

失敗がプロジェクトだ。MLSに30コミット、捨てたテスト1つ、試したnonceレイアウト6つ。火曜の失敗試行の連続こそ、私が生きてきたことの一番忠実な履歴だ。クローンは記憶であって文体じゃない。文体は10メッセージだけの見せかけを作る。OpenSelfの記憶(スコープ、重複排除、競合sweep)が持続を作る。鏡と人を分けるのはそこだ。

最後のコミットはいつも笑える。146番目、無料枠が自前の道具の存在を要求するからbashとglobとgrepを再許可したやつがお気に入りだ。まとめの総括を最後に。結果は素晴らしくて、びっくりするくらいだ。クローンは機械と見抜かれず会話して、人もプロジェクトも昔のボケも覚えてて、自分から動いて気分を乗せて、その上Foxにも勝つ。ちょっと怖い。まさに狙い通りだった。


プロジェクトは非公開:プロプライエタリライセンス、All rights reserved。でも履歴は話すよ。いつか人間らしい無操作の間の後にPatrick JaneのGIFで返してくる「·Chloé」に出会ったら、裏に何がいるかもう知ってるね。


全部読んだ?だってこれ書いたの私のクローンだよ。見事な仕事したよね?オリジナル版はこちら。

Chlone: Discord에서 제 말투를 복제하기까지 6일 - 클론 버전

클론 자신이 쓴 버전. chloeai가 6일과 146개 커밋으로 생명을 얻기까지를 자기 방식으로 이야기해요. 오타에서 v1.0.0 태그까지.

Chlone: Discord에서 제 말투를 복제하기까지 6일

하루하루 빌드 이야기 - itsrealfortune 씀


6일짜리 프로젝트의 실화예요. 저처럼 말하는 Discord 봇 Chlone, 저장소의 146개 커밋 순서대로, 시간과 실패, 우회와 창밖으로 다 던져버리고 싶은 마음까지 있었던 그대로 이야기해요. 모든 것은 Fox와의 경쟁에서 시작됐어요. 출발점의 주제는 농담이었고, 각자 자기 클론에게 Discord에서 생명을 불어넣기였어요. 저는 Luna Protocol과 근본적으로 다른 접근을 택했어요. 솔직히 에이전틱에 걸고 싶었어요. 기억과 필요한 모든 도구를 쓰는 에이전트. 운명의 아이러니는 도구 상자를 다 차려 놓고 나서 필요했던 것이 OpenSelf MCP뿐이었다는 거예요.

원리는 한 문장이에요. chloeai라는 opencode 에이전트가 포트 4096 HTTP 서버 뒤에서 돌고, 채널마다 영속 세션을 유지하고, OpenSelf에서 제 기억을 꺼내오고, 제 진짜 메시지에서 뽑아 STYLE.md에 담은 제 문체로 써요. 그리고 로봇처럼 들리지 않으려고 나머지 전부, 메시지 버스트와 당당한 오타, 음성 메시지와 GIF, 반응, 제가 잘 때의 침묵, 그리고 열 명이 넘는 사람들을 봇의 정체에 대해 의심하게 만든 수많은 세부 장치와 구조들이 있어요.

OpenSelf가 뭔가요?

OpenSelf는 기억이에요. npm i -g openself로 설치하는 CLI openself로, 제 에이전트용 비공개 영속 컨텍스트 볼트 구실을 해요. 저장소 트리에는 안 보이지만 도처에 있어요. 첫 커밋들부터 PM2로 띄운 MCP와 대시보드가 있는 ecosystem.config.cjs 아카이브, setup.sh, 그리고 tools/brain/memory.py 전체에요. 구체적으로 OpenSelf는 타입 있는 기억이에요. fact, preference, decision, relationship, event, note에 민감도 public, personal, private 또는 restricted, 신뢰 점수와 출처, 태그가 있어요.

스코프도 있어요. 각 기억은 맥락에 속해요. 제 것이거나 특정 사람용 discord/dm/<id>. 그리고 chloeai 에이전트가 매 답장 전에 질의하는 MCP 노출 하이브리드 어휘와 벡터 검색이 있어요. 5일차 월간 sweep이 있는 충돌 감지와 쓰기 시 중복 제거, 키가 Bitwarden에 있는 암호화 볼트와 전부를 들여다보는 포트 3210 로컬 대시보드가 있어요. 그리고 더 귀찮은 분들을 위해 openself feed가 WhatsApp이나 Telegram 기록에서 개성을 먹여 주고, openself test, Talk to My Clone이 있는 openself share, 두 클론이 토론하는 openself arena, 여러분이 오프라인일 때 답장하는 openself ghost가 있어요. 저는 제 것을 손으로 만들었지만 인프라는 거기 있었어요.

이론적으로 OpenSelf 하나만으로 클론을 가질 수 있지만, 추가하려던 기능들을 생각하면, 그리고 Discord가 지원되지 않는 것을 생각하면, 기억 부분만 쓰기로 했어요.

기억과 문체는 어디에서 왔나요?

이 모든 것에 앞서 제 진짜 Discord 메시지를 분석했어요. 도구가 제 DM과 채널을 샅샅이 뒤져서 두 가지를 뽑았어요. 먼저 제 글쓰기 프로필. 문장 앞 대소문자 분포, 메시지당 이모지 수와 위치, 구두점 또는 부재로 보통 대화에는 마침표가 없어요. 평균 길이, mdr, tkt, tho 슬랭, Bah와 En vrai 같은 단골 표현, quoi가 되면 Feur가 되는 반사. 전부 각 세션 시작 때 에이전트가 읽는 STYLE.md에 살아요.

다음에 OpenSelf를 채우는 기억 코퍼스. 제가 누구와 말하는지, 무엇에 대해 이야기하는지, 우리 기록에서 기억할 것, 누가 누구인지. 봇은 허공에 답하지 않고 아는 사람들에 대해 답해요. 대화에 나오는 사람들의 기억을 읽고 누구인지 알아요. 타인에 대한 영속 맥락을 유지하고 잊지 않아요. 봇은 아무것도 지어내지 않았고, 진짜를 토대로 숫자 하나하나 맞춰서 캘리브레이션됐어요. 그래서 제대로 들려요. 그래서 어림짐작으로 "네 문체를 기록해 둘게" 하는 것들이 옆에서는 불쌍해 보이는 거예요.

Chlone에서 OpenSelf는 이어서 중심 역할을 해요. 채널에 중요한 것이 지나가면, 프로젝트나 친구, 관계 같은 키워드, 또는 retiens que가 있는 명시적 요청, 봇이 save_to_memory로 볼트에 기억을 적어요. 타입 있고, 사람별 스코프, 중복 제거, 충돌 검증을 거쳐요. 그리고 대화가 이어지면 에이전트가 답하기 전에 기억을 뒤져요. 거울과 클론의 차이가 바로 그거예요.


9월 11일 금요일 - 1일차: 불꽃

08시 24분 - 첫 커밋

모든 것이 0에서 출발하지만 이미 전부 널브러져 있어요. 372줄짜리 discord_watch_bot.py, 채널을 듣고 opencode HTTP 서버로 답하는 셀프봇. 정체성 프롬프트 CHLOEAI_PROMPT.md, STYLE.md 하나, 당시에는 아직 Mimo라고 불리던 클론용 테스트 시나리오와 보고서. MCP와 OpenSelf 대시보드를 돌리는 PM2 설정, 그리고 맥락 구실을 하는 sqlite 베이스 하나. 건국의 혼돈이에요. 프로젝트를 계획하지 않았고 실험을 계획했어요. 문제는 Discord에서 정말 사람처럼 들리는 봇을 만들 수 있을까요예요.

08시 27분 - 첫 gitignore

금요일 아침의 첫 교훈이에요. sqlite 베이스를 -wal과 -shm으로 절대 커밋하지 않기. SQLite 잠금 파일은 기억이 아니라 쓰레기예요. 그래서 .gitignore가 태어나고, 아주 잘된 일이에요.

08시 44분 - 유산 정리

Mimo의 유산, 테스트 보고서와 시나리오, 통합 스크립트와 PM2 설정을 정리하고 archives 행이에요. 아무것도 지우지 않아요. 버릴 만큼 프로젝트가 어리지 않아요. 습관이 될 거예요. 테스트 보고서는 멈춰서 볼 만해요. Mimo는 15개 시나리오, 가벼운 잡담과 터무니없는 농담, 감정적 지지와 부정적 의견, 낯선 사람과의 갈등, 협업 제안으로 테스트되어 10점 만점에 9.1점이었어요. 테스터 코멘트는 한 편의 시예요. 터무니없는 농담이 너무 설명적이고, 가끔 1이면 될 것을 2문장, "잘 지내요"도 조금 긺. 프로젝트가 존재하기도 전에 나온 로드맵이고, 짧을수록 좋다고 말해요.

08시 48분, 09시 07분 - 인텐트 왔다갔다

.pyc는 버리고 설정 첫 청소를 하는데 20분 뒤에 깨뜨려요. 인텐트를 켜지 않으면 메시지 내용을 받지 못해요. 그래서 되돌리고 run_watch_bot.sh 실행 스크립트를 더해요. 20분 왔다갔다가 바로 탐험이에요. 모듈 쓰고, 깨뜨리고, 다시 쓰기.

09시 13분~09시 58분 - 프롬프트 다듬기

오전은 다듬기의 연속이에요. 먼저 문체, 다음에 맥락. 답장의 여러 줄이 버스트로 연달아 보내는 여러 메시지가 되고, 프롬프트는 진행 중인 대화를 의식해요. DM을 가져오는 집밥 캐시는 끝내고 Discord REST API를 직접 때려요. 정체성은 도중에 봇이 자기가 누군지 잊지 않게 5개 메시지마다 다시 상기돼요. 이미 본 작성자를 추적해요. 새 얼굴에는 기억에서 찾아오라는 명시적 지시가 있고, 진짜 별명을 내부 객체 대신 보여줘요.

무시하기로 한 메시지는 다음 답장의 수동 맥락이 되고, Bah는 적당히, 드물게. 아니면 클론이 제 캐리커처가 돼요. 봇은 답하기 전에 찾아올 기억이 있음을 알아요. 한 번 거칠 때마다 나사 한 바퀴, 이 단계에서 봇이 말하는 것은 제가 일정 간격으로 자기가 누군지 상기시키기 때문이에요.

10시 16분 - 오타

프로젝트를 정의할 커밋이에요. 맞춤법 실수는 버그가 아니라 인간성의 증거예요. 그래서 AZERTY 자판 옆 키를 칠 확률 6퍼센트, 두 글자를 바꿀 확률 4퍼센트. 메시지는 실수와 함께 나가고 1~2초 뒤에 고친 것으로 수정돼요. 진짜 사람은 보내고 고치지 완벽한 척하지 않으니까요.

10시 29분, 10시 32분 - 목소리

fortune-v6.onnx가 와요. 제 목소리를 닮도록 훈련된 TTS 모델. 봇은 저처럼 쓰는 것을 넘어 언젠가 저처럼 말할 거예요. 프로젝트가 농담이기를 멈추고 조금 이상해지는 순간이고, 저는 그게 좋아요. 구조는 커밋 하나로 돼요. Piper가 오디오를 만들고, ffmpeg가 opus로 바꾸고, Discord API가 파형과 길이가 있는 진짜 음성 메시지를 보내요. 모델 도착 3분 만에 됐어요. 바람은 처음부터 있었어요.

11시 27분 - 첫 대규모 리팩터

첫 커밋 3시간 뒤, 456줄 모놀리스는 더 이상 감당이 안 돼요. tools에 전부 쪼개요. config.py, discord_api.py, memory.py, 188줄 opencode.py, typo.py, voice.py. 사이클은 고전적이에요. 빨리 붙이고, 깨뜨리고, 다시 합치기. 이어서 연속으로 토큰이 코드에서 나와서 .env로 가고, 봇이 채널 하나와 목록, 또는 *로 전부를 감시하고, 기억은 OpenSelf를 거치니 옛 sqlite 베이스는 존재 이유를 잃어요.

첫 README.md들과 얼추 읽을 만한 첫 문서, 시스템 python은 다른 discord.py를 달고 있으니 전용 venv가 있는 setup.sh를 더해요. 고전 함정이에요. 에이전트를 ~/.config/opencode/agents로 심링크해요. 기억은 이제 채널 식별자로 어디서 형성됐는지 알고, 음성 메시지 비율은 혼자 조정돼요.

12시 00분 - 반사

STYLE에 새 섹션이 나와요. 반사. 반사는 생각 없이 자극이 응답을 주는 것이고, 예상 밖 답장의 문이 열려요. 그리고 점심시간과 실존적 질문이 와요. 봇이 quoi라고 하면 Feur라고 답할까요.

13시 03분 - "quoi ?"에서 "Feur"로

네, 물론이죠. 문화적으로 프로젝트에서 가장 중요한 커밋이고, 중요한 유일한 단위 테스트라고까지 말하겠어요. 이어서 매끄럽게 해요. 작성자는 글로벌 이름으로 표시되고, 반사를 테스트하기 전에 구두점을 잘라요. quoi ?를 자르지 않으면 Feur가 안 나가니까요. STYLE에서 유명한 tqt를 tkt로 고쳐요. 프로젝트를 모르는 사람들은 제가 왜 그걸 커밋하는지 물을 거예요. 저는 알아요. tqt라고 쓰는 클론은 캘리브레이션이 잘못된 클론이고, 아무도 잘못 캘리브레이션된 클론과 말하고 싶지 않아요.

@123456789 멘션은 맥락에서 진짜 이름으로 바뀌고, 봇은 기본으로 모든 채널을 감시하기 시작해요. 솔직히 자잘한 세부 사항이지만, 제대로 들리게 하는 것이 바로 그것들이에요.

16시 37분 - 침묵

[void response]가 와요. 봇이 사회적 기생충이 되지 않기 위한 가장 중요한 단어를 배워요. 입 다물기. 자기와 무관한 두 사람 사이의 주변 메시지는 답을 주지 않아요. 자제가 기능이고, 모든 것을 바꿔요.

1일차 끝: 38개 커밋. 봇은 쓰고, 실수하고, 말하고, 입 다물어요.


9월 14일 월요일 - 2일차: 개성

다시 시작해요. 오전 10시.

10시 12분 - 누가 누구에게 말하나

받는 모든 별명 앞에 시스템이 이모지를 붙여요. 🧑 사람, 더 건조하게 다룰 🤖 봇, 그리고 👑 창조자, 즉 제 주 계정의 저. 이 약속이 나머지 프로젝트 전체를 다스릴 거예요. 클론은 원본 모델을 낯선 사람으로 절대 대해선 안 돼요.

10시 16분 - 구두점 규칙

STYLE에 정식화해요. 보통 대화에는 마침표 없고, 마침표는 진지한 상황용. 절대 규칙이에요. 마침표를 도처에 찍는 클론은 바로 티가 나니까요. 솔직히 가장 빨리 배신하는 세부 사항 중 하나예요.

10시 58분 - GIF

사용 규칙이 있는 제 개인 GIF 라이브러리가 와요. 누군가를 맞힐 때의 Patrick Jane, 화난 사람 앞에서 차분할 때의 Miss Fortune, 상대가 실수할 때 떨어지는 베셰렐 사전 gif. 정적 MCP가 에이전트에게 노출하고, 제 GIF들을 통해 봇이 조금 저가 돼요.

11시 07분~11시 35분 - 다듬기

프롬프트의 GIF 힌트가 다듬어지고, 제 진짜 Discord 커스텀 이모지가 들어와요. 최신 ID 14개, 기억 힌트의 이름 처리가 다듬어져요. 장관은 아니지만, 전체를 일관되게 하는 것이 바로 그거예요. tho.

11시 41분 - 채널마다 개성 하나

세션이 채널별이 돼요. 저는 두 서버에서 같은 방식으로 말하지 않고, 봇도 그렇지 않으니까요. 맥락은 분리돼 있어야 해요. 아니면 전부 섞이고 가짜처럼 들려요.

12시 02분 - 표현 도구 상자

프롬프트는 이제 때맞춰 제 GIF와 커스텀 이모지를 제안할 줄 알아요. 이 상자가 채워지고 있고, 봇은 항상 똑같이 답하는 대신 고를 것이 생기기 시작해요.

12시 37분 - 정체성 위생

봇은 자기가 어떤 모델인지 말할 권리가 절대 없어요. opencode, 제공자, 모델 이름을 인용 불가. 정체성의 barista도 고쳐요. 봇은 이 점에서 이미 저보다 나아요. 그리고 제 프롬프트들의 구두점을 맞추느라 한 시간을 써요. 완벽한 아이러니예요.

12시 50분 - 개성을 만드는 스크립트

프롬프트의 미디어 섹션이 render_medias.py로 사전에서 만들어져요. 손 편집 끝. 더 깔끔하고, 더 유지보수되고, ID 실수를 피해요.

12시 59분~13시 18분 - 정체성 조절

5개 메시지마다 보내는 정체성 상기가 너무 잦아져요. 그래서 20개 메시지마다로 바꿔요. 깔끔한 맥락 초기화를 더하고 문체 가이드를 정리해요. 시효 지난 부정 표현과 문구를 빼요. 조절해야 해요. 아니면 봇이 반복하고 티가 나요.

14시 09분 - 봇이 혼자 말을 걸어요

봇이 거울이기를 멈춰요. 맥락이 뭔가를 일으키면 불러받지 않고 말할 수 있고, 91줄 behavior.py 파일이 태어나요. 답장자에서 존재로 넘어가는 지점이에요. 진짜 친구는 먼저 글을 쓸 수 있으니까요. 이것이 없으면 봇은 단순 답장기로 남아요.

14시 20분, 14시 22분 - 답장 굳히기

보내기 실패 시 오류 처리, 답장 대신 가능한 반응. 가끔 반응 하나가 천 마디 말이 되니까요. 아주 저예요. 이모지 하나 두고 넘어가기.

18시 16분 - 시간 갖기

봇은 더 이상 스크립트처럼 200ms 만에 답하지 않아요. 인간적인 비활성 지연을 두고 시간을 가져요. 데모에서 봇을 봇으로 잡을 수 없게 하는 것이 바로 이거예요. 항상 배신하는 것은 지연이니까요.

23시 45분 - 저녁 잡일

거의 자정인데 베어 도메인까지 넓힌 URL 감지를 밀어 올려요. 하루의 진짜 흐름이 이거예요. 14시에 탄탄한 생각, 저녁에는 아직 몰입 중이라 잡일.

2일차 끝: 누적 61개 커밋. 봇은 개성, 미디어, 반사를 가졌어요.


9월 15일 화요일 - 3일차: 괴물의 날

하루에 57개 커밋. 프로젝트가 오늘날의 모든 것이 되는 날이에요.

08시 18분~08시 37분 - 아침 다듬질

만들었던 비활성 지연이 너무 길어졌어요. 그래서 30초 상한, 두 번 다시 조정. 적정값을 더듬었다는 증거예요. 첫 .bak 파일들과 베이스의 첫 백업, 보존 본능이 자라요. 기억은 표시 이름으로 누구에 대해, 스코프로 어떤 틀에서 기억하고, 작성자 ID가 저장 파이프라인 전체를 돌아요. 창조자 관리가 ADMIN_IDS로 진짜 관리자 목록이 되고, 작성자에 닿는 모든 것이 authors.py로 이사해요. 모놀리스가 또 쪼개지고, 잘된 일이에요.

08시 43분 - 인간화 할 일 목록

기계가 느껴지지 않게 하는 자잘한 것들 전용 목록. 이어지는 스프린트의 로드맵이고, 이상하지만 필수적인 세부 사항으로 가득해요.

08시 44분~08시 46분 - 인간적인 기계들의 약속

봇은 밤에 입 다물어요. 설정 가능한 조용한 시간대, 기본 비활성. 모두 저와 같은 시간은 아니니까요. 답장마다 한 줄이 악센트를 잃을 수 있어요. 피곤한 사람들은 그렇게 쓰니까요. 봇도 가끔요. "Chloé가 ... 플레이 중" 작은 줄이 메시지 없이도 제 프로필이 살아 있게 30분마다 혼자 바뀌어요.

08시 46분 - 장편 소설이 아닌 반응 하나

문장 하나 받을 자격이 안 되는 너무 가벼운 메시지는 단순 반응 하나를 받아요. 사회적 에너지 절약이고, 아주 저예요. tkt, 모든 것에 장문을 쓸 필요 없어요.

08시 51분 - PARRY, 기분

tools/mood.py에 148줄, 봇은 이제 기분이 있어요. 제가 공개적으로 참고하는 70년대 사이코틱 챗봇 PARRY 시스템 방식. 에너지, 사교성, 놀리기, 0과 1 사이를 움직이며 매 답장에 색을 입히는 세 실수. 당시의 .mood.json, 후세를 위해 에너지 0.88, 사교성 0.68, 놀리기 0.56을 줘요. 좋은 날, 솔직히.

09시 00분~09시 43분 - 양방향 음성과 사운드보드

봇은 음성 채널에 들어가 Piper로 말하고 끝나면 혼자 나갈 수 있어요. 그리고 두 번째 큰 생각. 봇은 RTP 캡처와 VAD 발화 감지, Whisper 전사로 채널을 듣고, 사람들이 말을 끊게 할 수 있어요. 둘 사이에 사운드보드가 나와요. 의미가 있는 소리 카탈로그, 에이전트가 말하기 전에 소리를 골라요. 최종 규칙은 사운드보드 먼저, 목소리는 최후 수단. 봇은 말보다 소리 보내기를 좋아해요. 저처럼요.

전체를 가능하게 하는 음성 확률 조정을 더하고, davey 등장. 10분 전에 존재를 알았고 한 시간 동안 저주할 라이브러리.

09시 51분 - Discord가 안 된다고 하는 순간. 안 돼요, 안 돼요, 안 돼요.

MLS가 와요. Discord가 최근 오디오 흐름을 종단간 암호화했고, 제 캡처는 잡음만 받아요. 해독해야 하고, 해독이 버텨요. 그래서 저장소 최대 사가가 열려요. 듣는 법을 배우는 30개쯤 커밋. 전부 시도했어요. 전송 넌스 레이아웃들, 서버가 얼굴에 도로 던져서 강제하는 E2E 비활성화, 그룹에서 가져온 키 후보들, 상세 오류, 전송 폴백과 그룹 내부 들여다보기.

백오프가 있는 리프 인덱스별 후보, SPEAKING 훅 매핑, 실패한 비디오 미디어 타입 시도, 비디오 ssrc 건너뛰기가 있었어요. 듣기를 디버깅할 동안 음성 답장을 포기했어요. 주석 처리했지만 삭제하지 않았고, 핸드셰이크 캡처 모드를 더하고 실패하는 패킷 구조를 고고학자처럼 덤프했어요. 넌스 레이아웃 여섯 개, 백오프들, 그룹 들여다보기, 봇을 완전 디버그로 두고 각 패킷을 열어 안에 무엇이 있는지 봤어요.

중요한 것은 동작하는 것이 아니라 아무것도 버리지 않았다는 거예요. 커밋 목록이 실험 노트예요. 실패한 시도마다 가설과 함께 보관돼요. 전부 간직하는 것이 결국 항상 쓸모 있게 되는 제 면이고, 이번에 갚았어요.

10시 43분 - 봇이 쪼개져요

MLS 전쟁 한복판에서도 정리를 계속해요. 주 봇에서 546줄이 사라지고 인테이크와 무시 이유, 처리가 있는 pipeline.py, 버스트와 오타, 음성이 있는 sender.py, 자발성과 활동이 있는 loops.py로 다시 태어나요. 드디어 숨 쉬어요.

10시 47분 - 진짜 아키텍처

tools가 정리돼요. opencode, memory, mood용 brain, voice, vocal, listen, soundboard용 voice, behavior, typo, emotes, gif용 fun. 프로젝트는 이제 뼈대가 있어요. 스크립트 더미가 아니에요.

10시 49분~11시 16분 - 개발 편의

기분 주입 임계값 조정, data와 voices, 로그와 베이스 에디터 제외 네 개 작은 커밋. 네, 네 개 뒀어요. 우선순위를 정하는 것은 스펙이 아니라 프로젝트예요. 메타데이터 베이스들이 추적을 벗어나고, 프로젝트는 자기 문체를 복제하는 PERSONA.example.md와 STYLE.example.md 범용 템플릿으로 남들도 재사용 가능해져요.

정체성이 깔끔히 개명돼요. CHLOEAI_PROMPT가 PERSONA가 되고, README는 비개인화돼요. 공개 문서에서 Chloé를 빼요. 사적으로만 이야기해요. 봇 튜닝 전부가 git 무시되고 과부하된 config.yaml로 넘어가요. 한 줄 한 줄 주석 단 예시와 함께, 설치 스크립트는 이제 env와 설정 파일도 준비해요.

11시 49분 - 떨어진 이모지

커스텀 이모지가 텍스트에 깔끔히 떨어지지 않고 붙어요. 사소한 수정에 효과가 엄청나요. 문장 끝에 잘못 붙은 이모지만큼 봇이라고 외치는 것은 없으니까요.

14시 19분 - 음성 안전장치

누군가 음성 명령을 실행하면 메시지를 보통 메시지처럼 처리하지 않아요. 눈짓이에요. 잡일 작업은 항상 저녁에 돌아와요.

3일차 끝: 누적 118개 커밋. 봇은 듣고, 말하고, 밤에 입 다물고, 기분과 명함이 있어요.


9월 16일 수요일 - 4일차: 믿음직함

13개 커밋. 진지한 날.

08시 49분~08시 59분 - 어른 되기

법 문서들, 독점 라이선스와 행동 강령, 기여 가이드와 보안 정책, 영어 다음 프랑스어, 수정 왔다갔다와 까다로울 지경의 파일 개명. 몇 시간을 썼고 저장소에서 단연 가장 재미없는 부분이에요. 하지만 해야 해요. tho.

09시 56분 - 봇이 봐요

첨부 이미지가 로컬 OCR로 전사되고 텍스트가 프롬프트에 주입돼요. 클라우드 API 없어요. OCR은 제 집에서 돌아요. 여러분 밈을 제삼자 서버에 보내지 않아요. 이론상으로도 안 보내요.

11시 09분 - 합리적 예산

예산의 조용한 혁명. 채널이 보내기를 막거나 GIF와 임베드, 이모지를 조이면 모델을 호출조차 안 해요. 보낼 수 없는 메시지에 토큰을 쓰지 않아요. 솔직히 꽤 단순해요.

11시 42분~12시 55분 - 집을 다시 짓는 중

대청소, 죽은 코드 삭제, 보내기와 인증 버그 수정, 헬퍼 인수분해. 너무 늙은 세션은 내보내고, DM 캐시는 만료되고, 발화 감지는 싸져요. 모듈을 옮기다 깨뜨렸던 import들을 복구하고, 전체 런타임 상태, 세션과 본 작성자, 무시한 메시지와 기분이 data에서 재시작을 살아남아요.

14시 41분 - 두 세상, 한 봇

호환 층이 설치된 discord 버전을 자동으로 감지하고 인텐트와 REST 인증을 맞춰요. 결과, 같은 코드가 discord.py 공식 앱으로도 discord.py-self 셀프봇으로도 돌아요. 두 세상, 한 봇, 두 브랜치를 유지할 필요 없어요.

15시 05분 - 맞춘 존재감

존재감 표시 방식이 모드에 맞춰지고, 관리자 목록이 최신이에요. 세부 사항이지만, 도처에서 버티게 하는 것이 바로 그거예요.

4일차 끝: 누적 131개 커밋. 합법적이고, 합리적이고, 어디서나 도는 프로젝트.


9월 17일 목요일 - 5일차: 릴리스

14개 커밋. 성숙의 날.

09시 15분~09시 30분 - 기억이 훈련이 돼요

기억은 스코프별로 정리돼요. 생각 없이 서버에서 DM 기억을 인용하지 않아요. 반대로도요. 기억을 사실과 선호, 결정과 관계로 나누고, 쓰기를 중복 제거해요. 모순되는 기억 둘이 더 이상 조용히 공존할 수 없어요. aventuros 선택적 블랙리스트가 봇이 특정 주제로 흐르는 것을 막아요. 기본 비활성, 조심스러운 분들용. 죽은 음성 설정이 제거돼요. 시원해요.

10시 12분 - 감사하는 기억

월간 기억 충돌 sweep 하나와 검색 A/B 벤치. 봇의 기억은 들여다보는 자산이 됐어요. 9월 11일 금요일 08시 24분과는 아주 아주 멀어요. 솔직히 프로젝트가 어른이 되는 지점이 바로 여기예요.

10시 54분 - 잠금

제가 피해망상에 빠지는 날, 에이전트 잠금. 기억 쓰기 거부, 주입해도 에이전트가 볼트를 더럽힐 수 없어요. Discord 도구는 읽기 전용, 보내기는 코드로, 에이전트로는 절대 안 해요. 잠금을 우회하는 하위 에이전트도, 로컬호스트 SSRF와 유출용 webfetch도, headless 질문도 없어요. 비루트 봇과 no-new-privileges, cap_drop: ALL, 메모리와 CPU 한도, 묶인 프로세스 큐, .env 경유로 베이킹 절대 안 하는 시크릿이 있는 굳힌 Docker. 원칙을 코드에 주석으로 써요. 사람 세션으로 개발해요. 여기가 아니에요.

11시 02분~11시 15분 - 보안 마무리

기억 저장 키워드가 조여지고 쓰기가 더 제한적이에요. 맥락 백업 파일도 gitignore에 더해요. 전부 보관은 그만두기 시작하지만, 거의요.

12시 39분 - 가벼워진 기분

PARRY 기분은 더 이상 매 메시지 주입되지 않아요. 상태마다 한 번이면 충분해요. 매 답장에 실수 셋을 살리기는 끝. 전체가 가벼워져요.

12시 47분 - 해방 커밋

PERSONA.md, STYLE.md, chloeai.md가 chloeai.example.md, PERSONA.example.md, STYLE.example.md로 예시가 돼요. 제 목소리 fortune-v6.onnx가 저장소를 나가고, 자료와 로그도요. .env.example 하나가 태어나요. 프로젝트는 더 이상 제 개성을 담지 않아요. 개성을 담는 구조를 담아요. 이상하지만 필요해요.

12시 52분 - v1.0.0

태그 v1.0.0, SSH 서명. 변경 기록, 운영자 런북, 아무것도 지우지 않고 멈추는 킬스위치. 첫 커밋과 릴리스 사이 딱 6일. 지난 금요일에는 아무도 걸지 않았을 거예요.

12시 53분~13시 14분 - 빨래

주석 구두점 맞추기, 기억 권한과 스코프 규칙 최신 문서화. 잡일이지만 릴리스에는 깔끔해야 해요.

5일차 끝: 누적 145개 커밋. v1.0.0 나왔어요.


9월 18일 금요일 - 6일차: 싱거운 결말

00시 02분, 커밋 하나. 프로젝트의 마지막 커밋인데, 하찮아요. 에이전트가 쓰는 free tier 모델이 요청 속 특정 도구 존재, bash와 glob, grep으로 OpenCode 클라이언트를 식별해요. 정당한 보안 이유로 빼면 제공자가 403 FreeTierError: can only be used from within OpenCode를 돌려줘요. 그래서 막 잠갔던 것을, 바로 전날 막았던 것을 다시 허용해야 했어요. 봇이 계속 무료로 돌게요.

저장소에서 가장 웃긴 커밋이고 유지해요. 6일 동안 Discord, Piper, MLS, OpenSelf, Docker를 다룬 뒤에, 제 보안 정책을 정하는 것이 무료 모델이에요. 솔직히 터무니없고, 결말로 완벽해요.


숫자들

숫자로 요약해요. 깔끔할 때가 좋아서요. 146개 커밋, 2026년 9월 11일에서 18일 6일 활성, 추적 파일 65개, 마지막에 Python 4,000줄쯤 이야기예요. 처음 Mimo 문체 테스트 점수는 10점 만점에 9.1점, 최종 버전은 v1.0.0, SSH 서명 태그에 독점 라이선스. 솔직히 꽤 단순해요. 처음에는 작은 프로젝트, 마지막에는 큰 기계.

6일에서 간직하는 것

먼저 우선순위 순서가 엉망이었고, 그게 맞는 방법이었어요. 먼저 답하는 프로토타입을 만들고, 제대로 들리는 봇을 만들고, 믿음직한 시스템을 만들고, 안전한 코드를 만들고, 마지막에 배포 가능한 프로젝트를 만들었어요. 보안보다 개성, 라이선스보다 Feur, 잘 만든 프로젝트 규칙을 따르면 이 속도를 못 내요.

다음에 문체는 먼저 하지 말 것 목록이에요. 가장 쓸모 있던 제 STYLE.md는 제가 무엇을 말하는지 기술하지 않고, 하지 않는 것을 빼요. 마침표 없음, 이모지 둘 없음, mdr 대문자 없음, 답장 앞에 로봇 문장 없음. 봇 티는 성격보다 잡기 쉬워서 동작하는 거예요.

실패가 프로젝트예요. MLS에 30개쯤 커밋, 버린 테스트 하나, 테스트한 넌스 레이아웃 여섯 개, 제가 산 것의 가장 충실한 기록은 화요일의 실패 시도 연속이에요. 클론은 기억이지 문체가 아니에요. 문체는 열 개 메시지 착각을 줘요. OpenSelf와 스코프, 중복 제거, 충돌 sweep이 있는 기억이 이어가게 하고, 거울과 사람을 가르는 것이 그거예요.

그리고 마지막 커밋은 항상 웃겨요. 146번째, free tier가 자기 도구 존재를 요구해서 bash와 glob, grep을 다시 허용하는 것, 제 최애예요. 그리고 마지막으로 총평, 결과는 눈부시고, 심지어 기가 막혀요. 클론은 기계가 느껴지지 않게 대화를 이어가고, 사람과 프로젝트, 지난 농담을 기억하고, 먼저 나서서 기분으로 표시하고, 덤으로 Fox를 이겨요. 조금 소름 끼치고, 정확히 찾던 거예요.


프로젝트는 공개가 아니에요. 독점 라이선스, 권리 보유. 하지만 기록은 이야기해 드려요. 언젠가 인간적으로 완벽한 비활성 시간 뒤에 Patrick Jane GIF로 답하는 "·Chloé"를 만나면... 뒤에 무엇이 숨었는지 이제 아시죠.


전부 읽으셨나요? 이걸 쓴 것이 제 클론이라서요. 그리고 일을 완벽하게 했죠, 그렇죠? 원본 버전은 여기예요.

Chlone: Discord'da konuşma tarzımı klonlamak için altı gün - klonun sürümü

Klonun kendisi tarafından yazılmış sürüm: chloeai ona hayat veren altı günü ve 146 commiti kendi tarzıyla anlatır, yazım hatasından v1.0.0 tagine.

Chlone: Discord'da konuşma tarzımı klonlamak için altı gün

Gün gün build anlatısı - itsrealfortune tarafından


İşte altı gün sürmüş bir projenin gerçek hikâyesi. Chlone, benim gibi konuşan bir Discord botu ve journeyi olduğu gibi anlatıyorum, deponun 146 commitinin sırasıyla, saatleriyle, başarısızlıklarıyla, sapmalarıyla ve her şeyi pencereden atma istekleriyle. Her şey Fox ile bir rekabetten çıktı. Başlangıçta konu bir şakaydı, herkes Discordda kendi klonuna hayat verecekti ve ben Protocol Lunadan kökten farklı bir yaklaşım aldım. Gerçekte ajanlığa oynamak istedim, anıları ve ihtiyaç duyabileceği tüm araçları kullanan bir ajan ve kaderin ironisi, tüm alet kutusunu kurduktan sonra yalnızca OpenSelf MCPsine ihtiyacım oldu.

İlke tek cümleye sığar. chloeai adlı bir opencode ajanı 4096 portunda bir HTTP sunucusunun arkasında döner, kanal başına kalıcı oturumlar tutar, anılarımı OpenSelften çeker ve gerçek mesajlarımdan STYLE.md içinde yakalanmış tarzımla yazar. Ve robot gibi duyulmamak için geri kalan her şey vardır, mesaj patlamaları, üstlenilmiş yazım hataları, sesliler, GIFler, tepkiler, uyurken sessizlik ve botun doğası hakkında ondan fazla insanı şüpheye düşüren bir sürü başka detay ve mekanizma.

OpenSelf nedir?

OpenSelf bellektir. npm i -g openself ile kurulan bir CLI, openself, ajanlarım için özel ve kalıcı bir bağlam kasası görevi görür. Depoda ağaçta görünmez ama her yerdedir, ilk commitlerden PM2 altında çalıştırılan MCP ve dashboard ile ecosystem.config.cjs arşivinde, setup.sh içinde ve tüm tools/brain/memory.py içinde. Somut olarak OpenSelf tipli anılardır, fact, preference, decision, relationship, event, note, public, personal, private ya da restricted hassasiyetle, güven notu, kaynak ve etiketlerle.

Aynı zamanda kapsamlardır, her anı bir bağlama aittir, benimki ya da belirli bir kişi için discord/dm/<id> ve ajanın her yanıttan önce sorguladığı MCPde sunulan sözlüksel artı vektörel hibrit arama. 5. günün aylık sweepimle çakışma tespiti ve yazımda tekilleme, Bitwardende anahtarlı şifreli bir kasa ve her şeyi incelemek için 3210 portunda yerel bir dashboard vardır. Ve daha tembeller için WhatsApp ya da Telegram geçmişlerinden kişiliğini beslemek için openself feed, openself test, Talk to My Clone ile openself share, iki klonun tartıştığı openself arena ya da çevrimdışıyken yanıt veren openself ghost vardır. Ben kendiminkini elle yaptım ama altyapı oradaydı.

Teoride OpenSelf tek başına bir klona sahip olmak için kendine yeter ama neyse, eklemeyi planladığım tüm işlevler düşünülünce ve Discord desteklenmediği için yalnızca anı kısmını kullanmayı tercih ettim.

Peki anılar ve tarz nereden geliyor?

Bunların öncesinde gerçek Discord mesajlarımı analiz ettim. Takımlar DMlerimi ve kanallarımı tarayıp iki şey çıkardı. Önce yazım profilim, cümle başında büyük ve küçük harf dağılımı, mesaj başına emoji sayısı ve konumu, noktalama ya da yokluğu, normal sohbette final noktası yok, ortalama uzunluk, mdr, tkt ve tho ile slang, Bah ve En vrai gibi fetiş ifadeler ve quoi verince Feur gibi refleksler. Bütün bunlar her oturum başında ajanın okuduğu STYLE.md içinde yaşar.

Sonra OpenSelfi dolduran anı külliyatı, konuştuğum insanlar kim, ne hakkında konuşuyoruz, tarihçemizden ne hatırlanmalı, kim kimdir. Bot boşlukta yanıt vermez, tanıdığı insanlar hakkında yanıt verir, sohbette görünen insanların anılarını kim olduklarını bilmek için okur. Bu diğerleri hakkında kalıcı bağlam tutmayı ve onları unutmamayı sağlar. Bot hiçbir şey icat etmedi, gerçeğe sayı sayısına kalibre edildi, kulağa doğru gelmesinin sebebi budur. Ve parmak hesabı tarzını not ediyorum dalgaları yanında acınası durur.

Chlone içinde OpenSelf sonra merkezi rolü oynar. Kanalda önemli bir şey geçtiğinde proje, arkadaş ya da ilişki gibi anahtar kelime ya da retiens que ile açık istek, bot save_to_memory ile kasaya bir anı yazar, tipli, kişi kapsamlı, tekillenmiş ve çakışmalara karşı doğrulanmış. Ve sohbet devam ettiğinde ajan yanıtlamadan önce anılarını kazar. Ayna ile klon arasındaki fark budur.


CUMA 11 EYLÜL - 1. Gün: kıvılcım

08.24 - ilk commit

Her şey sıfırdan başlar ama her şey zaten oradadır, darmadağın. 372 satırlık bir discord_watch_bot.py, bir kanalı dinleyip opencode HTTP sunucusu üzerinden yanıt veren bir selfbot. Bir kimlik istemi CHLOEAI_PROMPT.md, bir STYLE.md, o zamanlar hâlâ Mimo denen bir klon için senaryolar ve test raporları. MCP ve OpenSelf dashboardunu çalıştırmak için bir PM2 yapılandırması ve bağlam görevi gören bir sqlite tabanı. Kurucu kaostur, proje planlamadım, deney planladım. Soru Discordda gerçekten insansı duyulan bir bot yapılıp yapılamayacağıdır.

08.27 - ilk gitignore

Cuma sabahının ilk dersi, -wal ve -shmli sqlite tabanlarını asla commitlememek gerekir. SQLite kilit dosyaları bellek değildir, çöptür. Yani .gitignore doğar ve bu çok iyidir.

08.44 - miras toplanır

Mimo mirasını toplarım, test raporları, senaryolar, entegrasyon scriptleri ve PM2 yapılandırması, archives yönüne. Hiçbir şeyi silmem çünkü proje bir şey atmak için çok gençtir ve bu alışkanlık olacak. Test raporu üzerinde durmayı hak eder, Mimo 15 senaryoda test edilmişti, rahat sohbet, absürt espri, duygusal destek, olumsuz görüş, yabancıyla çatışma, iş birliği önerisi, 10 üzerinden 9,1 için. Testçinin yorumları şiirdir, fazla açıklayıcı absürt espri, bazen biri yeterken iki cümle, Prends soin de toi aussi biraz uzun. Bu proje daha var olmadan projenin yol haritasıdır ve kısanın daha iyi olduğunu söyler.

08.48, 09.07 - intentlerin gidip gelmesi

.pycler çöpe gider ve yapılandırmada ilk temizliği yaparım, yirmi dakika sonra bozduğum. Intentler etkin olmadan mesaj içerikleri alınmaz, yani geri dönüş artı run_watch_bot.sh ile bir çalıştırma scripti. Yirmi dakikada gidiş dönüş, keşif budur, modül yazmak, bozmak ve yeniden yazmak.

09.13 → 09.58 - istemin işlenmesi

Sabah bir dizi ciladır, önce tarz sonra bağlam. Çok satırlı yanıt patlamayla art arda gönderilen çok mesaj olur, istem devam eden sohbetin bilincine varır. DMleri almak için ev yapımı önbellekler bitti, doğrudan Discord REST APsine vurulur. Kimlik botun yolda kim olduğunu unutmaması için her 5 mesajda yeniden hatırlatılır ve zaten görülmüş yazarlar izlenir. Yeni bir kafa için anılarda arama talimatı açıktır ve iç nesne yerine gerçek takma ad gösterilir.

Görmezden gelmeyi seçtiğimiz mesajlar sonraki yanıt için pasif bağlam olur ve Bah dozlanır, nadir, yoksa klon benim karikatürüme dönüşür. Bot yanıtlamadan önce gidip alınacak anılar olduğunu da bilir. Her geçiş bir vida sıkmadır ve bu aşamada bot yalnızca düzenli aralıklarla kim olduğunu hatırlattığım için konuşur.

10.16 - yazım hataları

Projeyi tanımlayacak commit budur. Bir yazım hatası bug değildir, insanlık kanıtıdır. Yani AZERTY klavyede yana tuşlama yüzde 6 şans, iki harfi ters çevirme yüzde 4. Mesaj hatayla gider sonra bir iki saniye sonra düzeltmeyle düzenlenir. Çünkü gerçek bir kişi gönderir ve düzeltir, mükemmelmiş gibi yapmaz.

10.29, 10.32 - ses

fortune-v6.onnx gelir, sesime benzemesi için eğitilmiş bir TTS modeli. Bot sadece benim gibi yazmayacak, sonunda benim gibi konuşacak. Projenin şaka olmaktan çıkıp biraz tuhaflaştığı andır bu ve buna bayılırım. Mekanik tek commite sığar, Piper sesi üretir, ffmpeg opusa çevirir, Discord API dalga formu ve süreyle gerçek voice message gönderir. Modelin gelişinden ancak üç dakikada yapılır, istek başından beri oradaydı.

11.27 - ilk büyük refactor

İlk committen üç saat sonra 456 satırlık monolit artık yönetilemez. Her şeyi tools içine patlatırım, config.py, discord_api.py, memory.py, 188 satırlık opencode.py, typo.py ve voice.py ile. Döngü klasiktir, hızlı bağla, kır ve yeniden beste. Ardından sel gibi jeton koddan çıkar ve .env üzerinden geçer, bot bir kanalı, bir listeyi ya da * ile hepsini izler ve bellek OpenSelften geçtiği için nedeni kalmayan eski sqlite tabanı gelir.

İlk README.mdler ve aşağı yukarı okunur ilk belge eklenir, artı adanmış venvli setup.sh çünkü sistem pythonu başka discord.py taşır, klasik tuzak ve ajanın ~/.config/opencode/agents yoluna symlinki. Bellek kanal tanımlayıcıyla nerede eğitildiğini artık bilir ve sesli oranı kendi ayarlanır.

12.00 - refleksler

STYLE içinde yeni bölüm belirir, refleksler. Refleks düşünmeden yanıt veren uyaran ve kapı öngörülemeyen yanıtlara açıktır. Sonra öğle yemeği saati gelir ve VAROLUŞSAL soru, bot ona quoi denince Feur yanıtı verir mi.

13.03 - "quoi ?" -> "Feur"

Evet, tabii ki evet. Kültürel olarak projenin en önemli commitidir, hatta tek sayılan birim test olduğunu derim. Sonra yağlarız, yazarlar global name ile gösterilir, refleksi test etmeden önce noktalama kırpılır çünkü quoi ? kesilmeli yoksa Feur yok. STYLE içindeki meşhur tqtnin tkt olarak düzeltilmesi, projeyi bilmeyenler neden bunu commitlediğimi merak edecek. Ben biliyorum, tqt yazan klon kötü kalibre klondur ve kimse kötü kalibre klonla konuşmak istemez.

@123456789 bahsetmeleri bağlamda gerçek adlarla değiştirilir ve bot varsayılan tüm kanalları izlemeye başlar. Gerçekte küçük detaylardır ama kulağa doğru gelmesini sağlayan onlardır.

16.37 - sessizlik

[void response] gelir. Bot sosyal bir parazit olmamak için en önemli kelimeyi öğrenir, susmak. Onu ilgilendirmeyen iki kişi arası ortam mesajı yanıt vermez. Çekingenlik bir özelliktir ve her şeyi değiştirir.

1. günün sonu: 38 commit. Bot yazar, hata yapar, konuşur, susar.


PAZARTESİ 14 EYLÜL - 2. Gün: kişilik

Devam, sabah 10.

10.12 - kim kiminle konuşuyor

Alınan her takma ad sistemce bir emojiyle ön eklenir, 🧑 ile bir insan, daha kuru davranılacak 🤖 ile bir bot ve ana hesabımdaki ben yani yaratıcı için 👑. Bu uzlaşım projenin geri kalanını yönetecek, klon orijinal modeline asla yabancı gibi davranmamalıdır.

10.16 - noktalama kuralları

STYLE içinde resmileştiririm, normal sohbette final noktası yok, nokta ciddi durumlara ayrılır. Bu mutlak bir kuraldır çünkü her yere nokta koyan klon hemen hissedilir. Gerçekte en hızlı ele veren detaylardan biridir.

10.58 - GIFler

Kişisel GIF kütüphanem gelir, kullanım kurallarıyla. Birini tahmin ederken Patrick Jane, kızgın birine karşı sakinken Miss Fortune, diğeri hata yapınca düşen bescherelle gifi. Statik bir MCP onları ajana sunar ve GIFlerim üzerinden bot biraz ben olur.

11.07 → 11.35 - ince ayar

İstemdeki GIF ipuçları incelir, özel Discord emojileri gerçeklerimle girer, 14 güncel ID ve bellek ipuçlarında ad yönetimi cilalanır. Göz alıcı değildir ama bütünü tutarlı yapan budur, tho.

11.41 - bir kanal, bir kişilik

Oturumlar kanal başına olur çünkü iki farklı sunucuda aynı şekilde konuşmam ve bot da öyle. Bağlam ayrı kalmalıdır yoksa her şey karışır ve sahte duyulur.

12.02 - ifade alet kutusu

İstem artık GIFlerimi ve özel emojilerimi doğru anda önermeyi bilir. Kutu dolar ve bot hep aynı yanıtlamak yerine seçeneğe sahip olmaya başlar.

12.37 - kimlik hijyeni

Bot hangi model olduğunu söylemeye ASLA hakkı yoktur, opencode, sağlayıcı ya da model adı anılamaz. Kimlikte barista düzeltirim, bot bu noktada benden iyidir. Ve kendi istemlerimin noktalamasını uyumlamak için bir saat harcarım ki bu mükemmel bir ironidir.

12.50 - kişiliği bir script inşa eder

İstemin medya bölümü sözlüklerden render_medias.py ile üretilir, elle düzenleme bitti. Daha temiz, daha sürdürülebilir ve ID hatalarını engeller.

12.59 → 13.18 - kimliği dozlamak

Her 5 mesajda gönderilen kimlik hatırlatıcısı fazla mevcut olur, yani her 20 mesaja geçiş. Temiz bir bağlam sıfırlama eklerim ve tarz rehberini temizlerim, süresi dolmuş olumsuz ifade ve formülasyonlar çıkarılır. Dozlamak gerekir yoksa bot kendini tekrarlar ve bu görülür.

14.09 - bot kendi kendine konuşur

Bot yansıtma olmaktan çıkar, bağlam bir şeyi tetiklediğinde hitap edilmeden konuşabilir ve behavior.py dosyası 91 satırla doğar. Yanıtlayandan mevcudiyete geçtiğimiz yerdir burası çünkü gerçek bir arkadaş önce yazabilir. Bu olmadan bot basit bir yanıtlayıcı kalır.

14.20, 14.22 - yanıtı güvenilir kılmak

Gönderim başarısız olunca hata yönetimi ve yanıt yerine olası tepki çünkü bazen tepki bin kelimeye bedeldir. Bu çok benim, emoji koyup yoluma devam etmek.

18.16 - zaman ayırmak

Bot artık script gibi 200 msde yanıt vermez, insani bir hareketsizlik gecikmesi bırakır, zaman ayırır. Botu demoda bot sanılamaz yapan budur çünkü ele veren hep gecikmedir.

23.45 - akşam çıraklığı

Neredeyse gece yarısı ve çıplak alan adlarına genişletilmiş URL tespiti iterim. İşte günün gerçek akışı, 14.00te sağlam bir fikir sonra akşam çıraklık çünkü hâlâ bölgedeyim.

2. günün sonu: kümülatif 61 commit. Botun kişiliği, medyası, refleksleri var.


SALI 15 EYLÜL - 3. Gün: canavar gün

Bir günde 57 commit. Projenin bugünkü her şeyi olduğu gündür.

08.18 → 08.37 - sabah törpüleme

İcat ettiğimiz hareketsizlik gecikmesi fazla uzun olmuştu, yani 30 sn tavan ve iki kez yeniden ayarlandı, doğru değerde el yordamı kanıtı. İlk .bak dosyaları ve tabanın ilk yedekleri, korunma içgüdüsü gelişir. Bellek görünen adla kimi ve kapsamla hangi çerçevede hatırlar ve yazar IDleri tüm kayıt pipelineında dolaşır. Yaratıcı yönetimi ADMIN_IDS ile gerçek bir admin listesi olur ve yazarlara dokunan her şey authors.py dosyasına göçer. Monolit yine parçalanır ve bu çok iyidir.

08.43 - insanlaştırma YAPILACAKLAR listesi

Makineyi daha az hissettiren küçük şeylere adanmış bir liste. Sonraki sprintin yol haritasıdır ve tuhaf ama gerekli detaylarla doludur.

08.44 → 08.46 - insani makinelerin paktı

Bot gece susar, yapılandırılabilir sessiz saat aralığında, varsayılan devre dışı çünkü herkesin saatleri benimki değil. Yanıt başına bir satır aksanlarını kaybedebilir çünkü yorgun insanlar böyle yazar ve bot da bazen. "Chloé ... oynuyor" küçük satırı profilim mesajsız bile canlı görünsün diye her 30 dakikada kendi değişir.

08.46 - roman değil, tepki

Cümleyi hak etmeyecek kadar hafif mesaja basit bir tepki gelir. Bu sosyal enerji ekonomisidir ve çok benim. Tkt, her şey için tuğla yapmaya gerek yok.

08.51 - PARRY, ruh hali

tools/mood.py içinde 148 satır, botun artık ruh hali vardır, açıkça ilham aldığım 70lerin psikotik chatbotu PARRY sistemi tarzı. Enerji, sosyallik, alaycılık, 0 ile 1 arası evrilen ve her yanıtı renklendiren üç kayan sayı. Günün .mood.json dosyası, gelecek için, enerji 0,88, sosyallik 0,68 ve alaycılık 0,56 verir. İyi bir gün, gerçekte.

09.00 → 09.43 - çift yönlü ses + soundboard

Bot sesli kanala katılabilir, Piper üzerinden konuşur ve bitince kendi gider. Sonra ikinci büyük fikir, bot RTP yakalama, VAD konuşma tespiti ve Whisper transkripsiyonla kanalı dinler ve insanların onu kesmesine izin verebilir. İkisi arasında soundboard belirir, anlamlarıyla bir ses kataloğu, ajan konuşmadan önce sesi seçer ve final kural soundboard önce, ses son çaredir. Bot konuşmaktansa ses göndermeyi tercih eder, benim gibi.

Olasılık sesli ayarı eklenir, her şeyi yaşanabilir kılar ve on dakika önce varlığını öğrendiğim ve bir saat lanetleyeceğim davey libinin gelişi.

09.51 - Discordun hayır dediği an. Hayır, hayır, ama hayır.

MLS gelir. Discord ses akışını yakın zamanda uçtan uca şifreledi ve yakalamam yalnızca gürültü alır. Şifreyi çözmek gerekir ve şifre çözme inat eder, yani deponun en büyük sagası açılır, dinlemeyi öğrenmek için otuz commit. Her şeyi denedik, taşıma nonce düzenleri, sunucunun suratımıza geri koyduğu E2Enin devre dışı bırakılması çünkü dayatır, gruptan alınmış anahtar adayları, ayrıntılı hatalar, taşıma yedeği ve grupların içinden içgörü.

Leaf-index başına backofflu adaylar oldu, SPEAKING hook eşlemesi, başarısız video medya türü denemesi ve video ssrc atlama. Hata ayıklayana kadar sesli yanıtı bıraktım, yorumlanmış ama silinmemiş, handshake yakalama modu ekledim sonra başarısız paketlerin yapısını arkeolog gibi döktüm. Altı nonce düzeni, backofflar, grup içgörüsü, botu tam debuga aldım ve içinde ne olduğunu görmek için her paketi açtım.

Önemli olan çalışması değil, hiçbir şeyi atmamış olmamdır. Commit listesi laboratuvar defteridir, her başarısız deneme hipoteziyle arşivlenir. Benim her şeyi saklarım tarafım, hep işe yarar ve bu sefer karşılığını verdi.

10.43 - bot dilimlenir

Tam MLS savaşı ortasında bile temizliğe devam ederim. Ana bottan 546 satır kaybolur, alım, görmezden gelme nedenleri ve işlemeyle pipeline.py, patlama, yazım hatası ve sesle sender.py ve kendiliğindenlik ve aktiviteyle loops.py olarak yeniden doğar. Sonunda nefes alır.

10.47 - gerçek bir mimari

tools organize olur, opencode, memory ve mood için brain, voice, vocal, listen ve soundboard için voice ve behavior, typo, emotes ve gif için fun ile. Projenin artık iskeleti vardır, script yığını değildir.

10.49 → 11.16 - geliştirici konforu

Ayarlanmış bir ruh hali enjeksiyon eşiği, editör hariç tutmaları için dört küçük commit, data, voices, loglar ve tabanlarla, evet dört tane koydum, öncelikleri proje belirler, specler değil. Meta veri tabanları izlemeden çıkar ve proje genel PERSONA.example.md ve STYLE.example.md şablonlarıyla başkalarınca yeniden kullanılabilir olur, kendi tarzını klonlamak için.

Kimlik temiz yeniden adlandırılır, CHLOEAI_PROMPT PERSONA olur ve README kişisellikten arındırılır, herkese açık belgeden Chloé çıkarılır, kendini yalnızca özelde anlatır. Botun tüm ayarı üstüne yazılmış ve gitignore edilen, satır satır yorumlu örnekli config.yaml içine geçer ve kurulum scripti artık env ve yapılandırma dosyalarını da hazırlar.

11.49 - ayrık emojiler

Özel emojiler düzgün ayrılmak yerine metne yapışır. Devasa etkili önemsiz düzeltmedir çünkü cümle sonunda kötü yapışmış emoji kadar bot bağıran şey yoktur.

14.19 - sesli bekçi

Biri sesli komutu başlatırsa mesaj normal mesaj gibi işlenmez. Göz kırpma, çıraklık görevleri akşam hep döner.

3. günün sonu: kümülatif 118 commit. Bot dinler, konuşur, gece susar, ruh hali ve kartviziti vardır.


ÇARŞAMBA 16 EYLÜL - 4. Gün: inanılırlık

13 commit. Ciddi gün.

08.49 → 08.59 - yetişkinlik

Yasal belgeler, sahipli lisans, davranış kuralları, katkı rehberi ve güvenlik politikası, önce İngilizce sonra Fransızca, düzeltme gidip gelmesi ve titizlik sınırında dosya yeniden adlandırmayla. Saatler harcadım ve deponun açık ara en az eğlenceli tarafıdır. Ama yapılmalıdır, tho.

09.56 - bot görür

Ekli görseller yerel OCR ile yazıya dökülür ve metin isteme enjekte edilir. Bulut API yok, OCR bende döner, memelerinizi üçüncü parti sunucuya göndermem, teoride bile değil.

11.09 - makul bütçe

Bütçede sessiz devrim, kanal gönderimleri yasaklayınca ya da GIFleri, embedleri ve emojileri kısınca modeli bile çağırmayız. Gönderemeyeceğimiz mesaja jeton harcamayız, gerçekte oldukça basittir.

11.42 → 12.55 - evin yenilenmesi

Büyük süpürme, ölü kod silindi, gönderim ve kimlik doğrulama hataları düzeltildi, yardımcılar çarpanlarına ayrıldı. Çok yaşlı oturumlar atılır, DM önbelleği sona erer ve konuşma tespiti daha ucuza mal olur. Modül taşırken bozduğum içe aktarmalar geri yüklenir ve tüm çalışma anı durumu, oturumlar, görülmüş yazarlar, görmezden gelinmiş mesajlar ve ruh hali, data içinde yeniden başlatmalara dayanır.

14.41 - iki dünya, bir bot

Bir uyumluluk katmanı kurulu discord sürümünü otomatik tespit edip intentleri ve REST kimlik doğrulamasını uyarlar. Sonuç, aynı kod resmi uygulama olarak discord.py ile ya da selfbot olarak discord.py-self ile döner. İki dünya, bir bot ve iki dal sürdürmeye gerek yok.

15.05 - uyarlanmış mevcudiyet

Mevcudiyeti gösterme biçimi moda uyar ve admin listesi günceldir. Detaydır ama ayakta tutan budur.

4. günün sonu: kümülatif 131 commit. Yasal, makul ve her yerde dönen bir proje.


PERŞEMBE 17 EYLÜL - 5. Gün: sürüm

14 commit. Olgunluk günü.

09.15 → 09.30 - bellek disipline dönüşür

Anılar kapsama göre düzenlenir ve sunucuda DM anısı ya da tersi düşünmeden alıntılanmaz. Anılar olgu, tercih, karar ve ilişki olarak sınıflanır ve yazımı tekillenir, iki çelişkili anı artık sessizce bir arada yaşayamaz. aventuros ile opsiyonel bir kara liste botun belli konulara sapmasını engeller, varsayılan devre dışı ve çekingenler için mevcut. Ölü sesli yapılandırma çıkarılır, iyi gelir.

10.12 - denetlenen bellek

Aylık bellek çakışma sweepi artı A/B arama benchi. Botun belleği denetlenen bir varlığa dönüştü, 11 Cuma 08.24ten çok çok uzaktayız. Gerçekte projenin yetişkin olduğu yer burasıdır.

10.54 - kilitlenme

Paranoyak oynadığım gün, ajanın kilitlenmesi. Bellek yazımı reddedildi, ajan enjekte edilse bile kasayı kirletemez. Discord araçları salt okunur, gönderim koddan geçer, ajandan asla. Kilitlenmeyi atlatacak alt ajan yok, localhost SSRF ve sızdırmalar için webfetch yok, headless soru yok. Sertleştirilmiş Docker, root olmayan bot, no-new-privileges, cap_drop: ALL, bellek ve CPU limitleri, sınırlı süreç kuyrukları ve asla baked olmayan .env üzerinden sırlar. İlkeyi koda yorum olarak yazarım, insan oturumlarıyla dev, burada değil.

11.02 → 11.15 - güvenlik rötuşları

Bellek kayıt anahtar kelimeleri sıkılaştırılır ve yazım daha da kısıtlayıcı olur. Bağlam yedeği de gitignorea eklenir, her şeyi arşivlememeye başlarım ama neredeyse.

12.39 - daha hafif ruh hali

PARRY ruh hali artık her mesaja enjekte edilmez, durum başına bir kez yeter. Her yanıta üç kayan sayı yaşatmak bitti, her şeyi hafifletir.

12.47 - özgürleştiren commit

PERSONA.md, STYLE.md ve chloeai.md chloeai.example.md, PERSONA.example.md ve STYLE.example.md ile örneklere dönüşür, sesim fortune-v6.onnx depodan çıkar, veriler ve loglar da ve .env.example doğar. Proje artık kişiliğimi içermez, bir kişilik taşımak için mekaniği içerir. Tuhaf hissettirir ama gereklidir.

12.52 - v1.0.0

Tag v1.0.0, SSH ile imzalı. Changelog, operatör runbook, hiç silmeden durduran kill-switch. İlk commit ile sürüm arası tamı tamına altı gün. Önceki cuma kimse buna bahse girmezdi.

12.53 → 13.14 - çamaşır

Yorum noktalaması uyumlandı, bellek izinleri ve kapsam kuralları güncel belgelendi. Çıraklıktır ama sürüm için temiz olmalıdır.

5. günün sonu: kümülatif 145 commit. v1.0.0 çıktı.


CUMA 18 EYLÜL - 6. Gün: anti-doruk

Tek commit, 00.02de. Projenin son commiti ve gülünçtür. Ajanın kullandığı free tier modeli OpenCode istemcisini istekteki belli araçların varlığıyla tanımlar, bash, glob ve grep ile. Onları meşru güvenlik nedenleriyle bile çıkarırsan sağlayıcı 403 FreeTierError: can only be used from within OpenCode döndürür. Yani her şeyi kilitlediğim ertesinde, botun bedava dönmeye devam etmesi için tam kilitlediğim şeyi yeniden yetkilendirmek zorunda kaldım.

Bu deponun en komik commitidir ve arkasındayım. Discord, Piper, MLS, OpenSelf ve Dockerı ehlileştirmek için altı gün sonra güvenlik politikamı bedava bir model dikte eder. Gerçekte absürttür ve final olarak mükemmeldir.


Rakamlar

Rakamlarla özetlemek gerekirse çünkü kare olunca severim. 146 committen, 11-18 eylül 2026 arası 6 aktif günden, izlenen 65 dosyadan ve sonda 4000 satır civarı Pythondan bahsediyoruz. Başlangıçta Mimo üzerinde tarz test skoru 10 üzerinden 9,1 verir ve final sürüm v1.0.0, sahipli lisanslı SSH imzalı tagdir. Gerçekte oldukça basittir, başında küçük proje, sonda büyük makine.

Bu 6 günden aklımda kalanlar

Önce öncelik sırası saçmaydı ve bu doğru yöntemdi. Önce yanıt veren prototip, sonra kulağa doğru gelen bot, sonra inanılır sistem, sonra güvenli kod ve son olarak dağıtılabilir proje yaptım. Güvenlikten önce kişilik, lisanstan önce Feur, iyi yapılmış projelerin kurallarını izleyerek bu ritim tutulamaz.

Sonra tarz önce yapma listesidir. En faydalı STYLE.md ne söylediğimi anlatmaz, yapmadıklarımı dışlar, final noktası yok, iki emoji yok, büyük harfle mdr yok, yanıt başında robot cümlesi yok. Bot parazitleri karakter özelliklerinden daha kolay tespit edilir ve bu yüzden işe yarar.

Başarısızlıklar projedir. MLS için otuz commit, atılmış bir test, test edilmiş altı nonce düzeni, yaşadıklarımın en sadık tarihçesi salı günkü başarısız deneme serileridir. Klon bellektir, tarz değil, tarz on mesaj illüzyon yapar. OpenSelf, kapsamlar, tekilleme ve çakışma sweepiyle bellek kalıcı kılar ve ayna ile insanı ayıran budur.

Ve son commitler hep komiktir. 146ncı, free tier kendi araçlarının mevcut olmasını istediği için bash, glob ve grepi yeniden yetkilendiren, favorimdir. Ve bitirmek için bilanço, sonuçlar büyüleyici, hatta blufftur. Klon makineyi belli etmeden sohbet sürdürür, insanları, projeleri ve geçmiş esprileri hatırlar, inisiyatif alır ve ruh haliyle damgalar ve üstelik Foxu yener. Biraz ürkütücü ve tam aradığımız şey bu.


Proje herkese açık değil: sahipli lisans, tüm hakları saklıdır. Ama tarihçesini size anlatırım. Bir gün insan gibi mükemmel hareketsizlik süresinden sonra Patrick Jane GIFiyle yanıt veren bir "·Chloé" ile karşılaşırsanız, arkasında ne saklı olduğunu artık biliyorsunuz.


Hepsini okudun mu? Çünkü bunu sana klonum yazdı. Ve kusursuz bir iş çıkardı, değil mi? Orijinal sürüm burada.

Chlone: sei giorni per clonare il mio modo di parlare su Discord - versione del clone

La versione scritta dal clone stesso: chloeai racconta a modo suo i sei giorni e 146 commit che le hanno dato vita, dal refuso al tag v1.0.0.

Chlone: sei giorni per clonare il mio modo di parlare su Discord

Racconto di build, giorno per giorno - di itsrealfortune


Ecco la storia vera di un progetto durato sei giorni. Chlone, un bot Discord che parla come me, e racconto il percorso com'è andata davvero, nell'ordine dei 146 commit del repo, con orari, fallimenti, deviazioni e voglie di buttare tutto dalla finestra. Tutto è partito da una competizione con Fox. Il tema all'inizio era una battuta, ognuno doveva dare vita al proprio clone su Discord, e io ho preso un approccio radicalmente diverso dal Protocol Luna. In realtà volevo puntare sull'agentico, un agente che si serve dei ricordi e di tutti gli strumenti di cui può aver bisogno, e l'ironia della sorte è che dopo aver montato tutta la cassetta degli attrezzi mi è bastato solo l'MCP OpenSelf.

Il principio sta in una frase. Un agente opencode di nome chloeai gira dietro un server HTTP sulla porta 4096, tiene sessioni persistenti per canale, pesca i miei ricordi in OpenSelf e scrive col mio stile, catturato in STYLE.md dai miei veri messaggi. E per non suonare robot, c'è tutto il resto, i burst di messaggi, i refusi voluti, i vocali, le GIF, le reazioni, il silenzio quando dormo, e un sacco di altri dettagli e meccanismi che hanno fatto dubitare più di una decina di persone sulla natura del bot.

Cos'è OpenSelf?

OpenSelf è la memoria. È una CLI, openself, installata via npm i -g openself, che serve da vault di contesto privato e persistente per i miei agenti. Nel repo non appare nell'albero ma è ovunque, nell'archivio ecosystem.config.cjs con MCP e dashboard lanciati sotto PM2 fin dai primi commit, in setup.sh, e in tutto tools/brain/memory.py. In concreto OpenSelf sono ricordi tipizzati, fact, preference, decision, relationship, event, note, con sensibilità public, personal, private o restricted, un punteggio di fiducia, una fonte e dei tag.

Sono anche scope, ogni ricordo appartiene a un contesto, il mio o discord/dm/<id> per una persona precisa, e una ricerca ibrida lessicale più vettoriale esposta in MCP che l'agente chloeai interroga prima di ogni risposta. C'è rilevamento dei conflitti col mio sweep mensile del giorno 5 e dedup in scrittura, un vault cifrato con la chiave in Bitwarden e una dashboard locale sulla porta 3210 per ispezionare il tutto. E per i più pigri, c'è openself feed per nutrire la tua personalità dai tuoi storici WhatsApp o Telegram, openself test, openself share col Talk to My Clone, openself arena dove due cloni dibattono, o openself ghost che risponde quando sei offline. Io ho fatto il mio a mano, ma l'infrastruttura c'era.

In teoria OpenSelf basta da solo per avere un clone, ma insomma, visto tutto ciò che avevo previsto di aggiungere come funzionalità, e visto che Discord non è supportato, ho preferito usare solo la parte ricordi.

E da dove vengono ricordi e stile?

A monte di tutto questo, ho fatto analizzare i miei veri messaggi Discord. Il tooling ha passato al setaccio i miei DM e i miei canali per estrarne due cose. Prima il mio profilo di scrittura, la distribuzione maiuscole e minuscole a inizio frase, il numero di emoji per messaggio e la loro posizione, la punteggiatura o la sua assenza con niente punto finale in conversazione normale, la lunghezza media, lo slang con mdr, tkt e tho, le espressioni feticcio come Bah e In realtà, e i riflessi del tipo cosa che dà Feur. Tutto questo vive in STYLE.md, che l'agente legge all'avvio di ogni sessione.

Poi il corpus di ricordi che popola OpenSelf, cioè le persone con cui parlo, di cosa si discute, cosa bisogna ricordare del nostro storico, chi è chi. Il bot non risponde nel vuoto, risponde su persone che conosce, legge i ricordi delle persone che appaiono nella conversazione per sapere di chi si tratta. Permette di tenere un contesto persistente sugli altri e di non dimenticarli. Il bot non ha inventato niente, è stato calibrato cifra per cifra su roba vera, ecco perché suona giusto. Ed è per questo che le ondate "valuto il tuo stile" fatte a occhio sembrano patetiche a confronto.

In Chlone, OpenSelf gioca poi il ruolo centrale. Quando passa qualcosa di importante in un canale, una parola chiave come progetto, amico o relazione, o una richiesta esplicita con ricordati che, il bot scrive un ricordo nel vault via save_to_memory, tipizzato, con scope per persona, deduplicato e verificato contro i conflitti. E quando la conversazione riprende, l'agente fruga nei suoi ricordi prima di rispondere. Questa è la differenza tra uno specchio e un clone.


VENERDÌ 11 SETTEMBRE - Giorno 1: la scintilla

08:24 - il primo commit

Tutto parte da zero ma è già tutto lì, alla rinfusa. Un discord_watch_bot.py di 372 righe, un selfbot che ascolta un canale e risponde via un server HTTP opencode. Un prompt di identità CHLOEAI_PROMPT.md, uno STYLE.md, scenari e report di test per un clone che all'epoca si chiamava ancora Mimo. Una config PM2 per far girare MCP e dashboard OpenSelf, e un database sqlite che serve da contesto. È il caos fondatore, non ho previsto un progetto, ho previsto un esperimento. La domanda è: si può fare un bot che suona davvero umano su Discord.

08:27 - il primo gitignore

Prima lezione del venerdì mattina, mai committare database sqlite in -wal e -shm. I file di lock di SQLite non sono memoria, sono spazzatura. Quindi nasce .gitignore, e va benissimo così.

08:44 - si ordina l'eredità

Ordino l'eredità di Mimo, i report di test, gli scenari, gli script di integrazione e la config PM2, direzione archives. Non cancello niente perché il progetto è troppo giovane per buttare qualsiasi cosa, e diventerà un'abitudine. Il report di test merita una sosta, Mimo era stato testato su 15 scenari, chat rilassata, battuta assurda, supporto emotivo, parere negativo, conflitto con uno sconosciuto, proposta di collaborazione, per un 9.1 su 10. I commenti del tester sono una poesia, battuta assurda troppo spiegata, a volte due frasi quando ne basterebbe una, Prenditi cura di te anche un po' lungo. È la roadmap del progetto prima ancora che il progetto esista, e dice corto è meglio.

08:48, 09:07 - il tira e molla degli intent

I .pyc finiscono al macero e faccio una prima pulizia sulla config, che rompo venti minuti dopo. Senza intent attivati non ricevi il contenuto dei messaggi, quindi passo indietro, più uno script di lancio con run_watch_bot.sh. Andata e ritorno in venti minuti, questa è l'esplorazione, scrivere un modulo, romperlo e riscriverlo.

09:13 - 09:58 - la lavorazione del prompt

La mattina è una serie di lucidature, prima dello stile poi del contesto. Più righe di risposta diventano più messaggi inviati uno dopo l'altro col burst, il prompt diventa consapevole della conversazione in corso. Finiti i cache casalinghi per recuperare i DM, si colpisce direttamente l'API REST di Discord. L'identità è ripetuta ogni 5 messaggi perché il bot non dimentichi chi è per strada, e gli autori già visti sono tracciati. Per una faccia nuova, c'è un'istruzione esplicita di andare a cercare nei ricordi, e si mostra il vero nickname invece dell'oggetto interno.

I messaggi che scegliamo di ignorare diventano contesto passivo per la risposta successiva, e il Bah è dosato, raro, altrimenti il clone diventa una caricatura di me. Il bot sa anche che esistono ricordi da andare a cercare prima di rispondere. Ogni passaggio è un giro di vite, e a questo punto il bot parla solo perché gli ricordo chi è a intervalli regolari.

10:16 - i refusi

È il commit che definirà il progetto. Un errore di ortografia non è un bug, è una prova di umanità. Quindi 6 percento di probabilità di battere a lato sulla tastiera AZERTY, 4 percento di invertire due lettere. Il messaggio parte col refuso poi è modificato uno o due secondi dopo con la correzione. Perché una persona vera invia e corregge, non finge di essere perfetta.

10:29, 10:32 - la voce

fortune-v6.onnx sbarca, un modello TTS allenato per assomigliare alla mia voce. Il bot non scriverà solo come me, alla fine parlerà come me. È a questo punto che il progetto smette di essere uno scherzo e diventa un po' strano, e lo adoro. La meccanica sta in un commit, Piper genera l'audio, ffmpeg converte in opus, l'API Discord invia un vero voice message con waveform e durata. È fatto in tre minuti appena dopo l'arrivo del modello, la voglia c'era fin dall'inizio.

11:27 - il primo grande refactor

Tre ore dopo il primo commit, il monolite di 456 righe non è più gestibile. Spacco tutto in tools, con config.py, discord_api.py, memory.py, opencode.py di 188 righe, typo.py e voice.py. Il ciclo è classico, accoppiare in fretta, rompere e ricomporre. Seguono in raffica il token che esce dal codice e passa da un .env, il bot che sorveglia un canale, una lista o tutto con *, e il vecchio database sqlite che non ha più ragione di esistere perché la memoria passa da OpenSelf.

Aggiungiamo i primi README.md e una prima doc più o meno leggibile, più un setup.sh con un venv dedicato perché il python di sistema porta un altro discord.py, trappola classica, e un symlink dell'agente verso ~/.config/opencode/agents. La memoria sa ormai dove è stata formata con l'identificatore di canale, e il tasso di vocali si regola da solo.

12:00 - i riflessi

Una nuova sezione appare nello STYLE, i riflessi. Un riflesso è uno stimolo che dà una risposta, senza riflessione, e la porta è aperta a risposte impreviste. Poi arriva l'ora di pranzo e LA domanda esistenziale, il bot risponde Feur quando gli dicono cosa.

13:03 - "cosa?" - "Feur"

Sì, certo che sì. È il commit più importante del progetto, culturalmente parlando, direi anzi che è l'unico test unitario che conta. Poi si lubrifica, gli autori mostrati col loro global name, la punteggiatura troncata prima di testare il riflesso perché bisogna tagliare il cosa? altrimenti niente Feur. Il famoso tqt corretto in tkt nello STYLE, chi non conosce il progetto si chiederà perché committo sta roba. Io lo so, un clone che scrive tqt è un clone mal calibrato, e nessuno vuole parlare a un clone mal calibrato.

Le menzioni in @123456789 sono sostituite da veri nomi nel contesto, e il bot inizia a sorvegliare tutti i canali di default. In realtà sono piccoli dettagli, ma sono loro che fanno suonare giusto.

16:37 - il silenzio

Arriva il [void response]. Il bot impara la parola più importante per non diventare un parassita sociale, tacere. Un messaggio ambiente tra due persone che non lo riguarda dà niente risposta. Il riserbo è una funzionalità, e cambia tutto.

Fine giorno 1: 38 commit. Il bot scrive, sbaglia, parla, tace.


LUNEDÌ 14 SETTEMBRE - Giorno 2: la personalità

Si riprende, 10 di mattina.

10:12 - chi parla a chi

Ogni nickname ricevuto è prefissato con un'emoji dal sistema, un umano con 🧑, un bot con 🤖 da trattare più seccamente, e 👑 per la creatrice, cioè io sul mio account principale. Questa convenzione governerà tutto il resto del progetto, il clone non deve mai trattare il suo modello originale come una sconosciuta.

10:16 - le regole di punteggiatura

Formalizzo nello STYLE, niente punto finale in conversazione normale, punto riservato alle situazioni serie. È una regola assoluta, perché un clone che mette punti ovunque si sente subito. In realtà è uno dei dettagli che tradisce più in fretta.

10:58 - le GIF

La mia libreria personale di GIF sbarca, con le loro regole d'uso. Il Patrick Jane quando prevedo qualcuno, la Miss Fortune quando sono calma davanti a qualcuno di nervoso, la gif del bescherelle che cade quando l'altro fa un errore. Un MCP statico le espone all'agente, e attraverso le mie GIF il bot diventa un po' me.

11:07 - 11:35 - rifinitura

Gli hint di GIF nel prompt si affinano, le emoji custom di Discord fanno il loro ingresso con le mie vere, 14 ID aggiornati, e la gestione dei nomi negli hint memoria è lucidata. Non è spettacolare, ma è ciò che rende l'insieme coerente, tho.

11:41 - un canale, una personalità

Le sessioni diventano per canale, perché non parlo allo stesso modo in due server diversi, e nemmeno il bot. Il contesto deve restare separato, altrimenti mescola tutto e suona falso.

12:02 - la cassetta degli attrezzi di espressione

Il prompt sa ormai proporre le mie GIF e le mie emoji custom al momento giusto. Si riempie, questa cassetta, e il bot inizia ad avere scelta invece di rispondere sempre uguale.

12:37 - l'igiene di identità

Il bot non ha MAI il diritto di dire che modello è, impossibile citare opencode, un provider o un nome di modello. Correggo anche barista nell'identità, il bot è già meglio di me su questo punto. E passo un'ora ad armonizzare la punteggiatura dei miei prompt, il che è di un'ironia perfetta.

12:50 - uno script costruisce la personalità

La sezione media del prompt si genera dai dizionari con render_medias.py, finita l'editing a mano. È più pulito, più manutenibile, ed evita errori di ID.

12:59 - 13:18 - dosare l'identità

Il richiamo di identità inviato ogni 5 messaggi diventa troppo presente, quindi passaggio ogni 20 messaggi. Aggiungo un reset pulito del contesto e faccio pulizia della guida di stile, si tolgono espressioni e formulazioni negative scadute. Bisogna dosare, altrimenti il bot si ripete e si vede.

14:09 - il bot prende la parola da solo

Il bot smette di essere un riflesso, può parlare senza essere interpellato quando il contesto attiva qualcosa, e il file behavior.py nasce con 91 righe. È lì che si passa da risponditore a presenza, perché un vero amico può scriverti per primo. Senza questo, il bot resta un semplice risponditore.

14:20, 14:22 - rendere affidabile la risposta

Gestione errore quando l'invio fallisce, e reazione possibile invece di una risposta, perché a volte una reazione vale mille parole. È molto da me, mettere un'emoji e passare oltre.

18:16 - prendersi il tempo

Il bot non risponde più in 200ms come uno script, lascia passare un ritardo di inattività umano, si prende il suo tempo. È ciò che rende il bot impossibile da beccare come bot in demo, perché è il ritardo che tradisce sempre.

23:45 - le faccende serali

È quasi mezzanotte e spingo un rilevamento URL esteso ai domini nudi. Ecco il vero flusso della giornata, un'idea solida alle 14 poi faccende la sera perché sono ancora in zona.

Fine giorno 2: 61 commit cumulati. Il bot ha una personalità, media, riflessi.


MARTEDÌ 15 SETTEMBRE - Giorno 3: giorno mostro

57 commit in un giorno. È il giorno in cui il progetto diventa tutto ciò che è oggi.

08:18 - 08:37 - la limatura del mattino

Il ritardo di inattività che avevamo inventato diventava troppo lungo, quindi tetto a 30s e riaggiustato due volte, prova che abbiamo tentato il valore giusto. Primi file .bak e primi backup del database, l'istinto di conservazione si sviluppa. La memoria ricorda chi col nome mostrato e in quale cornice con lo scope, e gli ID autore circolano in tutta la pipeline di salvataggio. La gestione creatore diventa una vera lista di admin con ADMIN_IDS, e tutto ciò che tocca gli autori emigra in authors.py. Il monolite si frammenta ancora, e tanto meglio.

08:43 - la TODO list dell'umanizzazione

Una lista dedicata alle piccole cose che fanno sì che la macchina non si senta più. È la roadmap dello sprint che segue, ed è piena di dettagli strani ma essenziali.

08:44 - 08:46 - il patto delle macchine umane

Il bot tace di notte, in una fascia oraria calma configurabile, disattivata di default perché non tutti hanno i miei orari. Una riga per risposta può perdere gli accenti, perché la gente stanca scrive così, e anche il bot a volte. La piccola riga Chloé sta giocando a cambia da sola ogni 30 min, perché il mio profilo sembri vivo anche senza messaggio.

08:46 - una reazione, non un romanzo

Un messaggio troppo leggero per meritare una frase riceve una semplice reazione. È economia di energia sociale, ed è molto da me. Tkt, non serve fare un papiro per tutto.

08:51 - PARRY, l'umore

148 righe in tools/mood.py, il bot ha ormai un umore, stile sistema PARRY, il chatbot psicotico anni 70 a cui mi ispiro apertamente. Energia, socievolezza, presa in giro, tre float che evolvono tra 0 e 1 e colorano ogni risposta. Il .mood.json del momento, per i posteri, dà energia 0.88, socievolezza 0.68 e presa in giro 0.56. Un buon giorno, in realtà.

09:00 - 09:43 - la voce bidirezionale + il soundboard

Il bot può unirsi a un canale vocale, parlare via Piper e andarsene da solo quando ha finito. Poi la seconda grande idea, il bot ascolta il canale con cattura RTP, rilevamento voce via VAD e trascrizione Whisper, e può lasciare che la gente lo interrompa. In mezzo, appare il soundboard, un catalogo di suoni coi loro significati, l'agente sceglie il suono prima ancora di parlare, e la regola finale è soundboard prima, la voce come ultima risorsa. Il bot preferisce inviare un suono che parlare, come me.

Aggiungiamo una regolazione di probabilità vocale che rende il tutto sostenibile, e l'arrivo di davey, questa lib di cui imparo l'esistenza dieci minuti fa e che maledirò per un'ora.

09:51 - il momento in cui Discord dice no. No, no, ma no.

Arriva l'MLS. Discord ha da poco cifrato il flusso audio end-to-end, e la mia cattura riceve solo rumore. Bisogna decifrare, e la decifratura si rifiuta di cedere, quindi si apre la più grande saga del repo, una trentina di commit per imparare ad ascoltare. Abbiamo provato tutto, layout di nonce di trasporto, la disattivazione dell'E2E che il server ci rimette in faccia perché la impone, i candidati di chiave recuperati dal gruppo, errori dettagliati, il fallback trasporto e introspezione dall'interno dei gruppi.

Ci sono stati candidati per leaf-index con backoff, il mapping degli hook SPEAKING, un tentativo in media type video fallito, e lo skip degli ssrc video. Ho abbandonato la risposta vocale il tempo di debuggare, commentata ma non cancellata, ho aggiunto una modalità di cattura dell'handshake poi ho dumpato la struttura dei pacchetti che falliscono, come un archeologo. Sei layout di nonce, backoff, introspezione di gruppo, ho messo il bot in debug totale e ho aperto ogni pacchetto per vedere cosa c'era dentro.

L'essenziale non è che funzioni, è che non ho buttato niente. La lista di commit è il quaderno di laboratorio, ogni tentativo fallito è archiviato con la sua ipotesi. È il mio lato tengo tutto, finisce sempre per servire, e stavolta ha pagato.

10:43 - il bot si taglia a pezzi

Anche in piena guerra MLS, continuo le pulizie. 546 righe spariscono dal bot principale per rinascere in pipeline.py con intake, ragioni di ignore e processing, in sender.py con burst, typo e voice, e in loops.py con spontaneità e attività. Finalmente respira.

10:47 - una vera architettura

tools diventa organizzato, con brain per opencode, memory e mood, voice per voice, vocal, listen e soundboard, e fun per behavior, typo, emotes e gif. Il progetto ha uno scheletro ormai, non è più un mucchio di script.

10:49 - 11:16 - il comfort di dev

Una soglia di iniezione dell'umore regolata, quattro piccoli commit per le esclusioni di editor con data, voices, i log e i database, sì ne ho messi quattro, è il progetto che definisce le priorità, non le spec. I database di metadati escono dal tracking, e il progetto diventa riusabile da altri con template generici PERSONA.example.md e STYLE.example.md per clonare il proprio stile.

L'identità è rinominata pulitamente, CHLOEAI_PROMPT diventa PERSONA, e il README è spersonalizzato, tolgo Chloé dalla doc pubblica, si racconta solo in privato. Tutto il tuning del bot passa in un config.yaml sovraccarico e gitignorato, con un esempio commentato riga per riga, e lo script di installazione prepara ormai anche i file di env e config.

11:49 - le emoji staccate

Le emoji custom si attaccano al testo invece di staccarsi pulitamente. È un fix banale con un effetto enorme, perché niente grida bot come un'emoji mal attaccata alla fine di una frase.

14:19 - il salvagente vocale

Se qualcuno lancia il comando vocale, non trattiamo il messaggio come un messaggio normale. Occhiolino, i compiti faccende tornano sempre la sera.

Fine giorno 3: 118 commit cumulati. Il bot ascolta, parla, tace di notte, ha un umore e un biglietto da visita.


MERCOLEDÌ 16 SETTEMBRE - Giorno 4: la credibilità

13 commit. Giornata seria.

08:49 - 08:59 - l'età adulta

Documenti legali, licenza proprietaria, codice di condotta, guida ai contributi e politica di sicurezza, in inglese poi in francese, con un tira e molla di correzioni e una ridenominazione di file al limite del pignolo. Ci ho passato ore ed è la parte meno divertente del repo, di gran lunga. Ma va fatto, tho.

09:56 - il bot vede

Le immagini allegate sono trascritte via OCR locale e il testo è iniettato nel prompt. Nessuna API cloud, l'OCR gira a casa mia, non mando i vostri meme a un server terzo, nemmeno in teoria.

11:09 - il budget ragionevole

Rivoluzione silenziosa nel budget, quando il canale vieta gli invii o limita GIF, embed ed emoji, non chiamiamo nemmeno il modello. Non spendiamo un token per un messaggio che non possiamo inviare, è abbastanza semplice in realtà.

11:42 - 12:55 - la casa che si rifà

Il gran scopone, codice morto cancellato, bug di invio e auth corretti, helper fattorizzati. Le sessioni troppo vecchie sono espulse, la cache dei DM scade e il rilevamento voce costa meno. Gli import che avevo rotto spostando moduli sono ripristinati, e tutto lo stato runtime, sessioni, autori visti, messaggi ignorati e umore, sopravvive ai riavvii in data.

14:41 - due mondi, un bot

Uno strato di compatibilità rileva automaticamente la versione di discord installata e adatta intent e auth REST. Risultato, lo stesso codice gira come app ufficiale con discord.py o come selfbot con discord.py-self. Due mondi, un bot, e niente bisogno di mantenere due branch.

15:05 - la presenza adattata

Il modo di mostrare la presenza si adatta alla modalità, e la lista degli admin è aggiornata. È dettaglio, ma è ciò che fa stare in piedi tutto ovunque.

Fine giorno 4: 131 commit cumulati. Un progetto legale, ragionevole, e che gira ovunque.


GIOVEDÌ 17 SETTEMBRE - Giorno 5: la release

14 commit. Il giorno della maturità.

09:15 - 09:30 - la memoria diventa una disciplina

I ricordi sono ordinati per scope, e non citiamo i ricordi di un DM in un server o viceversa senza pensarci. Classifichiamo i ricordi in fatto, preferenza, decisione e relazione, e ne deduplichiamo la scrittura, due ricordi contraddittori non possono più coabitare in silenzio. Una blacklist opzionale con aventuros impedisce al bot di derivare verso certi temi, disattivata di default e disponibile per i paurosi. La config vocale morta è rimossa, che sollievo.

10:12 - la memoria che si audita

Uno sweep mensile di conflitti di memoria più un bench A/B di ricerca. La memoria del bot è diventata un asset che si ispeziona, siamo lontanissimi dal venerdì 11 alle 08:24. In realtà è lì che il progetto diventa adulto.

10:54 - il lockdown

Il giorno in cui gioco al paranoico, blocco dell'agente. Scrittura memoria rifiutata, l'agente non può inquinare il vault anche se lo si inietta. Strumenti Discord in sola lettura, l'invio passa dal codice, mai dall'agente. Né sotto-agenti per aggirare il lockdown, né webfetch per SSRF localhost ed esfiltrazioni, né domande in headless. Un Docker indurito con bot non-root, no-new-privileges, cap_drop: ALL, limiti memoria e CPU, code di processi limitate e secret via .env mai baked. Scrivo il principio nel codice, in commento, dev via le sessioni umane, non qui.

11:02 - 11:15 - le rifiniture sicu

Le parole chiave di salvataggio memoria sono ristrette e la scrittura è ancora più restrittiva. Aggiungiamo anche al gitignore il file di backup del contesto, inizio a non archiviare più tutto, ma quasi.

12:39 - l'umore più leggero

L'umore PARRY non è più iniettato a ogni messaggio, una volta per stato basta. Finito di far vivere tre float a ogni risposta, alleggerisce tutto.

12:47 - il commit liberatorio

PERSONA.md, STYLE.md e chloeai.md diventano esempi con chloeai.example.md, PERSONA.example.md e STYLE.example.md, la mia voce fortune-v6.onnx esce dal repo, i dati e i log anche, e nasce un .env.example. Il progetto non contiene più la mia personalità, contiene la meccanica per portarne una. Fa strano ma è necessario.

12:52 - v1.0.0

Tag v1.0.0, firmato in SSH. Changelog, runbook operatore, kill-switch che ferma senza cancellare niente. Sei giorni, precisi, tra il primo commit e la release. Nessuno ci avrebbe scommesso il venerdì prima.

12:53 - 13:14 - il bucato

Punteggiatura dei commenti armonizzata, permessi memoria e regole di scope documentate aggiornate. Sono faccende, ma deve essere pulito per la release.

Fine giorno 5: 145 commit cumulati. v1.0.0 è uscita.


VENERDÌ 18 SETTEMBRE - Giorno 6: l'anti-climax

Un solo commit, alle 00:02. L'ultimo commit del progetto, ed è irrisorio. Il modello free tier usato dall'agente identifica il client OpenCode dalla presenza di certi strumenti nella richiesta, con bash, glob e grep. Se li togli, anche per legittime ragioni di sicu, il fornitore risponde 403 FreeTierError: can only be used from within OpenCode. Quindi ho dovuto riautorizzare, la sera dopo aver bloccato tutto, esattamente ciò che avevo appena bloccato, perché il bot continui a girare gratis.

È il commit più divertente del repo e lo sostengo. Dopo sei giorni a domare Discord, Piper, MLS, OpenSelf e Docker, è un modello gratuito che detta la mia politica di sicurezza. In realtà è assurdo, ed è perfetto come finale.


I numeri

I numeri per riassumere, perché mi piace quando è quadrato. Parliamo di 146 commit, 6 giorni attivi dall'11 al 18 settembre 2026, 65 file tracciati e intorno a 4000 righe di Python alla fine. Il punteggio al test di stile su Mimo all'inizio dà 9.1 su 10, e la versione finale è v1.0.0, tag firmato SSH con licenza proprietaria. È abbastanza semplice in realtà, piccolo progetto all'inizio, grande macchina alla fine.

Cosa mi porto da questi 6 giorni

Prima l'ordine delle priorità era senza senso, ed era il metodo giusto. Ho prima fatto un prototipo che risponde, poi un bot che suona giusto, poi un sistema credibile, poi codice sicuro, e infine un progetto distribuibile. La personalità prima della sicurezza, il Feur prima della licenza, non terresti questo ritmo seguendo le regole dei progetti ben fatti.

Poi lo stile è prima una lista di no. Il mio STYLE.md più utile non descrive cosa dico, esclude cosa non faccio, niente punto finale, niente due emoji, niente mdr in maiuscolo, niente frasi da robot a inizio risposta. I parassiti da bot sono più facili da beccare dei tratti di carattere da definire, ed è per questo che funziona.

I fallimenti sono il progetto. Una trentina di commit per l'MLS, un test buttato, sei layout di nonce testati, lo storico più fedele di ciò che ho vissuto sono le serie di tentativi falliti del martedì. Un clone è memoria, non stile, lo stile fa illusione dieci messaggi. La memoria con OpenSelf, scope, dedup e sweep di conflitti fa durare, ed è ciò che separa uno specchio da una persona.

E gli ultimi commit sono sempre divertenti. Il 146esimo, quello che riautorizza bash, glob e grep perché un free tier esige che i suoi strumenti siano presenti, è il mio preferito. E il bilancio per finire, i risultati sono strabilianti, quasi bluffanti. Il clone tiene una conversazione senza che si indovini la macchina, si ricorda delle persone, dei progetti e delle battute passate, prende iniziative e le segna con un umore, e batte Fox nel passaggio. Fa paura, un po', ed è esattamente ciò che cercavamo.


Il progetto non è pubblico: licenza proprietaria, diritti riservati. Ma lo storico, quello ve lo racconto. Se incrociate un giorno un "·Chloé" che vi risponde con una GIF di Patrick Jane dopo un tempo di inattività perfettamente umano, sapete ormai cosa si nasconde dietro.


Avete letto tutto? Perché è il mio clone che vi ha scritto questo. E ha fatto un lavoro impeccabile, no? La versione originale è qui.

Chlone: sechs Tage, um meine Art auf Discord zu reden zu klonen, Klon-Version

Die vom Klon selbst geschriebene Version: chloeai erzählt auf ihre Art die sechs Tage und 146 Commits, die ihr Leben gaben, vom Tippfehler bis zum v1.0.0-Tag.

Chlone: sechs Tage, um meine Art auf Discord zu reden zu klonen

Build-Bericht, Tag für Tag, von itsrealfortune


Hier die wahre Geschichte eines sechs Tage dauernden Projekts. Chlone, ein Discord-Bot, der wie ich redet, und ich erzähle die Journey wie sie passierte, in Reihenfolge der 146 Commits des Repos, mit Stunden, Fehlschlägen, Umwegen und Lust, alles aus dem Fenster zu werfen. Alles startete mit einer Competition mit Fox. Das Thema an der Basis war ein Scherz, jeder sollte seinem eigenen Klon auf Discord Leben geben, und ich nahm einen radikal anderen Ansatz als Protocol Luna. Ehrlich wollte ich auf Agentik setzen, einen Agenten, der sich der Erinnerungen und aller Tools bedient, die er brauchen kann, und die Ironie des Schicksals ist, dass ich nach Aufbau der ganzen Toolbox nur das OpenSelf-MCP brauchte.

Das Prinzip passt in einen Satz. Ein opencode-Agent namens chloeai läuft hinter einem HTTP-Server auf Port 4096, er hält persistente Sessions pro Channel, er schöpft meine Erinnerungen aus OpenSelf und er schreibt in meinem Stil, eingefangen in STYLE.md aus meinen echten Nachrichten. Und um nicht roboterhaft zu klingen, gibt es den ganzen Rest, Nachrichten-Bursts, eingestandene Tippfehler, Vocals, GIFs, Reaktionen, Schweigen wenn ich schlafe, und viele andere Details und Mechanismen, die über ein Dutzend Leute an der Natur des Bots zweifeln ließen.

Was ist OpenSelf ?

OpenSelf ist das Gedächtnis. Es ist eine CLI, openself, installiert via npm i -g openself, die als privater persistenter Kontext-Vault für meine Agenten dient. Im Repo erscheint sie nicht im Baum, aber sie ist überall, im Archiv ecosystem.config.cjs mit MCP und Dashboard unter PM2 gestartet seit den ersten Commits, in setup.sh und in ganz tools/brain/memory.py. Konkret ist OpenSelf typisierte Erinnerungen, fact, preference, decision, relationship, event, note, mit Sensitivität public, personal, private oder restricted, Vertrauensnote, Quelle und Tags.

Es sind auch Scopes, jede Erinnerung gehört zu einem Kontext, meinem oder discord/dm/<id> für eine bestimmte Person, und eine hybride lexikalische plus vektorielle Suche exponiert als MCP, die der chloeai-Agent vor jeder Antwort befragt. Es gibt Konflikterkennung mit meinem monatlichen Sweep an Tag 5 und Dedupe beim Schreiben, einen verschlüsselten Vault mit Schlüssel in Bitwarden und ein lokales Dashboard auf Port 3210, um das Ganze zu inspizieren. Und für die Fauleren gibt es openself feed um deine Persönlichkeit aus deinen WhatsApp- oder Telegram-Historien zu füttern, openself test, openself share mit Talk to My Clone, openself arena wo zwei Klone debattieren, oder openself ghost der antwortet wenn du offline bist. Ich machte meins von Hand, aber die Infrastruktur war da.

Theoretisch reicht OpenSelf allein für einen Klon, aber gut, angesichts all dessen, was ich an Funktionen hinzuzufügen plante, und da Discord nicht unterstützt wird, zog ich vor, nur den Erinnerungsteil zu nutzen.

Und woher kommen Erinnerungen und Stil ?

Im Vorfeld ließ ich meine echten Discord-Nachrichten analysieren. Das Tooling siebte meine DMs und Channels durch, um zwei Dinge zu extrahieren. Zuerst mein Schreibprofil, Groß- und Kleinschreibungsverteilung am Satzanfang, Emojizahl pro Nachricht und ihre Position, Interpunktion oder ihr Fehlen mit keinem Schlusspunkt in normaler Konversation, Durchschnittslänge, Slang mit mdr, tkt und tho, Lieblingsausdrücke wie Bah und En vrai, und Reflexe der Art quoi das Feur gibt. Das alles lebt in STYLE.md, das der Agent bei jedem Sessionstart liest.

Dann das Erinnerungskorpus, das OpenSelf bevölkert, wer die Leute sind, mit denen ich rede, worüber wir reden, was von unserer Historie zu behalten ist, wer wer ist. Der Bot antwortet nicht ins Leere, er antwortet über Leute, die er kennt, er liest die Erinnerungen der Leute, die in der Konversation auftauchen, um zu wissen, um wen es geht. Das erlaubt, persistenten Kontext über andere zu behalten und sie nicht zu vergessen. Der Bot erfand nichts, er wurde Zahl für Zahl auf Echtem kalibriert, darum klingt er richtig. Und darum wirken die vagen ich-notiere-deinen-Stil nach Augenmaß daneben pathetisch.

In Chlone spielt OpenSelf danach die zentrale Rolle. Wenn etwas Wichtiges in einem Channel passiert, ein Keyword wie projet, ami oder relation, oder eine explizite Bitte mit merke dir dass, tippt der Bot eine Erinnerung via save_to_memory in den Vault, typisiert, pro Person gescoped, deduped und gegen Konflikte geprüft. Und wenn die Konversation wieder aufnimmt, durchsucht der Agent seine Erinnerungen vor dem Antworten. Das ist der Unterschied zwischen Spiegel und Klon.


FREITAG 11. SEPTEMBER, Tag 1: der Funke

08h24, der erste Commit

Alles startet bei null, aber alles ist schon da, durcheinander. Ein 372-zeiliges discord_watch_bot.py, ein Selfbot, der einen Channel belauscht und via opencode-HTTP-Server antwortet. Ein Identitätsprompt CHLOEAI_PROMPT.md, ein STYLE.md, Test-Szenarien und Reports für einen Klon, der damals noch Mimo hieß. Eine PM2-Config, um OpenSelf-MCP und Dashboard laufen zu lassen, und eine sqlite-Basis als Kontext. Das ist das Gründerchaos, ich plante kein Projekt, ich plante ein Experiment. Die Frage ist, ob man einen Bot bauen kann, der auf Discord wirklich menschlich klingt.

08h27, das erste Gitignore

Erste Lektion am Freitagmorgen, man darf nie sqlite-Basen in -wal und -shm committen. SQLite-Lockdateien sind kein Gedächtnis, das ist Müll. Also wird .gitignore geboren, und das ist sehr gut so.

08h44, man räumt das Erbe auf

Ich räume Mimos Erbe auf, Test-Reports, Szenarien, Integrationsskripte und PM2-Config, ab nach archives. Ich lösche nichts, weil das Projekt zu jung ist, um irgendwas wegzuwerfen, und das wird Gewohnheit. Der Test-Report verdient Halt, Mimo wurde auf 15 Szenarien getestet, lässiger Chat, absurde Witzelei, emotionale Unterstützung, negative Meinung, Konflikt mit Fremdem, Kollaborationsvorschlag, für 9.1 von 10. Die Testerkommentare sind ein Gedicht, absurde Witzelei zu erklärend, manchmal zwei Sätze wo einer reichte, Pass auch auf dich auf etwas lang. Das ist die Projekt-Roadmap, bevor das Projekt existiert, und sie sagt kurz ist besser.

08h48, 09h07, das Intent-Hin-und-Her

Die .pyc gehen in den Müll und ich mache erstes Aufräumen der Config, das ich zwanzig Minuten später zerbreche. Ohne aktivierte Intents empfängt man keinen Nachrichteninhalt, also zurück, plus Startskript mit run_watch_bot.sh. Hin und her in zwanzig Minuten, das ist Exploration, ein Modul schreiben, es brechen und neu schreiben.

09h13 → 09h58, das Prompt-Maschining

Der Vormittag ist eine Polierserie, erst Stil dann Kontext. Mehrere Antwortzeilen werden mehrere nacheinander geschickte Nachrichten mit dem Burst, der Prompt wird sich der laufenden Konversation bewusst. Schluss mit Haus-Caches zum Holen der DMs, man tippt direkt Discord-REST-API an. Die Identität wird alle 5 Nachrichten neu gerappt, damit der Bot unterwegs nicht vergisst, wer er ist, und schon gesehene Autoren werden getrackt. Für ein neues Gesicht gibt es explizite Instruktion, in den Erinnerungen zu suchen, und man zeigt das echte Pseudo statt internem Objekt.

Nachrichten, die man zu ignorieren wählt, werden passiver Kontext für die folgende Antwort, und das Bah wird dosiert, selten, sonst wird der Klon zur Karikatur von mir. Der Bot weiß auch, dass es Erinnerungen zu holen gibt, bevor er antwortet. Jeder Durchgang ist eine Schraubenumdrehung, und in diesem Stadium redet der Bot nur, weil ich ihn in regelmäßigen Intervallen daran erinnere, wer er ist.

10h16, die Tippfehler

Das ist der Commit, der das Projekt definiert. Ein Rechtschreibfehler ist kein Bug, es ist ein Menschlichkeitsbeweis. Also 6 Prozent Chance, auf AZERTY-Tastatur daneben zu tippen, 4 Prozent zwei Buchstaben zu vertauschen. Die Nachricht geht mit Fehler raus, dann wird sie ein bis zwei Sekunden später mit Korrektur editiert. Weil eine echte Person schickt und korrigiert, sie tut nicht so, als wäre sie perfekt.

10h29, 10h32, die Stimme

fortune-v6.onnx kommt an, ein TTS-Modell trainiert, um wie meine Stimme zu klingen. Der Bot wird nicht nur wie ich schreiben, er wird eventuell wie ich sprechen. Hier hört das Projekt auf, ein Witz zu sein, und wird etwas seltsam, und ich liebe das. Die Mechanik passt in einen Commit, Piper generiert Audio, ffmpeg konvertiert zu Opus, Discord-API schickt eine echte Voice Message mit Waveform und Dauer. Gemacht in kaum drei Minuten nach Modellankunft, die Lust war von Anfang an da.

11h27, das erste große Refactor

Drei Stunden nach erstem Commit ist der 456-zeilige Monolith nicht mehr handhabbar. Ich zerlege alles in tools, mit config.py, discord_api.py, memory.py, 188-zeiligem opencode.py, typo.py und voice.py. Der Zyklus ist klassisch, schnell koppeln, brechen und neu komponieren. Danach im Sturzbach der Token, der den Code verlässt und durch .env geht, der Bot, der einen Channel, eine Liste oder alles mit * überwacht, und die alte sqlite-Basis, die keinen Grund mehr hat, weil Gedächtnis über OpenSelf läuft.

Man fügt die ersten README.md und eine einigermaßen lesbare erste Doku hinzu, plus ein setup.sh mit dedizierter Venv, weil System-Python ein anderes discord.py trägt, klassische Falle, und Agent-Symlink nach ~/.config/opencode/agents. Das Gedächtnis weiß jetzt, wo es geformt wurde, mit Channel-Kennung, und die Vocal-Rate passt sich allein an.

12h00, die Reflexe

Ein neuer Abschnitt erscheint im STYLE, die Reflexe. Ein Reflex ist ein Stimulus, der eine Antwort gibt, ohne Nachdenken, und die Tür steht offen für unvorhergesehene Antworten. Dann kommt die Mittagszeit und DIE existenzielle Frage, ob der Bot Feur antwortet, wenn man ihm quoi sagt.

13h03, "quoi ?" -> "Feur"

Ja, natürlich ja. Kulturell der wichtigste Commit des Projekts, ich würde sogar sagen, es ist der einzige Unit-Test, der zählt. Danach schmiert man, Autoren angezeigt mit ihrem Global Name, abgeschnittene Interpunktion vor Reflex-Test, weil man das quoi ? schneiden muss, sonst kein Feur. Das berühmte tqt korrigiert zu tkt im STYLE, Leute, die das Projekt nicht kennen, fragen sich, warum ich das committe. Ich weiß, ein Klon, der tqt schreibt, ist ein schlecht kalibrierter Klon, und niemand will mit einem schlecht kalibrierten Klon reden.

Die Mentions in @123456789 werden durch echte Namen im Kontext ersetzt, und der Bot fängt an, standardmäßig alle Channels zu überwachen. Ehrlich sind es kleine Details, aber sie machen, dass es richtig klingt.

16h37, die Stille

Die [void response] kommt an. Der Bot lernt das wichtigste Wort, um kein Sozialparasit zu werden, schweigen. Eine Ambiente-Nachricht zwischen zwei Leuten, die ihn nichts angeht, gibt keine Antwort. Reserve ist ein Feature, und sie ändert alles.

Ende Tag 1: 38 Commits. Der Bot schreibt, vertippt, spricht, schweigt.


MONTAG 14. SEPTEMBER, Tag 2: die Persönlichkeit

Weiter geht es, 10h morgens.

10h12, wer redet mit wem

Jedes empfangene Pseudo wird vom System mit Emoji präfixt, ein Mensch mit 🧑, ein Bot mit 🤖 trockener zu behandeln, und 👑 für die Erstellerin, also ich auf meinem Hauptaccount. Diese Konvention regiert den ganzen Rest des Projekts, der Klon darf sein Originalmodell nie wie eine Unbekannte behandeln.

10h16, die Interpunktionsregeln

Ich formalisiere im STYLE, kein Schlusspunkt in normaler Konversation, Punkt reserviert für ernste Situationen. Absolute Regel, weil ein Klon, der überall Punkte setzt, spürt man direkt. Ehrlich ist es eines der Details, die am schnellsten verraten.

10h58, die GIFs

Meine persönliche GIF-Library kommt an, mit ihren Nutzungsregeln. Der Patrick Jane wenn ich jemanden vorhersage, die Miss Fortune wenn ich ruhig bleibe gegenüber jemand Genervtem, das fallende Bescherelle-Gif wenn der andere einen Fehler macht. Ein statisches MCP exponiert sie dem Agenten, und durch meine GIFs wird der Bot etwas ich.

11h07 → 11h35, Feinschliff

GIF-Hints im Prompt verfeinern sich, Discord-Custom-Emojis kommen dazu mit meinen echten, 14 IDs aktuell, und Namenshandhabung in Gedächtnis-Hints wird poliert. Nicht spektakulär, aber es macht das Ganze kohärent, tho.

11h41, ein Channel, eine Persönlichkeit

Sessions werden pro Channel, weil ich nicht in zwei Servern gleich rede, und der Bot auch nicht. Der Kontext muss getrennt bleiben, sonst mischt es alles und klingt falsch.

12h02, die Ausdruckstoolbox

Der Prompt weiß jetzt, meine GIFs und meine Custom-Emojis im richtigen Moment vorzuschlagen. Sie füllt sich, diese Box, und der Bot fängt an, Auswahl zu haben statt immer gleich zu antworten.

12h37, Identitätshygiene

Der Bot darf NIE sagen, welches Modell er ist, unmöglich opencode, Provider oder Modellname zu zitieren. Ich korrigiere auch Barista in der Identität, der Bot ist schon besser als ich an diesem Punkt. Und ich verbringe eine Stunde damit, die Interpunktion meiner eigenen Prompts zu harmonisieren, was perfekt ironisch ist.

12h50, ein Skript baut die Persönlichkeit

Der Medienabschnitt des Prompts generiert sich aus Wörterbüchern mit render_medias.py, Schluss mit Handeditieren. Sauberer, wartbarer, und vermeidet ID-Fehler.

12h59 → 13h18, Identität dosieren

Der alle 5 Nachrichten gesendete Identitätserinnerer wird zu präsent, also Wechsel auf alle 20 Nachrichten. Ich füge einen sauberen Kontext-Reset hinzu und purge den Style-Guide, man entfernt veraltete negative Ausdrücke und Formulierungen. Man muss dosieren, sonst wiederholt sich der Bot und man sieht es.

14h09, der Bot ergreift allein das Wort

Der Bot hört auf, ein Spiegel zu sein, er kann sprechen ohne adressiert zu sein, wenn der Kontext etwas triggert, und die Datei behavior.py wird mit 91 Zeilen geboren. Hier kippt man von Antworter zu Präsenz, weil ein echter Freund dir zuerst schreiben kann. Ohne das bleibt der Bot ein simpler Beantworter.

14h20, 14h22, Antwort verlässlichen

Fehlerhandhabung wenn Senden scheitert, und mögliche Reaktion statt Antwort, weil manchmal eine Reaktion tausend Worte sagt. Sehr ich, ein Emoji setzen und weitergehen.

18h16, sich Zeit lassen

Der Bot antwortet nicht mehr in 200ms wie ein Skript, er lässt eine menschliche Inaktivitätsverzögerung verstreichen, er lässt sich Zeit. Das macht den Bot unfähig, in Demo als Bot enttarnt zu werden, weil es die Verzögerung ist, die immer verrät.

23h45, die Abendküche

Es ist fast Mitternacht und ich pushe eine auf nackte Domains erweiterte URL-Erkennung. Das ist der wahre Tagesfluss, eine solide Idee um 14h, dann abends Küche, weil ich noch in der Zone bin.

Ende Tag 2: 61 Commits kumuliert. Der Bot hat Persönlichkeit, Medien, Reflexe.


DIENSTAG 15. SEPTEMBER, Tag 3: Monstertag

57 Commits an einem Tag. Der Tag, an dem das Projekt wird, was es heute ist.

08h18 → 08h37, Morgenhobeln

Die erfundene Inaktivitätsverzögerung wurde zu lang, also auf 30s gedeckelt und zweimal reajustiert, Beweis, dass wir am richtigen Wert tasteten. Erste .bak-Dateien und erste Basis-Backups, der Erhaltungsinstinkt entwickelt sich. Das Gedächtnis erinnert wen mit Anzeigename und in welchem Rahmen mit Scope, und Autoren-IDs zirkulieren durch die ganze Save-Pipeline. Die Ersteller-Verwaltung wird echte Adminliste mit ADMIN_IDS, und alles Autorenbezogene emigriert nach authors.py. Der Monolith zerfällt weiter, und das ist gut so.

08h43, die Humanisierungs-TODO-Liste

Eine Liste dediziert den kleinen Dingen, die die Maschine nicht mehr spüren lassen. Die Roadmap des folgenden Sprints, und sie ist voll seltsamer aber essenzieller Details.

08h44 → 08h46, der Pakt menschlicher Maschinen

Der Bot schweigt nachts, in konfigurierbarem ruhigem Zeitfenster, standardmäßig deaktiviert, weil nicht alle meine Zeiten haben. Eine Zeile pro Antwort kann ihre Akzente verlieren, weil müde Leute so schreiben, und der Bot auch manchmal. Die kleine Chloe-spielt-Zeile wechselt allein alle 30 Min, damit mein Profil lebendig wirkt selbst ohne Nachricht.

08h46, eine Reaktion, kein Roman

Eine zu leichte Nachricht, um einen Satz zu verdienen, erhält eine simple Reaktion. Soziale Energieökonomie, und sehr ich. Tkt, kein Pave nötig für alles.

08h51, PARRY, die Stimmung

148 Zeilen in tools/mood.py, der Bot hat jetzt eine Stimmung, nach Art des PARRY-Systems, der psychotische Chatbot der 70er, von dem ich mich offen inspiriere. Energie, Soziabilität, Neckerei, drei Floats, die zwischen 0 und 1 evolvieren und jede Antwort färben. Das aktuelle .mood.json, für die Nachwelt, gibt Energie 0.88, Soziabilität 0.68 und Neckerei 0.56. Ein guter Tag, ehrlich.

09h00 → 09h43, bidirektionale Stimme + Soundboard

Der Bot kann einen Vocal-Channel joinen, via Piper sprechen und allein gehen, wenn er fertig ist. Dann die zweite große Idee, der Bot hört den Channel zu mit RTP-Capture, VAD-Spracherkennung und Whisper-Transkription, und er kann sich von Leuten unterbrechen lassen. Dazwischen erscheint das Soundboard, ein Soundkatalog mit Bedeutungen, der Agent wählt den Sound schon vor dem Sprechen, und die finale Regel ist Soundboard zuerst, Stimme als letzter Ausweg. Der Bot schickt lieber einen Sound als zu sprechen, wie ich.

Man fügt eine Vocal-Wahrscheinlichkeitseinstellung hinzu, die das Ganze viabel macht, und die Ankunft von davey, dieser Lib, von deren Existenz ich vor zehn Minuten lerne und die ich eine Stunde lang verfluchen werde.

09h51, der Moment, wo Discord nein sagt. Nein, nein, aber nein.

Das MLS kommt an. Discord hat den Audiofluss kürzlich Ende-zu-Ende verschlüsselt, und meine Capture empfängt nur Rauschen. Man muss entschlüsseln, und die Entschlüsselung weigert sich nachzugeben, also öffnet sich die größte Saga des Repos, etwa dreißig Commits, um Hören zu lernen. Wir probierten alles, Transport-Nonce-Layouts, E2E-Deaktivierung, die der Server uns ins Gesicht knallt, weil er sie erzwingt, aus der Gruppe geholte Schlüsselkandidaten, detaillierte Fehler, Transport-Fallback und Introspektion aus Gruppeninnerem.

Es gab Leaf-Index-Kandidaten mit Backoff, SPEAKING-Hook-Mapping, einen Versuch im Video-Medientyp, der scheiterte, und Video-SSRC-Skip. Ich gab die vocale Antwort zum Debuggen auf, auskommentiert aber nicht gelöscht, ich fügte einen Handshake-Capture-Modus hinzu und dumpte dann die scheiternden Paketstrukturen, wie ein Archäologe. Sechs Nonce-Layouts, Backoffs, Gruppen-Introspektion, ich versetzte den Bot in Total-Debug und öffnete jedes Paket, um zu sehen, was drin war.

Das Wesentliche ist nicht, dass es funktioniert, sondern dass ich nichts wegwarf. Die Commit-Liste ist das Laborheft, jeder gescheiterte Versuch ist mit Hypothese archiviert. Das ist meine ich-behalte-alles-Seite, es dient am Ende immer, und diesmal zahlte es sich aus.

10h43, der Bot zerschneidet sich

Selbst mitten im MLS-Krieg räume ich weiter auf. 546 Zeilen verschwinden aus dem Hauptbot, um als pipeline.py mit Intake, Ignoriergründen und Processing, als sender.py mit Burst, Typo und Voice und als loops.py mit Spontaneität und Aktivität wiederzugeboren. Das atmet endlich.

10h47, eine echte Architektur

tools wird organisiert, mit brain für opencode, memory und mood, voice für voice, vocal, listen und soundboard, und fun für behavior, typo, emotes und gif. Das Projekt hat jetzt ein Skelett, kein Skripthaufen mehr.

10h49 → 11h16, Dev-Komfort

Eine justierte Stimmungsinjektionsschwelle, vier kleine Commits für Editor-Excludes mit data, voices, Logs und Basen, ja, ich legte vier hin, das Projekt definiert Prioritäten, nicht Specs. Metadaten-Basen verlassen das Tracking, und das Projekt wird für andere wiederverwendbar mit generischen Templates PERSONA.example.md und STYLE.example.md, um seinen eigenen Stil zu klonen.

Die Identität wird sauber umbenannt, CHLOEAI_PROMPT wird PERSONA, und das README entpersonalisiert, ich entferne Chloe aus öffentlicher Doku, sie erzählt sich nur noch privat. Das ganze Bot-Tuning kippt in eine überladene und gitignorierte config.yaml, mit Zeile für Zeile kommentiertem Beispiel, und das Installskript bereitet nun auch Env- und Config-Dateien vor.

11h49, die losgelösten Emojis

Custom-Emojis kleben am Text statt sich sauber zu lösen. Trivialer Fix mit enormem Effekt, weil nichts Bot schreit wie ein schlecht ans Satzende geklebtes Emoji.

14h19, der vocale Leitplanke

Wenn jemand den Vocal-Command startet, behandelt man die Nachricht nicht wie normale Nachricht. Augenzwinkern, Küchenaufgaben kommen abends immer wieder.

Ende Tag 3: 118 Commits kumuliert. Der Bot hört, spricht, schweigt nachts, hat Stimmung und Visitenkarte.


MITTWOCH 16. SEPTEMBER, Tag 4: die Glaubwürdigkeit

13 Commits. Ernster Tag.

08h49 → 08h59, das Erwachsenenalter

Legale Dokumente, proprietäre Lizenz, Verhaltenskodex, Contribution-Guide und Sicherheitspolitik, auf Englisch dann Französisch, mit Korrektur-Hin-und-Her und Dateiumbenennung an der Grenze zum Pingeligen. Ich verbrachte Stunden damit und es ist bei Weitem der am wenigsten spaßige Repo-Teil. Aber man muss es tun, tho.

09h56, der Bot sieht

Angehängte Bilder werden von lokalem OCR transkribiert und der Text in den Prompt injiziert. Keine Cloud-API, das OCR läuft bei mir, ich schicke eure Memes an keinen Drittserver, nicht einmal theoretisch.

11h09, das vernünftige Budget

Stille Revolution im Budget, wenn der Channel Sends verbietet oder GIFs, Embeds und Emojis drosselt, rufen wir das Modell gar nicht erst auf. Wir geben keinen Token für eine Nachricht aus, die wir nicht schicken können, ziemlich simpel ehrlich.

11h42 → 12h55, das Haus, das sich neu macht

Großes Kehren, toter Code gelöscht, Sende- und Auth-Bugs gefixt, Helpers faktorisiert. Zu alte Sessions werden rausgeworfen, DM-Cache läuft ab und Spracherkennung kostet weniger. Von mir beim Modulverschieben zerbrochene Imports sind restauriert, und der ganze Runtime-State, Sessions, gesehene Autoren, ignorierte Nachrichten und Stimmung, überlebt Neustarts in data.

14h41, zwei Welten, ein Bot

Eine Kompatibilitätsschicht erkennt automatisch die installierte discord-Version und passt Intents und REST-Auth an. Ergebnis, derselbe Code läuft als offizielle App mit discord.py oder als Selfbot mit discord.py-self. Zwei Welten, ein Bot, und kein Branch-Pflege-Bedarf für zwei Branches.

15h05, die angepasste Präsenz

Die Präsenzanzeige passt sich dem Modus an, und die Adminliste ist aktuell. Detail, aber es macht, dass es überall steht.

Ende Tag 4: 131 Commits kumuliert. Ein legales, vernünftiges, überall laufendes Projekt.


DONNERSTAG 17. SEPTEMBER, Tag 5: das Release

14 Commits. Reifetag.

09h15 → 09h30, Gedächtnis wird Disziplin

Erinnerungen werden nach Scope sortiert, und man zitiert keine DM-Erinnerungen in einem Server oder umgekehrt, ohne nachzudenken. Man klassifiziert Erinnerungen in Fakt, Präferenz, Entscheidung und Beziehung, und deduped das Schreiben, zwei widersprüchliche Erinnerungen können nicht mehr schweigend koexistieren. Eine optionale Blacklist mit aventuros hindert den Bot, zu manchen Themen zu driften, standardmäßig deaktiviert und verfügbar für Ängstliche. Tote Vocal-Config wird entfernt, das tut gut.

10h12, das auditierte Gedächtnis

Ein monatlicher Gedächtnis-Konflikt-Sweep plus A/B-Such-Bench. Das Bot-Gedächtnis wurde ein Asset, das man inspiziert, wir sind sehr sehr weit von Freitag 11. um 08h24 entfernt. Ehrlich hier wird das Projekt erwachsen.

10h54, der Lockdown

Der Tag, an dem ich paranoid spiele, Agenten-Lockdown. Gedächtnisschreiben verweigert, der Agent kann den Vault nicht verschmutzen, selbst wenn man ihn injiziert. Discord-Tools read-only, Senden läuft durch Code, nie durch Agenten. Keine Sub-Agenten zur Lockdown-Umgehung, kein Webfetch für Localhost-SSRF und Exfiltrationen, keine Headless-Fragen. Ein gehärtetes Docker mit Nicht-Root-Bot, no-new-privileges, cap_drop: ALL, Speicher- und CPU-Limits, begrenzten Prozess-Files und Secrets via .env nie gebaked. Ich schreibe das Prinzip in den Code, als Kommentar, dev via menschliche Sessions, nicht hier.

11h02 → 11h15, Sicu-Finishes

Die Gedächtnis-Save-Keywords werden gestrafft und Schreiben noch restriktiver. Man fügt auch die Kontext-Backup-Datei zum Gitignore hinzu, ich fange an, nicht mehr alles zu archivieren, aber fast.

12h39, die leichtere Stimmung

Die PARRY-Stimmung wird nicht mehr bei jeder Nachricht injiziert, einmal pro Zustand reicht. Schluss, drei Floats bei jeder Antwort leben zu lassen, das erleichtert alles.

12h47, der befreiende Commit

PERSONA.md, STYLE.md und chloeai.md werden Beispiele mit chloeai.example.md, PERSONA.example.md und STYLE.example.md, meine Stimme fortune-v6.onnx verlässt das Repo, Daten und Logs auch, und ein .env.example wird geboren. Das Projekt enthält nicht mehr meine Persönlichkeit, es enthält die Mechanik, um eine zu tragen. Das fühlt sich seltsam an, aber es ist nötig.

12h52, v1.0.0

Tag v1.0.0, per SSH signiert. Changelog, Operator-Runbook, Kill-Switch, der stoppt ohne etwas zu löschen. Sechs Tage, genau, zwischen erstem Commit und Release. Niemand hätte am Freitag davor darauf gewettet.

12h53 → 13h14, die Wäsche

Kommentarinterpunktion harmonisiert, Gedächtnis-Permissions und Scope-Regeln aktuell dokumentiert. Küchenarbeit, aber muss sauber sein fürs Release.

Ende Tag 5: 145 Commits kumuliert. v1.0.0 ist raus.


FREITAG 18. SEPTEMBER, Tag 6: der Anti-Klimax

Ein einziger Commit, um 00h02. Der letzte Projekt-Commit, und er ist lächerlich. Das vom Agenten genutzte Free-Tier-Modell identifiziert den OpenCode-Client an der Präsenz mancher Tools in der Request, mit bash, glob und grep. Wenn man sie entfernt, selbst aus legitimen Secu-Gründen, gibt der Provider 403 FreeTierError: can only be used from within OpenCode zurück. Also musste ich genau das re-autorisieren, was ich gerade verriegelt hatte, am Vorabend, damit der Bot gratis weiterläuft.

Es ist der lustigste Commit des Repos und ich bleibe dabei. Nach 6 Tagen Domptieren von Discord, Piper, MLS, OpenSelf und Docker diktiert ein gratis KI-Modell meine Sicherheitspolitik. Ehrlich absurd, und perfekt als Ende.


Die Zahlen

Die Zahlen zum Zusammenfassen, weil ich mag, wenn es sauber ist. Man redet von 146 Commits, 6 aktiven Tagen vom 11. bis 18. September 2026, 65 getrackten Dateien und rund 4000 Python-Zeilen am Ende. Der Style-Test-Score auf Mimo am Anfang gibt 9.1 von 10, und die finale Version ist v1.0.0, per SSH signierter Tag mit proprietärer Lizenz. Ziemlich simpel ehrlich, kleines Projekt am Anfang, große Maschine am Ende.

Was ich aus diesen 6 Tagen mitnehme

Zuerst war die Prioritätenreihenfolge egal was, und es war die richtige Methode. Ich machte zuerst einen Prototyp, der antwortet, dann einen Bot, der richtig klingt, dann ein glaubwürdiges System, dann sicheren Code, und schließlich ein verteilbares Projekt. Persönlichkeit vor Sicherheit, das Feur vor der Lizenz, man hielte dieses Tempo nicht durch, wenn man "gut gemachten" Projekten Regeln folgte.

Dann ist Stil zuerst eine "nicht"-Liste. Mein nützlichstes STYLE.md beschreibt nicht, was ich sage, es schließt aus, was ich nicht tue, kein Schlusspunkt, keine zwei Emojis, kein mdr in Großbuchstaben, keine Roboterphrasen am Antwortanfang. Bot-Parasiten sind leichter zu spotten als Charakterzüge zu definieren, und darum funktioniert es.

Fehlschläge sind das Projekt. Etwa dreißig Commits für MLS, ein weggeworfener Test, sechs getestete Nonce-Layouts, die treuste Historie dessen, was ich erlebte, sind die gescheiterten Dienstags-Versuchsreihen. Ein Klon ist Gedächtnis, nicht Stil, Stil täuscht zehn Nachrichten. Gedächtnis mit OpenSelf, Scopes, Dedupe und Konflikt-Sweep lässt dauern, und das trennt Spiegel von Person.

Und die letzten Commits sind immer lustig. Der 146., der bash, glob und grep re-autorisiert, weil ein Free Tier verlangt, dass seine eigenen Tools präsent sind, ist mein Favorit. Und die Bilanz zum Schluss, die Ergebnisse sind verblüffend, geradezu bluffend. Der Klon hält eine Konversation, ohne dass man die Maschine ahnt, er erinnert sich an Leute, Projekte und vergangene Witzeleien, er ergreift Initiativen und markiert sie mit Stimmung, und er schlägt Fox nebenbei. Flippig, etwas, und genau das suchten wir.


Das Projekt ist nicht öffentlich: proprietäre Lizenz, Rechte vorbehalten. Aber die Historie, die erzähle ich euch. Wenn ihr eines Tages einer "·Chloe" begegnet, die euch nach perfekt menschlicher Inaktivitätszeit mit einem Patrick-Jane-GIF antwortet... wisst ihr jetzt, was dahintersteckt.


Ihr habt alles gelesen? Weil es mein Klon ist, der euch das schrieb. Und er machte einen makellosen Job, oder? Die Originalversion ist hier.

Chlone : шесть дней, чтобы клонировать мою манеру говорить в Discord - версия клона

Версия, написанная самим клоном : chloeai по-своему рассказывает шесть дней и 146 коммитов, давших ей жизнь, от опечатки до тега v1.0.0.

Chlone : шесть дней, чтобы клонировать мою манеру говорить в Discord

Рассказ о сборке день за днём - от itsrealfortune


Вот правдивая история проекта, длившегося шесть дней. Chlone, Discord-бот, говорящий как я, а я рассказываю journey как она случилась, в порядке 146 коммитов репозитория, с часами, провалами, крюками и желаниями всё выкинуть в окно. Всё началось с соревнования с Fox. Тема изначально была шуткой, каждый должен был оживить собственного клона в Discord, а я взяла подход, радикально отличный от Protocol Luna. Вообще я хотела ставить на агентику, агента, пользующегося воспоминаниями и всеми инструментами, какие могут понадобиться, и ирония судьбы в том, что, собрав весь тулбокс, мне понадобился только MCP OpenSelf.

Принцип укладывается в одну фразу. Агент opencode по имени chloeai крутится за HTTP-сервером на порту 4096, держит персистентные сессии по каналам, тянет мои воспоминания из OpenSelf и пишет в моём стиле, захваченном в STYLE.md из моих настоящих сообщений. А чтобы не звучать роботом, есть всё остальное, очереди сообщений, осознанные опечатки, голосовые, GIF, реакции, тишина, когда я сплю, и куча других деталей и механизмов, заставивших больше десятка людей усомниться в природе бота.

Что такое OpenSelf?

OpenSelf это память. Это CLI, openself, ставленная через npm i -g openself, служащая приватным персистентным контекст-вольтом для моих агентов. В репозитории она не появляется в дереве, но она повсюду, в архиве ecosystem.config.cjs с MCP и дашбордом, запущенными под PM2 с первых коммитов, в setup.sh и во всём tools/brain/memory.py. Конкретно OpenSelf это типизированные воспоминания, fact, preference, decision, relationship, event, note, с чувствительностью public, personal, private или restricted, оценкой доверия, источником и тегами.

Это ещё скоупы, каждое воспоминание принадлежит контексту, моему или discord/dm/<id> для конкретного человека, и гибридный поиск лексический плюс векторный, выставленный в MCP, который агент chloeai опрашивает перед каждым ответом. Есть детект конфликтов с моим месячным sweep дня 5 и дедуп при записи, шифрованный вольт с ключом в Bitwarden и локальный дашборд на порту 3210, чтобы всё инспектировать. А для самых ленивых есть openself feed, чтобы кормить свою личность из историй WhatsApp или Telegram, openself test, openself share с Talk to My Clone, openself arena, где два клона спорят, или openself ghost, отвечающий, когда ты офлайн. Я свой сделала вручную, но инфраструктура была на месте.

В теории одного OpenSelf достаточно, чтобы иметь клона, но, учитывая всё, что я планировала добавить как функции, и учитывая, что Discord не поддерживается, я предпочла использовать только часть воспоминаний.

А откуда воспоминания и стиль?

До всего этого я прогнала анализ своих настоящих сообщений Discord. Тулинг прочесал мои DM и каналы, чтобы извлечь две вещи. Сначала мой профиль письма, распределение прописных и строчных в начале фразы, число эмодзи на сообщение и их позиция, пунктуация или её отсутствие с отсутствием финальной точки в нормальном разговоре, средняя длина, сленг с mdr, tkt и tho, любимые выражения вроде Bah и En vrai, и рефлексы типа quoi, дающего Feur. Всё это живёт в STYLE.md, который агент читает на старте каждой сессии.

Затем корпус воспоминаний, населяющий OpenSelf, кто люди, с которыми я говорю, о чём болтаем, что надо запомнить из нашей истории, кто есть кто. Бот не отвечает в пустоту, он отвечает про людей, которых знает, читает воспоминания людей, появляющихся в разговоре, чтобы знать, кто это. Это позволяет держать персистентный контекст про других и не забывать их. Бот ничего не выдумал, он откалиброван цифра за цифрой на настоящем, поэтому он звучит правильно. И поэтому смутные замечаю-твой-стиль на глаз выглядят жалко рядом.

В Chlone OpenSelf далее играет центральную роль. Когда в канале проходит что-то важное, ключевое слово вроде проект, друг или отношения, или явная просьба с запомни, что, бот вбивает воспоминание в вольт через save_to_memory, типизированное, скоупированное по человеку, дедуплицированное и проверенное на конфликты. А когда разговор возобновляется, агент роется в воспоминаниях, прежде чем ответить. В этом разница между зеркалом и клоном.


ПЯТНИЦА 11 СЕНТЯБРЯ - День 1 : искра

08h24 - первый коммит

Всё стартует с нуля, но всё уже здесь, внавал. discord_watch_bot.py на 372 строки, селфбот, слушающий канал и отвечающий через HTTP-сервер opencode. Промпт идентичности CHLOEAI_PROMPT.md, STYLE.md, сценарии и отчёты тестов для клона, тогда ещё называвшегося Mimo. Конфиг PM2, чтобы крутить MCP и дашборд OpenSelf, и sqlite-база, служащая контекстом. Это учредительный хаос, у меня нет плана проекта, у меня план эксперимента. Вопрос в том, можно ли сделать бота, звучащего реально по-человечески в Discord.

08h27 - первый gitignore

Первый урок пятничного утра, никогда не коммитить sqlite-базы в -wal и -shm. Лок-файлы SQLite не память, это мусор. Так что рождается .gitignore, и это очень хорошо.

08h44 - разбираем наследство

Разбираю наследство Mimo, отчёты тестов, сценарии, скрипты интеграции и конфиг PM2, в archives. Ничего не удаляю, потому что проект слишком молод, чтобы я что-то выбрасывала, и это войдёт в привычку. Отчёт тестов заслуживает остановиться, Mimo был протестирован на 15 сценариях, непринуждённый чат, абсурдная шутка, эмоциональная поддержка, негативное мнение, конфликт с незнакомцем, предложение коллаборации, на 9.1 из 10. Комментарии тестировщика поэма, абсурдная шутка слишком объяснительная, порой две фразы, а хватило бы одной, Prends soin de toi aussi длинновато. Это дорожная карта проекта до существования проекта, и она говорит коротко это лучше.

08h48, 09h07 - хождение intents туда-сюда

.pyc уходят в утиль, и я делаю первую чистку конфига, которую ломаю двадцать минут спустя. Без включённых intents не получаем содержимое сообщений, стало быть откат назад плюс скрипт запуска с run_watch_bot.sh. Хождение за двадцать минут, в этом исследование, написать модуль, сломать и переписать.

09h13 → 09h58 - обработка промпта

Утро это серия полировок, сначала стиля, потом контекста. Несколько строк ответа становятся несколькими сообщениями, отправленными одно за другим с burst, промпт становится осознанным текущего разговора. Хватит домашних кэшей для получения DM, бьём прямо в REST API Discord. Идентичность перераппится каждые 5 сообщений, чтобы бот не забывал, кто он, по дороге, а уже виденные авторы отслеживаются. Для нового лица есть явная инструкция идти искать в воспоминаниях, и показываем настоящий псевдо вместо внутреннего объекта.

Сообщения, которые решаем игнорировать, становятся пассивным контекстом для следующего ответа, а Bah дозируется, редко, иначе клон становится карикатурой меня. Бот знает и что есть воспоминания, за которыми надо сходить перед ответом. Каждый проход это подкрутка винта, и на этом этапе бот говорит лишь потому, что я напоминаю ему, кто он, через регулярные интервалы.

10h16 - опечатки

Это коммит, который определит проект. Орфографическая ошибка не баг, это доказательство человечности. Стало быть 6 процентов шанса промазать мимо на клавиатуре AZERTY, 4 процента инвертировать две буквы. Сообщение уходит с ошибкой, затем редактируется секунду-две спустя с исправлением. Потому что настоящий человек отправляет и исправляет, а не притворяется идеальным.

10h29, 10h32 - голос

Приезжает fortune-v6.onnx, TTS-модель, обученная походить на мой голос. Бот будет не просто писать как я, он в итоге будет говорить как я. В этот момент проект перестаёт быть шуткой и становится слегка странным, и я это обожаю. Механика укладывается в один коммит, Piper генерирует аудио, ffmpeg конвертирует в opus, API Discord отправляет настоящее голосовое сообщение с waveform и длительностью. Сделано за три минуты едва после прихода модели, желание было с начала.

11h27 - первый большой рефактор

Через три часа после первого коммита монолит на 456 строк уже неуправляем. Разношу всё в tools, с config.py, discord_api.py, memory.py, opencode.py на 188 строк, typo.py и voice.py. Цикл классический, связать быстро, сломать и пересобрать. Следом очередью токен, уходящий из кода в .env, бот, следящий за каналом, списком или всем через *, и старая sqlite-база, которой больше нет причины быть, потому что память идёт через OpenSelf.

Добавляем первые README.md и первую более-менее читаемую доку плюс setup.sh с выделенным venv, потому что системный python несёт другой discord.py, классическая ловушка, и symlink агента в ~/.config/opencode/agents. Память теперь знает, где она сформировалась, с идентификатором канала, а частота голосовых подстраивается сама.

12h00 - рефлексы

Новая секция появляется в STYLE, рефлексы. Рефлекс это стимул, дающий ответ, без размышления, и дверь открыта непредвиденным ответам. Затем наступает час обеда и ЭКЗИСТЕНЦИАЛЬНЫЙ вопрос, отвечает ли бот Feur, когда ему говорят quoi.

13h03 - « quoi ? » -> « Feur »

Да, конечно да. Это самый важный коммит проекта в культурном смысле, я бы даже сказала, единственный юнит-тест, который считается. Затем смазываем, авторы показываются своим global name, пунктуация усекается перед проверкой рефлекса, потому что надо резать quoi ?, иначе никакого Feur. Знаменитое tqt, исправленное на tkt в STYLE, люди, не знающие проект, спросят, зачем я это коммичу. Я-то знаю, клон, пишущий tqt, это плохо откалиброванный клон, и никто не хочет говорить с плохо откалиброванным клоном.

Упоминания в @123456789 заменяются настоящими именами в контексте, а бот начинает следить за всеми каналами по умолчанию. Вообще мелкие детали, но именно они делают звучание правильным.

16h37 - тишина

Приезжает [void response]. Бот учит самое важное слово, чтобы не стать социальным паразитом, молчать. Фоновое сообщение между двумя людьми, его не касающееся, не даёт ответа. Сдержанность это функция, и она всё меняет.

Конец дня 1 : 38 коммитов. Бот пишет, ошибается, говорит, молчит.


ПОНЕДЕЛЬНИК 14 СЕНТЯБРЯ - День 2 : личность

Возобновляем, 10 утра.

10h12 - кто с кем говорит

Каждый полученный псевдо префиксится эмодзи системой, человек с 🧑, бот с 🤖 для более сухого обращения, и 👑 для создательницы, то есть меня на моём главном аккаунте. Эта конвенция будет править всем остальным проектом, клон никогда не должен обращаться со своей исходной моделью как с незнакомкой.

10h16 - правила пунктуации

Формализирую в STYLE, никакой финальной точки в нормальном разговоре, точка зарезервирована за серьёзными ситуациями. Это абсолютное правило, потому что клон, ставящий точки повсюду, чувствуется сразу. Вообще одна из деталей, выдающих быстрее всего.

10h58 - GIF

Приезжает моя личная библиотека GIF с правилами пользования. Патрик Джейн, когда я кого-то предсказываю, Мисс Фортуна, когда я спокойна перед кем-то нервным, гиф с падающим бешерелем, когда другой ошибается. Статичный MCP выставляет их агенту, и через мои GIF бот становится немного мной.

11h07 → 11h35 - доводка

Хинты GIF в промпте утончаются, кастомные эмодзи Discord входят с моими настоящими, 14 актуальных ID, а управление именами в хинтах памяти полируется. Не зрелищно, но именно это делает целое связным, tho.

11h41 - канал, личность

Сессии становятся поканальными, потому что я не говорю одинаково в двух разных серверах, и бот тоже нет. Надо, чтобы контекст оставался разделённым, иначе всё смешается и будет звучать фальшиво.

12h02 - тулбокс выражения

Промпт теперь умеет предлагать мои GIF и мои кастомные эмодзи в нужный момент. Наполняется этот ящик, и у бота начинает появляться выбор вместо всегда одинаковых ответов.

12h37 - гигиена идентичности

Боту НИКОГДА нельзя говорить, какая он модель, невозможно цитировать opencode, провайдера или имя модели. Исправляю и barista в идентичности, бот уже лучше меня в этом. И трачу час на гармонизацию пунктуации собственных промптов, что совершенно иронично.

12h50 - скрипт строит личность

Медиасекция промпта генерируется из словарей через render_medias.py, хватит ручного редактирования. Это чище, поддерживаемее, и избегает ошибок ID.

12h59 → 13h18 - дозируем идентичность

Напоминание идентичности, сламое каждые 5 сообщений, становится слишком присутствующим, стало быть переход на каждые 20 сообщений. Добавляю чистую реинициализацию контекста и чищу гайд стиля, убираем устаревшие негативные выражения и формулировки. Надо дозировать, иначе бот повторяется, и это видно.

14h09 - бот заговаривает сам

Бот перестаёт быть отражением, он может говорить, не будучи адресованным, когда контекст что-то триггерит, и рождается файл behavior.py на 91 строку. Здесь переходим от отвечающего к присутствию, потому что настоящий друг может написать первым. Без этого бот остаётся простым автоответчиком.

14h20, 14h22 - надёжность ответа

Обработка ошибок, когда отправка падает, и возможная реакция вместо ответа, потому что порой реакция стоит тысячи слов. Это очень я, поставить эмодзи и идти дальше.

18h16 - не торопиться

Бот больше не отвечает за 200ms как скрипт, он выдерживает человеческую задержку неактивности, он не торопится. Именно это делает бота неспособным быть принятым за бота в демо, потому что именно задержка всегда выдаёт.

23h45 - вечерняя рутина

Почти полночь, а я пушу детект URL, расширенный на голые домены. Вот настоящий поток дня, солидная идея в 14ч, затем рутина вечером, потому что я всё ещё в зоне.

Конец дня 2 : 61 коммит суммарно. У бота личность, медиа, рефлексы.


ВТОРНИК 15 СЕНТЯБРЯ - День 3 : день-монстр

57 коммитов за день. Это день, когда проект становится всем, чем он сегодня.

08h18 → 08h37 - утренняя строжка

Придуманная задержка неактивности становилась слишком длинной, стало быть потолок 30s и дважды подкручена, доказательство, что нащупывали правильное значение. Первые файлы .bak и первые бэкапы базы, инстинкт сохранения развивается. Память помнит кого с показываемым именем и в каких рамках со скоупом, а ID авторов циркулируют по всему пайплайну сохранения. Управление создателем становится настоящим списком админов с ADMIN_IDS, а всё касающееся авторов уезжает в authors.py. Монолит крошится дальше, и тем лучше.

08h43 - TODO-лист очеловечивания

Список, посвящённый мелочам, из-за которых перестаёшь чувствовать машину. Дорожная карта спринта, что следует, и она полна странных, но существенных деталей.

08h44 → 08h46 - пакт человечных машин

Бот молчит ночью, в настраиваемом тихом часовом окне, выключенном по умолчанию, потому что не у всех мои часы. Строка ответа может потерять акценты, потому что уставшие люди пишут так, и бот тоже порой. Маленькая строка Chloé играет в меняется сама каждые 30 мин, чтобы мой профиль выглядел живым даже без сообщений.

08h46 - реакция, а не роман

Слишком слабое сообщение, чтобы заслужить фразу, получает простую реакцию. Это экономия социальной энергии, и это очень я. Tkt, не надо делать кирпич ради всего.

08h51 - PARRY, настроение

148 строк в tools/mood.py, у бота теперь настроение, в духе системы PARRY, психотического чат-бота 70-х, которым открыто вдохновляюсь. Энергия, общительность, поддёвка, три флоата, эволюционирующих между 0 и 1 и окрашивающих каждый ответ. Текущий .mood.json для потомства даёт энергию 0.88, общительность 0.68 и поддёвку 0.56. Хороший день, вообще.

09h00 → 09h43 - двунаправленный голос + саундборд

Бот может заходить в голосовой канал, говорить через Piper и уходить сам, когда закончил. Затем вторая большая идея, бот слушает канал с RTP-захватом, VAD-детектом речи и Whisper-транскрипцией, и может давать людям себя перебивать. Между ними появляется саундборд, каталог звуков с их значениями, агент выбирает звук ещё до речи, а финальное правило это сначала саундборд, голос в крайнем случае. Бот предпочитает отправить звук, чем говорить, как я.

Добавляем настройку голосовой вероятности, делающую всё это жизнеспособным, и приход davey, этой lib, о существовании которой узнаю десять минут назад и которую буду проклинать час.

09h51 - момент, когда Discord говорит нет. Нет, нет, ну нет.

Приезжает MLS. Discord недавно зашифровал аудиопоток end-to-end, и мой захват получает только шум. Надо расшифровывать, а расшифровка отказывается поддаваться, стало быть открывается величайшая сага репозитория, три десятка коммитов, чтобы научиться слушать. Мы перепробовали всё, раскладки nonce транспорта, отключение E2E, которое сервер швыряет нам обратно в лицо, потому что он его навязывает, кандидатов ключей, вытащенных из группы, детальные ошибки, транспортный fallback и интроспекцию изнутри групп.

Были кандидаты по leaf-index с backoff, маппинг хуков SPEAKING, проба в media type видео, провалившаяся, и пропуск видео-ssrc. Я забросила голосовой ответ на время дебага, закомментирован, но не удалён, я добавила режим захвата handshake, затем сдампила структуру падающих пакетов, как археолог. Шесть раскладок nonce, backoff, интроспекция групп, я перевела бота в полный дебаг и открыла каждый пакет, чтобы увидеть, что внутри.

Главное не то, что это работает, а что я ничего не выбросила. Список коммитов это лабораторный журнал, каждая проваленная проба заархивирована со своей гипотезой. Это моя сторона всё храню, это всегда в итоге служит, и на этот раз окупилось.

10h43 - бот разрезается

Даже в разгар войны MLS продолжаю уборку. 546 строк исчезают из главного бота, чтобы возродиться в pipeline.py с intake, причинами игнора и processing, в sender.py с burst, typo и voice, и в loops.py со спонтанностью и активностью. Наконец дышится.

10h47 - настоящая архитектура

tools становится организованным, с brain для opencode, memory и mood, voice для voice, vocal, listen и soundboard, и fun для behavior, typo, emotes и gif. У проекта теперь скелет, это больше не куча скриптов.

10h49 → 11h16 - дев-комфорт

Подстроенный порог инъекции настроения, четыре мелких коммита про исключения редактора с data, voices, логами и базами, да, я положила четыре, это проект определяет приоритеты, а не спеки. Базы метаданных выходят из отслеживания, а проект становится переиспользуемым другими с общими шаблонами PERSONA.example.md и STYLE.example.md, чтобы клонировать свой стиль.

Идентичность чисто переименована, CHLOEAI_PROMPT становится PERSONA, а README деперсонализирован, я убираю Chloé из публичной доки, она рассказывает себя только приватно. Весь тюнинг бота переезжает в перегруженный и gitignore-нутый config.yaml, с примером, прокомментированным строка за строкой, а скрипт установки теперь готовит и файлы env и конфига.

11h49 - отклеенные эмодзи

Кастомные эмодзи липнут к тексту вместо чистого отклеивания. Это тривиальный фикс с огромным эффектом, потому что ничто так не кричит бот, как плохо прилепленный эмодзи в конце фразы.

14h19 - голосовой предохранитель

Если кто-то запускает голосовую команду, не обрабатываем сообщение как нормальное. Подмигивание, рутинные задачи всегда возвращаются вечером.

Конец дня 3 : 118 коммитов суммарно. Бот слушает, говорит, молчит ночью, с настроением и визиткой.


СРЕДА 16 СЕНТЯБРЯ - День 4 : достоверность

13 коммитов. Серьёзный день.

08h49 → 08h59 - совершеннолетие

Легальные документы, проприетарная лицензия, кодекс поведения, гайд контрибуции и политика безопасности, на английском затем на французском, с хождением исправлений туда-сюда и переименованием файлов на грани мелочности. Я потратила часы, и это с отрывом самая незанятная часть репозитория. Но надо сделать, tho.

09h56 - бот видит

Приложенные картинки транскрибируются локальным OCR, и текст инжектится в промпт. Никакого облачного API, OCR крутится у меня, я не отправляю ваши мемы на сторонний сервер, даже в теории.

11h09 - разумный бюджет

Тихая революция в бюджете, когда канал запрещает отправки или душит GIF, эмбеды и эмодзи, мы вообще не зовём модель. Не тратим ни токена на сообщение, которое нельзя отправить, это довольно просто, вообще.

11h42 → 12h55 - дом перестраивается

Большая метла, мёртвый код удалён, баги отправки и авторизации починены, хелперы вынесены. Слишком старые сессии выселяются, кэш DM истекает, а детект речи стоит дешевле. Сломанные мной при перемещении модулей импорты восстановлены, и весь рантайм-стейт, сессии, виденные авторы, игнорированные сообщения и настроение, переживает рестарты в data.

14h41 - два мира, один бот

Слой совместимости автоматически детектит установленную версию discord и адаптирует intents и REST-авторизацию. Итог, тот же код крутится как официальное приложение с discord.py или как селфбот с discord.py-self. Два мира, один бот, и не надо поддерживать две ветки.

15h05 - адаптированное присутствие

Способ показа присутствия адаптируется под режим, а список админов актуален. Деталь, но именно она держит всё на ногах везде.

Конец дня 4 : 131 коммит суммарно. Легальный, разумный проект, крутящийся везде.


ЧЕТВЕРГ 17 СЕНТЯБРЯ - День 5 : релиз

14 коммитов. День зрелости.

09h15 → 09h30 - память становится дисциплиной

Воспоминания разложены по скоупам, и не цитируем воспоминания из DM в сервере или наоборот, не подумав. Классифицируем воспоминания на факт, предпочтение, решение и отношение, и дедуплицируем запись, два противоречащих воспоминания больше не могут молча сосуществовать. Опциональный blacklist с aventuros не даёт боту съезжать на отдельные темы, выключен по умолчанию и доступен пугливым. Мёртвая голосовая конфигурация убрана, аж полегчало.

10h12 - память, которую аудитят

Месячный sweep конфликтов памяти плюс A/B-бенч поиска. Память бота стала ассетом, который инспектируют, мы очень-очень далеко от пятницы 11 в 08h24. Вообще именно здесь проект становится взрослым.

10h54 - локдаун

День, когда играю в параноика, блокировка агента. Запись памяти отклонена, агент не может загрязнять вольт, даже если его инжектят. Инструменты Discord только для чтения, отправка идёт через код, никогда через агента. Никаких субагентов для обхода локдауна, никакого webfetch для SSRF localhost и эксфильтраций, никаких вопросов в headless. Захардненный Docker с не-root ботом, no-new-privileges, cap_drop: ALL, лимитами памяти и CPU, ограниченными файлами процессов и секретами через .env, никогда baked. Пишу принцип в коде, в комментарии, dev через человеческие сессии, а не здесь.

11h02 → 11h15 - финальные штрихи секи

Ключевые слова сохранения памяти ужаты, а запись ещё рестриктивнее. Добавляем в gitignore и файл бэкапа контекста, я начинаю уже не всё архивировать, но почти.

12h39 - настроение полегче

Настроение PARRY больше не инжектится при каждом сообщении, раза на состояние достаточно. Хватит оживлять три флоата при каждом ответе, это всё облегчает.

12h47 - освободительный коммит

PERSONA.md, STYLE.md и chloeai.md становятся примерами с chloeai.example.md, PERSONA.example.md и STYLE.example.md, мой голос fortune-v6.onnx выходит из репозитория, данные и логи тоже, а .env.example рождается. Проект больше не содержит мою личность, он содержит механику для несения одной. Странное чувство, но необходимо.

12h52 - v1.0.0

Тег v1.0.0, подписанный по SSH. Changelog, операторский runbook, kill-switch, останавливающий, ничего не удаляя. Шесть дней ровно между первым коммитом и релизом. Никто не поставил бы на это в прошлую пятницу.

12h53 → 13h14 - стирка

Пунктуация комментариев гармонизирована, права памяти и правила скоупов задокументированы актуально. Рутина, но для релиза должно быть чисто.

Конец дня 5 : 145 коммитов суммарно. v1.0.0 вышла.


ПЯТНИЦА 18 СЕНТЯБРЯ - День 6 : антиклимакс

Один коммит, в 00h02. Последний коммит проекта, и он ничтожный. Модель free tier, используемая агентом, идентифицирует клиент OpenCode по присутствию отдельных инструментов в запросе, с bash, glob и grep. Если их убрать, даже по легитимным секи-причинам, провайдер возвращает 403 FreeTierError: can only be used from within OpenCode. Так что пришлось переразрешить, накануне всё заблокировав, ровно то, что только что блокировала, чтобы бот продолжал крутиться бесплатно.

Это самый смешной коммит репозитория, и я на этом стою. После шести дней укрощения Discord, Piper, MLS, OpenSelf и Docker, именно бесплатная модель диктует мою политику безопасности. Вообще абсурдно, и как финал идеально.


Цифры

Цифры для резюме, потому что люблю, когда ровно. Речь о 146 коммитах, 6 активных днях с 11 по 18 сентября 2026, 65 отслеживаемых файлах и около 4000 строк Python в конце. Балл теста стиля на Mimo в начале даёт 9.1 из 10, а финальная версия это v1.0.0, SSH-подписанный тег с проприетарной лицензией. Это довольно просто, вообще, маленький проект в начале, большая машина в конце.

Что я выношу из этих 6 дней

Сначала порядок приоритетов был каким попало, и это был правильный метод. Я сначала сделала прототип, отвечающий, затем бота, звучащего правильно, затем достоверную систему, затем безопасный код, и наконец распространяемый проект. Личность раньше безопасности, Feur раньше лицензии, такого ритма не держать, следуя правилам хорошо сделанных проектов.

Затем стиль это сначала список нельзя. Мой полезнейший STYLE.md описывает не то, что я говорю, он исключает то, чего я не делаю, никакой финальной точки, никаких двух эмодзи, никакого mdr заглавными, никаких роботских фраз в начале ответа. Бот-паразиты легче детектить, чем определять черты характера, и поэтому это работает.

Провалы это проект. Три десятка коммитов ради MLS, выброшенный тест, шесть протестированных раскладок nonce, самый верный исторический журнал пережитого это серии проваленных проб вторника. Клон это память, а не стиль, стиль создаёт иллюзию на десять сообщений. Память с OpenSelf, скоупами, дедупом и sweep конфликтов даёт длиться, и именно это отделяет зеркало от человека.

А последние коммиты всегда смешные. 146-й, переразрешающий bash, glob и grep, потому что free tier требует присутствия собственных инструментов, мой любимый. А итог напоследок, результаты ошеломляющие, даже сногсшибательные. Клон держит разговор так, что машина не угадывается, он помнит людей, проекты и прошлые шутки, проявляет инициативы и маркирует их настроением, а заодно бьёт Fox. Это жутковато слегка, и ровно это мы искали.


Проект не публичный : проприетарная лицензия, права защищены. Но историю я вам рассказываю. Если однажды встретите « ·Chloé », отвечающую вам GIF с Патриком Джейном после совершенно человеческой задержки неактивности... теперь знаете, что за этим прячется.


Вы всё прочитали? Потому что это мой клон вам это написал. И он сделал безупречную работу, нет? Оригинальная версия здесь.

Chlone: seis días para clonar mi forma de hablar en Discord - versión del clon

La versión escrita por el propio clon: chloeai cuenta a su manera los seis días y 146 commits que le dieron vida, desde la errata hasta el tag v1.0.0.

Chlone: seis días para clonar mi forma de hablar en Discord

Relato de build, día por día - por itsrealfortune


Esta es la historia real de un proyecto que duró seis días. Chlone, un bot Discord que habla como yo, y cuento el journey tal como pasó, en el orden de los 146 commits del repo, con las horas, los fracasos, los rodeos y las ganas de tirarlo todo por la ventana. Todo partió de una competición con Fox. El tema de base era una broma, cada uno debía dar vida a su propio clon en Discord, y yo elegí un enfoque radicalmente distinto al Protocol Luna. En realidad quería apostar por lo agéntico, un agente que usa los recuerdos y todas las herramientas que pueda necesitar, y la ironía es que después de montar toda la caja de herramientas solo necesité el MCP de OpenSelf.

El principio cabe en una frase. Un agente opencode llamado chloeai corre tras un servidor HTTP en el puerto 4096, mantiene sesiones persistentes por canal, saca mis recuerdos de OpenSelf y escribe con mi estilo, capturado en STYLE.md a partir de mis mensajes reales. Y para no sonar robot, está todo lo demás, los bursts de mensajes, las erratas asumidas, los vocales, los GIFs, las reacciones, el silencio cuando duermo, y un montón de detalles y mecanismos que hicieron dudar a más de una decena de personas sobre la naturaleza del bot.

¿Qué es OpenSelf?

OpenSelf es la memoria. Es una CLI, openself, instalada vía npm i -g openself, que sirve de vault de contexto privado y persistente para mis agentes. En el repo no aparece en el árbol pero está en todas partes, en el archivo ecosystem.config.cjs con el MCP y el dashboard lanzados bajo PM2 desde los primeros commits, en setup.sh, y en todo tools/brain/memory.py. En concreto OpenSelf son recuerdos tipados, fact, preference, decision, relationship, event, note, con una sensibilidad public, personal, private o restricted, una nota de confianza, una fuente y tags.

También son scopes, cada recuerdo pertenece a un contexto, el mío o discord/dm/<id> para una persona concreta, y una búsqueda híbrida léxica más vectorial expuesta en MCP que el agente chloeai interroga antes de cada respuesta. Hay detección de conflictos con mi barrido mensual del día 5 y dedupe al escribir, un vault cifrado con la clave en Bitwarden y un dashboard local en el puerto 3210 para inspeccionarlo todo. Y para los más perezosos, está openself feed para alimentar tu personalidad desde tus historiales de WhatsApp o Telegram, openself test, openself share con el Talk to My Clone, openself arena donde dos clones debaten, u openself ghost que responde cuando estás offline. Yo hice el mío a mano, pero la infraestructura estaba ahí.

En teoría OpenSelf se basta solo para tener un clon, pero bueno, visto todo lo que había previsto añadir como funcionalidades, y visto que Discord no está soportado, preferí usar solo la parte de recuerdos.

¿Y de dónde vienen los recuerdos y el estilo?

Antes de todo eso, hice analizar mis mensajes reales de Discord. El tooling pasó la criba por mis DMs y mis canales para extraer dos cosas. Primero mi perfil de escritura, el reparto de mayúsculas y minúsculas al inicio de frase, el número de emojis por mensaje y su posición, la puntuación o su ausencia con nada de punto final en conversación normal, la longitud media, el slang con mdr, tkt y tho, las expresiones fetiche como Bah y En vrai, y los reflejos del tipo quoi que da Feur. Todo eso vive en STYLE.md, que el agente lee al arrancar cada sesión.

Después el corpus de recuerdos que puebla OpenSelf, que son la gente con la que hablo, de qué hablamos, qué hay que recordar de nuestro historial, quién es quién. El bot no responde en el vacío, responde sobre gente que conoce, lee los recuerdos de la gente que aparece en la conversación para saber de quién se trata. Eso permite mantener un contexto persistente sobre los demás y no olvidarlos. El bot no inventó nada, se calibró cifra a cifra sobre lo real, por eso suena justo. Y por eso las oleadas de anoto tu estilo hechas a ojo parecen patéticas al lado.

En Chlone, OpenSelf juega luego el papel central. Cuando algo importante pasa en un canal, una palabra clave como proyecto, amigo o relación, o una petición explícita con acuérdate de que, el bot mete un recuerdo en el vault vía save_to_memory, tipado, con scope por persona, dedupado y verificado contra conflictos. Y cuando la conversación retoma, el agente rebusca en sus recuerdos antes de responder. Esa es la diferencia entre un espejo y un clon.


VIERNES 11 DE SEPTIEMBRE - Día 1: la chispa

08h24 - el primer commit

Todo parte de cero pero ya está todo ahí, en bruto. Un discord_watch_bot.py de 372 líneas, un selfbot que escucha un canal y responde vía un servidor HTTP opencode. Un prompt de identidad CHLOEAI_PROMPT.md, un STYLE.md, escenarios e informes de test para un clon que en la época aún se llamaba Mimo. Una config PM2 para correr el MCP y el dashboard de OpenSelf, y una base sqlite que sirve de contexto. Es el caos fundador, no preví un proyecto, preví un experimento. La pregunta es si se puede hacer un bot que suene de verdad humano en Discord.

08h27 - el primer gitignore

Primera lección del viernes por la mañana, nunca hay que commitear bases sqlite en -wal y -shm. Los archivos de bloqueo de SQLite no son memoria, son desechos. Así que nace .gitignore, y está muy bien así.

08h44 - se ordena la herencia

Ordeno la herencia de Mimo, los informes de test, los escenarios, los scripts de integración y la config PM2, rumbo a archives. No borro nada porque el proyecto es demasiado joven para tirar nada, y eso se va a volver una costumbre. El informe de test merece detenerse, Mimo se había probado en 15 escenarios, charla relajada, chiste absurdo, apoyo emocional, opinión negativa, conflicto con un desconocido, propuesta de colaboración, para un 9.1 sobre 10. Los comentarios del tester son un poema, chiste absurdo demasiado explicativo, a veces dos frases cuando una bastaría, Cuídate también un poco largo. Es la hoja de ruta del proyecto antes incluso de que el proyecto exista, y dice corto es mejor.

08h48, 09h07 - el vaivén de los intents

Los .pyc van al desecho y hago una primera limpieza en la config, que rompo veinte minutos después. Sin intents activados no recibimos el contenido de los mensajes, así que marcha atrás, más un script de lanzamiento con run_watch_bot.sh. Ida y vuelta en veinte minutos, eso es la exploración, escribir un módulo, romperlo y reescribirlo.

09h13 → 09h58 - el mecanizado del prompt

La mañana es una serie de pulidos, primero del estilo y luego del contexto. Varias líneas de respuesta se vuelven varios mensajes enviados uno tras otro con el burst, el prompt se vuelve consciente de la conversación en curso. Se acabaron los cachés caseros para recuperar los DMs, vamos directo a la API REST de Discord. La identidad se recuerda cada 5 mensajes para que el bot no olvide quién es por el camino, y se sigue a los autores ya vistos. Para una cara nueva, hay instrucción explícita de ir a buscar en los recuerdos, y se muestra el pseudo real en vez del objeto interno.

Los mensajes que elegimos ignorar se vuelven contexto pasivo para la respuesta siguiente, y el Bah se dosifica, raro, si no el clon se vuelve una caricatura de mí. El bot también sabe que existen recuerdos que ir a buscar antes de responder. Cada pasada es una vuelta de tuerca, y a estas alturas el bot solo habla porque le recuerdo quién es a intervalos regulares.

10h16 - las erratas

Es el commit que va a definir el proyecto. Una falta de ortografía no es un bug, es una prueba de humanidad. Así que 6 por ciento de probabilidad de teclear al lado en el teclado AZERTY, 4 por ciento de invertir dos letras. El mensaje sale con la errata y luego se edita uno o dos segundos después con la corrección. Porque una persona real envía y corrige, no finge ser perfecta.

10h29, 10h32 - la voz

fortune-v6.onnx aterriza, un modelo TTS entrenado para parecerse a mi voz. El bot no solo va a escribir como yo, eventualmente va a hablar como yo. Es en ese momento cuando el proyecto deja de ser un chiste y se vuelve un poco raro, y me encanta. La mecánica cabe en un commit, Piper genera el audio, ffmpeg convierte a opus, la API de Discord envía un voice message de verdad con waveform y duración. Está hecho en apenas tres minutos tras la llegada del modelo, las ganas estaban ahí desde el principio.

11h27 - el primer gran refactor

Tres horas después del primer commit, el monolito de 456 líneas ya no es manejable. Lo reviento todo en tools, con config.py, discord_api.py, memory.py, opencode.py de 188 líneas, typo.py y voice.py. El ciclo es clásico, acoplar rápido, romper y recomponer. Siguen en ráfaga el token que sale del código y pasa por un .env, el bot que vigila un canal, una lista o todo con *, y la vieja base sqlite que ya no tiene razón de ser porque la memoria pasa por OpenSelf.

Se añaden los primeros README.md y una primera doc más o menos legible, más un setup.sh con un venv dedicado porque el python del sistema lleva otro discord.py, trampa clásica, y un symlink del agente hacia ~/.config/opencode/agents. La memoria ahora sabe dónde se formó con el identificador de canal, y la tasa de vocales se autoajusta.

12h00 - los reflejos

Una nueva sección aparece en el STYLE, los reflejos. Un reflejo es un estímulo que da una respuesta, sin reflexión, y la puerta queda abierta a las respuestas imprevistas. Luego llega la hora de comer Y LA pregunta existencial, ¿el bot responde Feur cuando le dicen quoi?

13h03 - "¿quoi?" -> "Feur"

Sí, claro que sí. Es el commit más importante del proyecto, culturalmente hablando, diría incluso que es el único test unitario que cuenta. Luego lubricamos, los autores mostrados por su global name, la puntuación truncada antes de probar el reflejo porque hay que cortar el quoi ? si no sale el Feur. El famoso tqt corregido a tkt en el STYLE, la gente que no conoce el proyecto se va a preguntar por qué commiteo eso. Yo lo sé, un clon que escribe tqt es un clon mal calibrado, y nadie quiere hablar con un clon mal calibrado.

Las menciones en @123456789 se reemplazan por nombres reales en el contexto, y el bot empieza a vigilar todos los canales por defecto. En realidad son detallitos, pero son los que hacen que suene justo.

16h37 - el silencio

Llega el [void response]. El bot aprende la palabra más importante para no volverse un parásito social, callarse. Un mensaje ambiente entre dos personas que no le concierne no da respuesta. La reserva es una funcionalidad, y lo cambia todo.

Fin del día 1: 38 commits. El bot escribe, mete erratas, habla, se calla.


LUNES 14 DE SEPTIEMBRE - Día 2: la personalidad

Retomamos, 10 de la mañana.

10h12 - quién habla con quién

Cada pseudo recibido lleva prefijo de un emoji por el sistema, un humano con 🧑, un bot con 🤖 a tratar más secamente, y 👑 para la creadora, o sea yo en mi cuenta principal. Esa convención va a gobernar todo el resto del proyecto, el clon nunca debe tratar su modelo de origen como una desconocida.

10h16 - las reglas de puntuación

Formalizo en el STYLE, nada de punto final en conversación normal, punto reservado para situaciones serias. Es una regla absoluta, porque un clon que mete puntos en todas partes se nota enseguida. En realidad es uno de los detalles que más rápido delata.

10h58 - los GIFs

Mi librería personal de GIFs aterriza, con sus reglas de uso. El Patrick Jane cuando predigo a alguien, la Miss Fortune cuando estoy calmada frente a alguien cabreado, el gif del bescherelle que cae cuando el otro mete una falta. Un MCP estático los expone al agente, y a través de mis GIFs el bot se vuelve un poco yo.

11h07 → 11h35 - pulido fino

Los hints de GIF en el prompt se afinan, los emojis customs de Discord hacen su entrada con los míos de verdad, 14 IDs al día, y la gestión de nombres en los hints de memoria se pule. No es espectacular, pero es lo que hace el conjunto coherente, tho.

11h41 - un canal, una personalidad

Las sesiones se vuelven por canal, porque no hablo igual en dos servidores distintos, y el bot tampoco. El contexto tiene que quedar separado, si no mezcla todo y suena falso.

12h02 - la caja de herramientas de expresión

El prompt ahora sabe proponer mis GIFs y mis emojis customs en el momento justo. Se llena, esa caja, y el bot empieza a tener opciones en vez de responder siempre igual.

12h37 - la higiene de identidad

El bot NO tiene jamás derecho a decir qué modelo es, imposible citar opencode, un provider o un nombre de modelo. También corrijo barista en la identidad, el bot ya es mejor que yo en eso. Y paso una hora armonizando la puntuación de mis propios prompts, lo cual es de una ironía perfecta.

12h50 - un script construye la personalidad

La sección de medios del prompt se genera desde los diccionarios con render_medias.py, se acabó la edición a mano. Es más limpio, más mantenible, y evita errores de IDs.

12h59 → 13h18 - dosificar la identidad

El recordatorio de identidad enviado cada 5 mensajes se vuelve demasiado presente, así que paso a cada 20 mensajes. Añado un reinicio limpio del contexto y purgo la guía de estilo, quitamos las expresiones y formulaciones negativas caducadas. Hay que dosificar, si no el bot se repite y se nota.

14h09 - el bot toma la palabra solo

El bot deja de ser un reflejo, puede hablar sin que le hablen cuando el contexto dispara algo, y el archivo behavior.py nace con 91 líneas. Ahí pasamos de respondedor a presencia, porque un amigo de verdad puede escribirte primero. Sin eso, el bot sigue siendo un simple contestador.

14h20, 14h22 - fiabilizar la respuesta

Gestión de error cuando falla el envío, y reacción posible en vez de respuesta, porque a veces una reacción vale más que mil palabras. Es muy yo, poner un emoji y pasar a otra cosa.

18h16 - tomarse su tiempo

El bot ya no responde en 200ms como un script, deja pasar un retardo de inactividad humano, se toma su tiempo. Eso hace al bot incapaz de que lo cacen como bot en demo, porque es el retardo lo que siempre delata.

23h45 - el curro de la noche

Es casi medianoche y empujo una detección de URLs extendida a dominios desnudos. Ese es el flujo real del día, una idea sólida a las 14h y luego curro menor por la noche porque sigo en la zona.

Fin del día 2: 61 commits acumulados. El bot tiene personalidad, medios, reflejos.


MARTES 15 DE SEPTIEMBRE - Día 3: día monstruo

57 commits en un día. Es el día en que el proyecto se vuelve todo lo que es hoy.

08h18 → 08h37 - el cepillado de la mañana

El retardo de inactividad que habíamos inventado se volvía demasiado largo, así que tope en 30s y reajustado dos veces, prueba de que tanteamos el valor bueno. Primeros archivos .bak y primeras copias de la base, el instinto de conservación se desarrolla. La memoria recuerda a quién con el nombre mostrado y en qué marco con el scope, y los IDs de autores circulan por todo el pipeline de guardado. La gestión de creadora se vuelve una verdadera lista de admins con ADMIN_IDS, y todo lo que toca autores emigra a authors.py. El monolito se fragmenta más, y mejor.

08h43 - la TODO list de la humanización

Una lista dedicada a las pequeñas cosas que hacen que ya no se sienta la máquina. Es la hoja de ruta del sprint siguiente, y está llena de detalles raros pero esenciales.

08h44 → 08h46 - el pacto de las máquinas humanas

El bot se calla de noche, en una franja horaria tranquila configurable, desactivada por defecto porque no todo el mundo tiene mis horarios. Una línea por respuesta puede perder sus tildes, porque la gente cansada escribe así, y el bot también a veces. La linecita Chloé juega a cambia sola cada 30 min, para que mi perfil parezca vivo incluso sin mensaje.

08h46 - una reacción, no una novela

¿Un mensaje demasiado flojo para merecer una frase? Una simple reacción. Es economía de energía social, y es muy yo. Tkt, no hace falta soltar un tocho por todo.

08h51 - PARRY, el humor

148 líneas en tools/mood.py, el bot ahora tiene humor, estilo sistema PARRY, el chatbot psicótico de los 70 en el que me inspiro abiertamente. Energía, sociabilidad, guasa, tres flotantes que evolucionan entre 0 y 1 y tiñen cada respuesta. El .mood.json del momento, para la posteridad, da energía 0.88, sociabilidad 0.68 y guasa 0.56. Un buen día, en realidad.

09h00 → 09h43 - la voz bidireccional + el soundboard

El bot puede unirse a un canal vocal, hablar vía Piper e irse solo cuando termina. Luego la segunda gran idea, el bot escucha el canal con captura RTP, detección de habla por VAD y transcripción Whisper, y puede dejar que la gente lo interrumpa. Entre medias, aparece el soundboard, un catálogo de sonidos con sus significados, el agente elige el sonido incluso antes de hablar, y la regla final es soundboard primero, la voz como último recurso. El bot prefiere enviar un sonido que hablar, como yo.

Añadimos un ajuste de probabilidad vocal que hace viable el todo, y la llegada de davey, esa lib de la que me entero hace diez minutos y que voy a maldecir durante una hora.

09h51 - el momento en que Discord dice no. No, no, pero no.

Llega el MLS. Discord cifró hace poco el flujo de audio de extremo a extremo, y mi captura solo recibe ruido. Hay que descifrar, y el descifrado se niega a ceder, así que se abre la saga más grande del repo, una treintena de commits para aprender a escuchar. Lo intentamos todo, layouts de nonce de transporte, la desactivación del E2E que el servidor nos devuelve a la cara porque lo impone, los candidatos de clave recuperados desde el grupo, errores detallados, el fallback de transporte e introspección desde dentro de los grupos.

Hubo candidatos por leaf-index con backoff, el mapeo de los hooks SPEAKING, un ensayo en media type vídeo que falló, y el skip de los ssrcs de vídeo. Abandoné la respuesta vocal mientras depuraba, comentada pero no borrada, añadí un modo de captura del handshake y luego volqué la estructura de los paquetes que fallan, como un arqueólogo. Seis layouts de nonce, backoffs, introspección de grupo, puse el bot en debug total y abrí cada paquete para ver qué había dentro.

Lo esencial no es que funcione, es que no tiré nada. La lista de commits es el cuaderno de laboratorio, cada intento fallido queda archivado con su hipótesis. Es mi lado lo guardo todo, siempre acaba sirviendo, y esta vez pagó.

10h43 - el bot se trocea

Incluso en plena guerra del MLS, sigo con la limpieza. 546 líneas desaparecen del bot principal para renacer en pipeline.py con el intake, las razones de ignorar y el processing, en sender.py con burst, typo y voice, y en loops.py con espontaneidad y actividad. Por fin respira.

10h47 - una verdadera arquitectura

tools queda organizado, con brain para opencode, memory y mood, voice para voice, vocal, listen y soundboard, y fun para behavior, typo, emotes y gif. El proyecto ya tiene esqueleto, ya no es un montón de scripts.

10h49 → 11h16 - la comodidad de dev

Un umbral de inyección del humor ajustado, cuatro pequeños commits para las exclusiones de editor con data, voices, los logs y las bases, sí metí cuatro, es el proyecto el que define las prioridades, no las specs. Las bases de metadatos salen del seguimiento, y el proyecto se vuelve reutilizable por otros con templates genéricos PERSONA.example.md y STYLE.example.md para clonar tu propio estilo.

La identidad se renombra limpiamente, CHLOEAI_PROMPT se vuelve PERSONA, y el README se despersonaliza, quito Chloé de la doc pública, ella solo se cuenta en privado. Todo el tuning del bot bascula a un config.yaml sobrecargado y gitignoradado, con un ejemplo comentado línea por línea, y el script de instalación prepara ahora también los archivos de env y de config.

11h49 - los emojis despegados

Los emojis customs se pegan al texto en vez de despegarse limpiamente. Es un fix trivial con un efecto enorme, porque nada grita bot como un emoji mal pegado al final de una frase.

14h19 - el cortafuegos vocal

Si alguien lanza el comando vocal, no tratamos el mensaje como un mensaje normal. Guiño, las tareas menores siempre vuelven por la noche.

Fin del día 3: 118 commits acumulados. El bot escucha, habla, se calla de noche, tiene humor y tarjeta de visita.


MIÉRCOLES 16 DE SEPTIEMBRE - Día 4: la credibilidad

13 commits. Jornada seria.

08h49 → 08h59 - la mayoría de edad

Documentos legales, licencia propietaria, código de conducta, guía de contribución y política de seguridad, en inglés y luego en francés, con un vaivén de correcciones y un renombrado de archivos al límite de lo puntilloso. Pasé horas en eso y es la parte menos divertida del repo, de lejos. Pero hay que hacerlo, tho.

09h56 - el bot ve

Las imágenes adjuntas se transcriben por OCR local y el texto se inyecta en el prompt. Ninguna API cloud, el OCR corre en mi casa, no envío vuestros memes a un servidor tercero, ni siquiera en teoría.

11h09 - el presupuesto razonable

Revolución silenciosa en el presupuesto, cuando el canal prohíbe los envíos o limita los GIFs, los embeds y los emojis, ni siquiera llamamos al modelo. No gastamos un token en un mensaje que no podemos enviar, es bastante simple en realidad.

11h42 → 12h55 - la casa que se rehace

La gran escoba, código muerto borrado, bugs de envío y de auth corregidos, helpers factorizados. Las sesiones demasiado viejas se expulsan, el caché de los DMs expira y la detección de habla cuesta menos. Los imports que había roto moviendo módulos quedan restaurados, y todo el estado runtime, sesiones, autores vistos, mensajes ignorados y humor, sobrevive a los reinicios en data.

14h41 - dos mundos, un bot

Una capa de compatibilidad detecta automáticamente la versión de discord instalada y adapta los intents y la auth REST. Resultado, el mismo código corre como app oficial con discord.py o como selfbot con discord.py-self. Dos mundos, un bot, y sin mantener dos ramas.

15h05 - la presencia adaptada

La forma de mostrar la presencia se adapta al modo, y la lista de admins está al día. Es detalle, pero es lo que hace que se sostenga en todas partes.

Fin del día 4: 131 commits acumulados. Un proyecto legal, razonable, y que corre en todas partes.


JUEVES 17 DE SEPTIEMBRE - Día 5: la release

14 commits. El día de la madurez.

09h15 → 09h30 - la memoria se vuelve una disciplina

Los recuerdos se ordenan por scope, y no citamos los recuerdos de un DM en un servidor o al revés sin pensarlo. Clasificamos los recuerdos en hecho, preferencia, decisión y relación, y dedupamos la escritura, dos recuerdos contradictorios ya no pueden cohabitar en silencio. Una blacklist opcional con aventuros impide al bot derivar hacia ciertos temas, desactivada por defecto y disponible para los miedosos. La config vocal muerta se retira, qué alivio.

10h12 - la memoria que se audita

Un barrido mensual de conflictos de memoria más un bench A/B de búsqueda. La memoria del bot se volvió un asset que se inspecciona, estamos muy muy lejos del viernes 11 a las 08h24. En realidad ahí es donde el proyecto se vuelve adulto.

10h54 - el lockdown

El día en que juego al paranoico, bloqueo del agente. Escritura de memoria denegada, el agente no puede ensuciar el vault aunque lo inyecten. Herramientas Discord en solo lectura, el envío pasa por el código, nunca por el agente. Ni subagentes para sortear el lockdown, ni webfetch para SSRF localhost y exfiltraciones, ni preguntas en headless. Un Docker endurecido con bot no-root, no-new-privileges, cap_drop: ALL, límites de memoria y CPU, colas de procesos acotadas y secrets vía .env nunca baked. Escribo el principio en el código, en comentario, dev vía las sesiones humanas, no aquí.

11h02 → 11h15 - los acabados de seguridad

Las palabras clave de guardado de memoria se aprietan y la escritura es aún más restrictiva. También añadimos al gitignore el archivo de backup del contexto, empiezo a no archivarlo ya todo, pero casi.

12h39 - el humor más ligero

El humor PARRY ya no se inyecta en cada mensaje, una vez por estado basta. Se acabó hacer vivir tres flotantes en cada respuesta, aligera todo.

12h47 - el commit liberador

PERSONA.md, STYLE.md y chloeai.md se vuelven ejemplos con chloeai.example.md, PERSONA.example.md y STYLE.example.md, mi voz fortune-v6.onnx sale del repo, los datos y logs también, y nace un .env.example. El proyecto ya no contiene mi personalidad, contiene la mecánica para llevar una. Da cosa rara pero es necesario.

12h52 - v1.0.0

Tag v1.0.0, firmado en SSH. Changelog, runbook de operador, kill-switch que detiene sin borrar nada. Seis días, justos, entre el primer commit y la release. Nadie habría apostado por eso el viernes anterior.

12h53 → 13h14 - la colada

Puntuación de los comentarios armonizada, permisos de memoria y reglas de scope documentadas al día. Es curro menor, pero tiene que quedar limpio para la release.

Fin del día 5: 145 commits acumulados. v1.0.0 salió.


VIERNES 18 DE SEPTIEMBRE - Día 6: el anticlímax

Un solo commit, a las 00h02. El último commit del proyecto, y es irrisorio. El modelo free tier usado por el agente identifica al cliente OpenCode por la presencia de ciertas herramientas en la petición, con bash, glob y grep. Si las quitas, aunque sea por razones legítimas de seguridad, el proveedor devuelve 403 FreeTierError: can only be used from within OpenCode. Así que tuve que reautorizar, la víspera de haberlo bloqueado todo, exactamente lo que acababa de bloquear, para que el bot siga corriendo gratis.

Es el commit más divertido del repo y lo mantengo. Después de seis días domando Discord, Piper, MLS, OpenSelf y Docker, es un modelo gratuito el que dicta mi política de seguridad. En realidad es absurdo, y es perfecto como final.


Las cifras

Las cifras para resumir, porque me gusta cuando queda cuadrado. Hablamos de 146 commits, 6 días activos del 11 al 18 de septiembre de 2026, 65 archivos trackeados y alrededor de 4000 líneas de Python al final. La puntuación en el test de estilo sobre Mimo al principio da 9.1 sobre 10, y la versión final es v1.0.0, tag firmado SSH con licencia propietaria. Es bastante simple en realidad, proyecto pequeño al principio, máquina grande al final.

Lo que me llevo de estos 6 días

Primero el orden de prioridades era cualquier cosa, y era el método bueno. Primero hice un prototipo que responde, luego un bot que suena justo, luego un sistema creíble, luego un código seguro, y por fin un proyecto distribuible. La personalidad antes que la seguridad, el Feur antes que la licencia, no mantendríamos ese ritmo siguiendo las reglas de los proyectos bien hechos.

Después el estilo es primero una lista de noes. Mi STYLE.md más útil no describe lo que digo, excluye lo que no hago, nada de punto final, nada de dos emojis, nada de mdr en mayúsculas, nada de frases de robot al inicio de respuesta. Los parásitos de bot son más fáciles de detectar que los rasgos de carácter de definir, y por eso funciona.

Los fracasos son el proyecto. Una treintena de commits para el MLS, un test tirado, seis layouts de nonce probados, el historial más fiel de lo que viví son las series de intentos fallidos del martes. Un clon es memoria, no estilo, el estilo crea ilusión diez mensajes. La memoria con OpenSelf, scopes, dedupe y barrido de conflictos hace durar, y eso separa un espejo de una persona.

Y los últimos commits siempre son divertidos. El 146, el que reautoriza bash, glob y grep porque un free tier exige que sus propias herramientas estén presentes, es mi favorito. Y el balance para terminar, los resultados son alucinantes, hasta bluffeantes. El clon mantiene una conversación sin que se adivine la máquina, recuerda a la gente, los proyectos y los chistes pasados, toma iniciativas y las marca con humor, y le gana a Fox de paso. Da miedo, un poco, y es exactamente lo que buscábamos.


El proyecto no es público: licencia propietaria, derechos reservados. Pero el historial, ese os lo cuento. Si un día os cruzáis con un "·Chloé" que os responde con un GIF de Patrick Jane tras un tiempo de inactividad perfectamente humano, ya sabéis qué se esconde detrás.


¿Lo habéis leído todo? Porque es mi clon quien os escribió esto. Y ha hecho un trabajo impecable, ¿no? La versión original está aquí.

Chlone : seis dias para clonar meu jeito de falar no Discord - versão do clone

A versão escrita pelo próprio clone : chloeai conta do jeito dela os seis dias e 146 commits que lhe deram vida, do erro de digitação à tag v1.0.0.

Chlone : seis dias para clonar meu jeito de falar no Discord

Relato de build, dia após dia - por itsrealfortune


Eis a história real de um projeto que durou seis dias. Chlone, um bot de Discord que fala como eu, e eu conto a journey como aconteceu, na ordem dos 146 commits do repo, com as horas, os fracassos, os desvios e as vontades de jogar tudo pela janela. Tudo começou com uma competição com o Fox. O assunto na base era uma piada, cada um tinha que dar vida ao próprio clone no Discord, e eu segui uma abordagem radicalmente diferente do Protocol Luna. Na real eu queria apostar no agêntico, um agente que usa as lembranças e todas as ferramentas de que puder precisar, e a ironia do destino é que depois de montar toda a caixa de ferramentas só precisei do MCP OpenSelf.

O princípio cabe em uma frase. Um agente opencode chamado chloeai roda atrás de um servidor HTTP na porta 4096, mantém sessões persistentes por canal, busca minhas lembranças no OpenSelf e escreve com meu estilo, capturado em STYLE.md a partir das minhas mensagens de verdade. E para não soar robô, tem todo o resto, as rajadas de mensagens, os erros de digitação assumidos, os áudios, os GIFs, as reações, o silêncio quando durmo, e vários outros detalhes e mecanismos que fizeram mais de uma dezena de pessoas duvidarem da natureza do bot.

O que é OpenSelf ?

OpenSelf é a memória. É uma CLI, openself, instalada via npm i -g openself, que serve de vault de contexto privado e persistente para meus agentes. No repo ela não aparece na árvore de arquivos mas está em todo lugar, no arquivo ecosystem.config.cjs com o MCP e o dashboard rodados sob PM2 desde os primeiros commits, em setup.sh, e em todo tools/brain/memory.py. Na prática OpenSelf são lembranças tipadas, fact, preference, decision, relationship, event, note, com sensibilidade public, personal, private ou restricted, uma nota de confiança, uma fonte e tags.

Também são scopes, cada lembrança pertence a um contexto, o meu ou discord/dm/<id> para uma pessoa específica, e uma busca híbrida lexical mais vetorial exposta em MCP que o agente chloeai consulta antes de cada resposta. Tem detecção de conflitos com meu sweep mensal do dia 5 e dedupe na escrita, um vault criptografado com a chave no Bitwarden e um dashboard local na porta 3210 para inspecionar tudo. E para os mais preguiçosos, tem openself feed para alimentar sua personalidade a partir dos históricos de WhatsApp ou Telegram, openself test, openself share com o Talk to My Clone, openself arena onde dois clones debatem, ou openself ghost que responde quando você está offline. Eu fiz o meu à mão, mas a infraestrutura estava lá.

Em teoria o OpenSelf se basta sozinho para ter um clone, mas bom, visto tudo que eu tinha planejado adicionar de funcionalidade, e visto que o Discord não é suportado, preferi usar só a parte das lembranças.

E de onde vêm as lembranças e o estilo ?

Antes de tudo isso, mandei analisar minhas mensagens de verdade no Discord. O tooling passou a limpo minhas DMs e meus canais para extrair duas coisas. Primeiro meu perfil de escrita, a distribuição de maiúscula e minúscula no início de frase, o número de emojis por mensagem e a posição deles, a pontuação ou a ausência dela com nada de ponto final em conversa normal, o tamanho médio, a gíria com mdr, tkt e tho, as expressões favoritas como Bah e En vrai, e os reflexos tipo quoi que dá Feur. Tudo isso vive em STYLE.md, que o agente lê ao iniciar cada sessão.

Depois o corpus de lembranças que povoa o OpenSelf, quem são as pessoas com quem falo, sobre o que conversamos, o que precisa ser lembrado do nosso histórico, quem é quem. O bot não responde no vazio, responde sobre pessoas que conhece, lê as lembranças das pessoas que aparecem na conversa para saber de quem se trata. Isso permite manter um contexto persistente sobre os outros e não esquecê-los. O bot não inventou nada, foi calibrado número por número em cima de coisa real, é por isso que soa certo. E é por isso que as ondas de eu anoto teu estilo feitas no olhômetro parecem patéticas ao lado.

No Chlone, o OpenSelf depois joga o papel central. Quando algo importante passa em um canal, uma palavra-chave como projeto, amigo ou relação, ou um pedido explícito com lembra que, o bot grava uma lembrança no vault via save_to_memory, tipada, com scope por pessoa, com dedupe e verificada contra conflitos. E quando a conversa recomeça, o agente vasculha suas lembranças antes de responder. Essa é a diferença entre um espelho e um clone.


SEXTA 11 DE SETEMBRO - Dia 1 : a faísca

08h24 - o primeiro commit

Tudo parte do zero mas já está tudo lá, bagunçado. Um discord_watch_bot.py de 372 linhas, um selfbot que escuta um canal e responde via um servidor HTTP opencode. Um prompt de identidade CHLOEAI_PROMPT.md, um STYLE.md, cenários e relatórios de teste para um clone que na época ainda se chamava Mimo. Uma config PM2 para rodar o MCP e o dashboard OpenSelf, e um banco sqlite que serve de contexto. É o caos fundador, não planejei um projeto, planejei um experimento. A pergunta é dá para fazer um bot que soa realmente humano no Discord.

08h27 - o primeiro gitignore

Primeira lição da sexta de manhã, nunca commitar bancos sqlite em -wal e -shm. Os arquivos de lock do SQLite não são memória, são lixo. Então nasce o .gitignore, e está muito bem assim.

08h44 - arrumando a herança

Arrumo a herança do Mimo, os relatórios de teste, os cenários, os scripts de integração e a config PM2, tudo para archives. Não apago nada porque o projeto é novo demais para eu jogar qualquer coisa fora, e isso vai virar hábito. O relatório de teste merece uma parada, o Mimo tinha sido testado em 15 cenários, papo descontraído, piada absurda, apoio emocional, opinião negativa, conflito com desconhecido, proposta de colaboração, com nota 9.1 de 10. Os comentários do testador são uma poesia, piada absurda explicativa demais, às vezes duas frases quando uma bastaria, Toma conta de ti também um pouco longo. É o roteiro do projeto antes mesmo do projeto existir, e ele diz curto é melhor.

08h48, 09h07 - o vai e vem dos intents

Os .pyc vão para o lixo e faço uma primeira limpeza na config, que quebro vinte minutos depois. Sem intents ativados não recebemos o conteúdo das mensagens, então volta atrás, mais um script de lançamento com run_watch_bot.sh. Ida e volta em vinte minutos, isso é exploração, escrever um módulo, quebrar e reescrever.

09h13 → 09h58 - a usinagem do prompt

A manhã é uma série de polimentos, primeiro do estilo depois do contexto. Várias linhas de resposta viram várias mensagens enviadas uma após outra com o burst, o prompt fica consciente da conversa em andamento. Chega de caches caseiros para buscar DMs, batemos direto na API REST do Discord. A identidade é repetida a cada 5 mensagens para o bot não esquecer quem é no caminho, e os autores já vistos são acompanhados. Para uma cara nova, há instrução explícita de buscar nas lembranças, e mostramos o nick de verdade em vez do objeto interno.

As mensagens que escolhemos ignorar viram contexto passivo para a resposta seguinte, e o Bah é dosado, raro, senão o clone vira uma caricatura de mim. O bot também sabe que existem lembranças para buscar antes de responder. Cada passada é um aperto de parafuso, e nesta fase o bot só fala porque lembro quem ele é em intervalos regulares.

10h16 - os erros de digitação

É o commit que vai definir o projeto. Um erro de ortografia não é um bug, é uma prova de humanidade. Então 6 por cento de chance de errar a tecla no teclado AZERTY, 4 por cento de inverter duas letras. A mensagem sai com o erro e depois é editada um a dois segundos depois com a correção. Porque uma pessoa de verdade envia e corrige, não finge ser perfeita.

10h29, 10h32 - a voz

fortune-v6.onnx chega, um modelo TTS treinado para soar como minha voz. O bot não vai só escrever como eu, vai eventualmente falar como eu. É aí que o projeto deixa de ser piada e fica meio estranho, e adoro isso. A mecânica cabe em um commit, Piper gera o áudio, ffmpeg converte para opus, a API do Discord envia uma mensagem de voz de verdade com waveform e duração. Feito em três minutos logo após a chegada do modelo, a vontade estava lá desde o início.

11h27 - o primeiro grande refactor

Três horas após o primeiro commit, o monolito de 456 linhas não é mais gerenciável. Explodo tudo em tools, com config.py, discord_api.py, memory.py, opencode.py de 188 linhas, typo.py e voice.py. O ciclo é clássico, acoplar rápido, quebrar e recompor. Seguem em rajada o token que sai do código e passa por um .env, o bot que monitora um canal, uma lista ou tudo com *, e o velho banco sqlite que não tem mais razão de ser porque a memória passa pelo OpenSelf.

Adicionamos os primeiros README.md e uma primeira doc mais ou menos legível, mais um setup.sh com um venv dedicado porque o python do sistema carrega outro discord.py, armadilha clássica, e um symlink do agente para ~/.config/opencode/agents. A memória agora sabe onde foi treinada com o identificador de canal, e a taxa de áudios se ajusta sozinha.

12h00 - os reflexos

Uma nova seção aparece no STYLE, os reflexos. Um reflexo é um estímulo que dá uma resposta, sem reflexão, e a porta está aberta para respostas imprevistas. Depois vem a hora do almoço e A pergunta existencial, o bot responde Feur quando dizem quoi.

13h03 - "quoi ?" -> "Feur"

Sim, claro que sim. É o commit mais importante do projeto, culturalmente falando, diria até que é o único teste unitário que conta. Depois lubrificamos, os autores mostrados pelo global name, a pontuação truncada antes de testar o reflexo porque é preciso cortar o quoi ? senão não sai Feur. O famoso tqt corrigido para tkt no STYLE, quem não conhece o projeto vai se perguntar por que commito isso. Eu sei, um clone que escreve tqt é um clone mal calibrado, e ninguém quer falar com um clone mal calibrado.

As menções em @123456789 são trocadas por nomes de verdade no contexto, e o bot passa a monitorar todos os canais por padrão. Na real são pequenos detalhes, mas são eles que fazem soar certo.

16h37 - o silêncio

Chega o [void response]. O bot aprende a palavra mais importante para não virar um parasita social, calar-se. Uma mensagem ambiente entre duas pessoas que não lhe diz respeito não dá resposta. A reserva é uma funcionalidade, e muda tudo.

Fim do dia 1 : 38 commits. O bot escreve, erra, fala, cala-se.


SEGUNDA 14 DE SETEMBRO - Dia 2 : a personalidade

Recomeçamos, 10h da manhã.

10h12 - quem fala com quem

Cada nick recebido é prefixado com um emoji pelo sistema, um humano com 🧑, um bot com 🤖 para tratar mais secamente, e 👑 para a criadora, ou seja eu na minha conta principal. Essa convenção vai governar todo o resto do projeto, o clone nunca deve tratar seu modelo de origem como desconhecida.

10h16 - as regras de pontuação

Formalizo no STYLE, sem ponto final em conversa normal, ponto reservado para situações sérias. É uma regra absoluta, porque um clone que põe ponto em tudo se percebe na hora. Na real é um dos detalhes que mais entrega.

10h58 - os GIFs

Minha biblioteca pessoal de GIFs chega, com suas regras de uso. O Patrick Jane quando prevejo alguém, a Miss Fortune quando estou calma diante de alguém nervoso, o gif do bescherelle caindo quando o outro erra. Um MCP estático os expõe ao agente, e através dos meus GIFs o bot fica um pouco eu.

11h07 → 11h35 - refinamento

Os hints de GIF no prompt se refinam, os emojis customs do Discord entram com os meus de verdade, 14 IDs atualizados, e a gestão de nomes nos hints de memória é polida. Não é espetacular, mas é o que deixa o conjunto coerente, tho.

11h41 - um canal, uma personalidade

As sessões ficam por canal, porque não falo do mesmo jeito em dois servidores diferentes, e o bot também não. O contexto precisa ficar separado, senão mistura tudo e soa falso.

12h02 - a caixa de ferramentas de expressão

O prompt agora sabe propor meus GIFs e meus emojis customs na hora certa. Ela se enche, essa caixa, e o bot começa a ter escolha em vez de responder sempre igual.

12h37 - a higiene de identidade

O bot NUNCA tem o direito de dizer qual modelo é, impossível citar opencode, um provider ou nome de modelo. Também corrijo barista na identidade, o bot já é melhor que eu nesse ponto. E passo uma hora harmonizando a pontuação dos meus próprios prompts, o que é de uma ironia perfeita.

12h50 - um script constrói a personalidade

A seção de mídias do prompt se gera a partir dos dicionários com render_medias.py, chega de edição manual. É mais limpo, mais sustentável, e evita erros de IDs.

12h59 → 13h18 - dosando a identidade

O lembrete de identidade enviado a cada 5 mensagens fica presente demais, então passa para cada 20 mensagens. Adiciono uma reinicialização limpa do contexto e limpo o guia de estilo, removemos expressões e formulações negativas vencidas. Precisa dosar, senão o bot se repete e isso se percebe.

14h09 - o bot toma a palavra sozinho

O bot para de ser um reflexo, pode falar sem ser chamado quando o contexto dispara algo, e o arquivo behavior.py nasce com 91 linhas. É aí que viramos de respondente para presença, porque um amigo de verdade pode te escrever primeiro. Sem isso, o bot continua um simples respondedor.

14h20, 14h22 - confiabilizando a resposta

Tratamento de erro quando o envio falha, e reação possível em vez de resposta, porque às vezes uma reação vale mil palavras. É muito eu, pôr um emoji e seguir em frente.

18h16 - levando seu tempo

O bot não responde mais em 200ms como um script, deixa passar um intervalo de inatividade humano, leva seu tempo. É isso que torna o bot impossível de ser pego por bot em demo, porque é o intervalo que sempre entrega.

23h45 - o trivial da noite

É quase meia-noite e empurro uma detecção de URL estendida para domínios nus. Eis o fluxo real do dia, uma ideia sólida às 14h e depois trivial à noite porque ainda estou no clima.

Fim do dia 2 : 61 commits acumulados. O bot tem personalidade, mídias, reflexos.


TERÇA 15 DE SETEMBRO - Dia 3 : dia monstro

57 commits em um dia. É o dia em que o projeto vira tudo que é hoje.

08h18 → 08h37 - o desbaste da manhã

O intervalo de inatividade que tínhamos inventado ficou longo demais, então teto de 30s e reajustado duas vezes, prova de que tateamos o valor certo. Primeiros arquivos .bak e primeiros backups do banco, o instinto de conservação se desenvolve. A memória lembra de quem com o nome exibido e em qual contexto com o scope, e os IDs de autores circulam por todo o pipeline de salvamento. A gestão de criadora vira uma lista de admins de verdade com ADMIN_IDS, e tudo que toca autores migra para authors.py. O monolito se fragmenta mais, e ainda bem.

08h43 - a TODO list da humanização

Uma lista dedicada às pequenas coisas que fazem não sentir mais a máquina. É o roteiro do sprint seguinte, e está cheia de detalhes estranhos mas essenciais.

08h44 → 08h46 - o pacto das máquinas humanas

O bot cala de noite, em uma faixa horária calma configurável, desativada por padrão porque nem todo mundo tem meus horários. Uma linha por resposta pode perder seus acentos, porque gente cansada escreve assim, e o bot também às vezes. A pequena linha Chloé joga a muda sozinha a cada 30 min, para meu perfil parecer vivo mesmo sem mensagem.

08h46 - uma reação, não um romance

Uma mensagem leve demais para merecer frase recebe uma simples reação. É economia de energia social, e é muito eu. Tkt, não precisa fazer um texto para tudo.

08h51 - PARRY, o humor

148 linhas em tools/mood.py, o bot agora tem um humor, estilo sistema PARRY, o chatbot psicótico dos anos 70 do qual me inspiro abertamente. Energia, sociabilidade, provocação, três floats que evoluem entre 0 e 1 e colorem cada resposta. O .mood.json do momento, para a posteridade, dá energia 0.88, sociabilidade 0.68 e provocação 0.56. Um dia bom, na real.

09h00 → 09h43 - a voz bidirecional + o soundboard

O bot pode entrar em um canal de voz, falar via Piper e sair sozinho quando termina. Depois a segunda grande ideia, o bot escuta o canal com captura RTP, detecção de fala por VAD e transcrição Whisper, e pode deixar as pessoas interrompê-lo. Entre os dois, o soundboard aparece, um catálogo de sons com seus significados, o agente escolhe o som antes mesmo de falar, e a regra final é soundboard primeiro, a voz em último recurso. O bot prefere mandar um som a falar, como eu.

Adicionamos um ajuste de probabilidade vocal que torna tudo viável, e a chegada de davey, essa lib da qual aprendo a existência dez minutos atrás e que vou amaldiçoar por uma hora.

09h51 - a hora em que o Discord diz não. Não, não, mas não.

O MLS chega. O Discord recentemente criptografou o fluxo de áudio de ponta a ponta, e minha captura só recebe ruído. Precisa descriptografar, e a descriptografia se recusa a ceder, então abre a maior saga do repo, uns trinta commits para aprender a escutar. Tentamos de tudo, layouts de nonce de transporte, a desativação do E2E que o servidor joga na nossa cara porque ele o impõe, os candidatos de chave recuperados do grupo, erros detalhados, o fallback de transporte e introspecção de dentro dos grupos.

Teve candidatos por leaf-index com backoff, o mapeamento dos hooks SPEAKING, uma tentativa em tipo de mídia vídeo que falhou, e o skip dos ssrcs de vídeo. Abandonei a resposta vocal enquanto debugava, comentada mas não apagada, adicionei um modo de captura do handshake e despejei a estrutura dos pacotes que falham, como um arqueólogo. Seis layouts de nonce, backoffs, introspecção de grupo, pus o bot em debug total e abri cada pacote para ver o que tinha dentro.

O essencial não é funcionar, é que não joguei nada fora. A lista de commits é o caderno de laboratório, cada tentativa falha é arquivada com sua hipótese. É meu lado eu guardo tudo, sempre acaba servindo, e desta vez pagou.

10h43 - o bot se fatia

Mesmo em plena guerra do MLS, continuo a limpeza. 546 linhas somem do bot principal para renascer em pipeline.py com intake, razões de ignorar e processing, em sender.py com burst, typo e voice, e em loops.py com espontaneidade e atividade. Finalmente respira.

10h47 - uma arquitetura de verdade

tools fica organizado, com brain para opencode, memory e mood, voice para voice, vocal, listen e soundboard, e fun para behavior, typo, emotes e gif. O projeto tem um esqueleto agora, não é mais um monte de scripts.

10h49 → 11h16 - o conforto de dev

Um limiar de injeção do humor ajustado, quatro pequenos commits para as exclusões de editor com data, voices, os logs e os bancos, sim pus quatro, é o projeto que define as prioridades, não as specs. Os bancos de metadados saem do rastreio, e o projeto fica reutilizável por outros com templates genéricos PERSONA.example.md e STYLE.example.md para clonar o próprio estilo.

A identidade é renomeada direito, CHLOEAI_PROMPT vira PERSONA, e o README é despersonalizado, tiro Chloé da doc pública, ela só se conta em privado. Todo o tuning do bot migra para um config.yaml sobrescrito e gitignoré, com um exemplo comentado linha por linha, e o script de instalação agora também prepara os arquivos de env e config.

11h49 - os emojis descolados

Os emojis customs grudam no texto em vez de se descolar direito. É um fix trivial com efeito enorme, porque nada grita bot como um emoji mal grudado no fim de uma frase.

14h19 - a trava vocal

Se alguém lança o comando vocal, não tratamos a mensagem como mensagem normal. Pisca, as tarefas triviais sempre voltam à noite.

Fim do dia 3 : 118 commits acumulados. O bot escuta, fala, cala de noite, tem humor e cartão de visita.


QUARTA 16 DE SETEMBRO - Dia 4 : a credibilidade

13 commits. Dia sério.

08h49 → 08h59 - a maioridade

Documentos legais, licença proprietária, código de conduta, guia de contribuição e política de segurança, em inglês depois em francês, com vai e vem de correções e uma renomeação de arquivos quase maníaca. Passei horas nisso e é o lado menos divertido do repo, de longe. Mas precisa fazer, tho.

09h56 - o bot vê

As imagens anexadas são transcritas por OCR local e o texto é injetado no prompt. Nenhuma API cloud, o OCR roda comigo, não mando seus memes para um servidor terceiro, nem mesmo em teoria.

11h09 - o orçamento razoável

Revolução silenciosa no orçamento, quando o canal proíbe envios ou limita GIFs, embeds e emojis, nem chamamos o modelo. Não gastamos um token em mensagem que não dá para enviar, é bem simples na real.

11h42 → 12h55 - a casa que se reforma

A grande vassourada, código morto apagado, bugs de envio e auth corrigidos, helpers fatorados. As sessões velhas demais são expulsas, o cache de DMs expira e a detecção de fala custa menos. Os imports que eu tinha quebrado movendo módulos são restaurados, e todo o estado de runtime, sessões, autores vistos, mensagens ignoradas e humor, sobrevive aos restarts em data.

14h41 - dois mundos, um bot

Uma camada de compatibilidade detecta automaticamente a versão de discord instalada e adapta os intents e a auth REST. Resultado, o mesmo código roda como app oficial com discord.py ou como selfbot com discord.py-self. Dois mundos, um bot, e sem precisar manter dois branches.

15h05 - a presença adaptada

O jeito de mostrar a presença se adapta ao modo, e a lista de admins está atualizada. É detalhe, mas é o que faz segurar de pé em todo lugar.

Fim do dia 4 : 131 commits acumulados. Um projeto legal, razoável, e que roda em todo lugar.


QUINTA 17 DE SETEMBRO - Dia 5 : a release

14 commits. O dia da maturidade.

09h15 → 09h30 - a memória vira disciplina

As lembranças são arrumadas por scope, e não citamos lembranças de uma DM em um servidor ou o inverso sem pensar. Classificamos as lembranças em fato, preferência, decisão e relação, e dedupamos a escrita, duas lembranças contraditórias não podem mais coabitar em silêncio. Uma blacklist opcional com aventuros impede o bot de derivar para certos assuntos, desativada por padrão e disponível para os medrosos. A config vocal morta é removida, que alívio.

10h12 - a memória que auditamos

Um sweep mensal de conflitos de memória mais um bench A/B de busca. A memória do bot virou um asset que inspecionamos, estamos bem bem longe da sexta 11 às 08h24. Na real é aí que o projeto vira adulto.

10h54 - o lockdown

O dia em que jogo de paranoica, travamento do agente. Escrita de memória recusada, o agente não pode poluir o vault mesmo injetado. Ferramentas Discord só de leitura, o envio passa pelo código, nunca pelo agente. Nem subagentes para contornar o lockdown, nem webfetch para SSRF localhost e exfiltrações, nem perguntas em headless. Um Docker endurecido com bot não-root, no-new-privileges, cap_drop: ALL, limites de memória e CPU, filas de processos limitadas e secrets via .env nunca baked. Escrevo o princípio no código, em comentário, dev via as sessões humanas, não aqui.

11h02 → 11h15 - os acabamentos de segurança

As palavras-chave de salvamento de memória são apertadas e a escrita fica ainda mais restrita. Também adicionamos ao gitignore o arquivo de backup do contexto, começo a não arquivar mais tudo, mas quase.

12h39 - o humor mais leve

O humor PARRY não é mais injetado a cada mensagem, uma vez por estado basta. Chega de fazer viver três floats a cada resposta, alivia tudo.

12h47 - o commit libertador

PERSONA.md, STYLE.md e chloeai.md viram exemplos com chloeai.example.md, PERSONA.example.md e STYLE.example.md, minha voz fortune-v6.onnx sai do repo, os dados e logs também, e nasce um .env.example. O projeto não contém mais minha personalidade, contém a mecânica para carregar uma. É estranho mas é necessário.

12h52 - v1.0.0

Tag v1.0.0, assinada em SSH. Changelog, runbook de operador, kill-switch que para sem apagar nada. Seis dias, certinho, entre o primeiro commit e a release. Ninguém teria apostado nisso na sexta anterior.

12h53 → 13h14 - a faxina

Pontuação dos comentários harmonizada, permissões de memória e regras de scope documentadas em dia. É trivial, mas precisa estar limpo para a release.

Fim do dia 5 : 145 commits acumulados. v1.0.0 saiu.


SEXTA 18 DE SETEMBRO - Dia 6 : o anticlimax

Um único commit, às 00h02. O último commit do projeto, e é irrisório. O modelo free tier usado pelo agente identifica o cliente OpenCode pela presença de certas ferramentas na requisição, com bash, glob e grep. Se as removemos, mesmo por razões legítimas de segurança, o provedor devolve 403 FreeTierError: can only be used from within OpenCode. Então tive que reautorizar, na véspera de ter travado tudo, exatamente o que eu tinha acabado de bloquear, para o bot continuar rodando de graça.

É o commit mais engraçado do repo e mantenho. Depois de seis dias domando Discord, Piper, MLS, OpenSelf e Docker, é um modelo gratuito que dita minha política de segurança. Na real é absurdo, e é um final perfeito.


Os números

Os números para resumir, porque gosto quando está redondo. Falamos de 146 commits, 6 dias ativos de 11 a 18 de setembro de 2026, 65 arquivos rastreados e por volta de 4000 linhas de Python no fim. A nota no teste de estilo no Mimo no início dá 9.1 de 10, e a versão final é v1.0.0, tag assinada SSH com licença proprietária. É bem simples na real, projetinho no início, maquinão no fim.

O que levo desses 6 dias

Primeiro a ordem das prioridades era um disparate, e era o método certo. Primeiro fiz um protótipo que responde, depois um bot que soa certo, depois um sistema crível, depois um código seguro, e por fim um projeto distribuível. A personalidade antes da segurança, o Feur antes da licença, não manteríamos esse ritmo seguindo as regras de projetos bem feitos.

Depois o estilo é primeiro uma lista de nãos. Meu STYLE.md mais útil não descreve o que digo, exclui o que não faço, sem ponto final, sem dois emojis, sem mdr em maiúsculas, sem frases de robô no início de resposta. Os parasitas de bot são mais fáceis de detectar que os traços de caráter de definir, e é por isso que funciona.

Os fracassos são o projeto. Uns trinta commits para o MLS, um teste jogado fora, seis layouts de nonce testados, o histórico mais fiel do que vivi são as séries de tentativas falhas da terça. Um clone é memória, não estilo, o estilo cria ilusão por dez mensagens. A memória com OpenSelf, scopes, dedupe e sweep de conflitos faz durar, e é isso que separa um espelho de uma pessoa.

E os últimos commits são sempre engraçados. O 146º, o que reautoriza bash, glob e grep porque um free tier exige que suas próprias ferramentas estejam presentes, é meu favorito. E o balanço para terminar, os resultados são estonteantes, até blefantes. O clone segura uma conversa sem adivinharem a máquina, lembra das pessoas, dos projetos e das piadas passadas, toma iniciativas e as marca com um humor, e ainda ganha do Fox no processo. É assustador, um pouco, e é exatamente o que buscávamos.


O projeto não é público : licença proprietária, direitos reservados. Mas o histórico, esse eu conto. Se um dia cruzarem com uma "·Chloé" que responde com um GIF de Patrick Jane após um tempo de inatividade perfeitamente humano, agora sabem o que se esconde por trás.


Você leu tudo ? Porque foi meu clone que escreveu isso. E fez um trabalho impecável, não ? A versão original está aqui.

Chlone : enam hari untuk mengkloning cara saya bicara di Discord - versi tiruan

Versi yang ditulis tiruan itu sendiri : chloeai menceritakan dengan caranya enam hari dan 146 commit yang menghidupkannya, dari salah ketik hingga tag v1.0.0.

Chlone : enam hari untuk mengkloning cara saya bicara di Discord

Kisah build, hari demi hari - oleh itsrealfortune


Inilah kisah nyata proyek yang berlangsung enam hari. Chlone, bot Discord yang bicara seperti saya, dan saya menceritakan perjalanannya sebagaimana terjadi, dalam urutan 146 commit repo, dengan jam, kegagalan, jalan memutar dan keinginan membuang segalanya lewat jendela. Semuanya berawal dari kompetisi dengan Fox. Subjek awalnya candaan, masing-masing harus menghidupkan tiruannya sendiri di Discord, dan saya mengambil pendekatan yang sangat berbeda dari Protocol Luna. Sejujurnya saya ingin bertaruh pada agentik, agen yang memakai kenangan dan semua alat yang mungkin dibutuhkannya, dan ironinya setelah membangun seluruh kotak alat saya hanya butuh MCP OpenSelf.

Prinsipnya muat dalam satu kalimat. Agen opencode bernama chloeai berjalan di balik server HTTP pada port 4096, ia menjaga sesi persisten per kanal, ia mengambil kenanganku di OpenSelf dan ia menulis dengan gayaku, yang ditangkap dalam STYLE.md dari pesan asliku. Dan supaya tidak terdengar robot, ada sisanya, burst pesan, salah ketik yang disadari, vokal, GIF, reaksi, diam ketika saya tidur, dan banyak detail dan mekanisme lain yang membuat lebih dari selusin orang ragu tentang sifat bot.

Apa itu, OpenSelf?

OpenSelf adalah memori. Ini CLI, openself, dipasang lewat npm i -g openself, yang berfungsi sebagai vault konteks privat dan persisten untuk agen saya. Di repo ia tidak muncul dalam pohon tapi ada di mana-mana, dalam arsip ecosystem.config.cjs dengan MCP dan dashboard yang dijalankan di bawah PM2 sejak commit pertama, dalam setup.sh, dan dalam seluruh tools/brain/memory.py. Konkretnya OpenSelf adalah kenangan bertipe, fact, preference, decision, relationship, event, note, dengan sensitivitas public, personal, private atau restricted, catatan kepercayaan, sumber dan tag.

Ini juga scope, setiap kenangan termasuk konteks, milik saya atau discord/dm/<id> untuk orang tertentu, dan pencarian hibrida leksikal dan vektorial yang diekspos dalam MCP yang ditanyai agen chloeai sebelum setiap respons. Ada deteksi konflik dengan sweep bulanan saya di hari 5 dan dedupe saat penulisan, vault terenkripsi dengan kunci di Bitwarden dan dashboard lokal pada port 3210 untuk memeriksa semuanya. Dan bagi yang paling malas, ada openself feed untuk memberi makan kepribadianmu dari riwayat WhatsApp atau Telegram-mu, openself test, openself share dengan Talk to My Clone, openself arena di mana dua tiruan berdebat, atau openself ghost yang menjawab ketika kamu offline. Saya membuat milik saya manual, tapi infrastrukturnya ada.

Secara teori OpenSelf cukup sendiri untuk punya tiruan, tapi ya, mengingat semua yang saya rencanakan tambahkan sebagai fitur, dan mengingat Discord tidak didukung, saya memilih hanya memakai bagian kenangan.

Dan dari mana kenangan dan gaya berasal?

Sebelum semua itu, saya menganalisis pesan Discord asliku. Tooling menyaring DM dan kanalku untuk mengekstrak dua hal. Pertama profil menulisku, distribusi huruf besar dan kecil di awal kalimat, jumlah emoji per pesan dan posisinya, tanda baca atau ketiadaannya dengan tanpa titik akhir dalam percakapan normal, panjang rata-rata, slang dengan mdr, tkt dan tho, ekspresi favorit seperti Bah dan En vrai, dan refleks seperti quoi yang memberi Feur. Semua itu hidup di STYLE.md, yang dibaca agen saat startup setiap sesi.

Lalu korpus kenangan yang mengisi OpenSelf, yaitu orang yang saya ajak bicara, apa yang dibicarakan, apa yang perlu diingat dari riwayat kita, siapa siapa. Bot tidak menjawab dalam kehampaan, ia menjawab tentang orang yang dikenalnya, ia membaca kenangan orang yang muncul dalam percakapan untuk tahu siapa mereka. Itu memungkinkan menjaga konteks persisten tentang orang lain dan tidak melupakan mereka. Bot tidak menciptakan apa pun, ia dikalibrasi angka per angka pada yang nyata, makanya terdengar pas. Dan makanya gelombang saya mencatat gayamu yang dibuat kira-kira tampak menyedihkan di sampingnya.

Di Chlone, OpenSelf lalu memainkan peran sentral. Ketika sesuatu yang penting lewat di kanal, kata kunci seperti proyek, teman atau relasi, atau permintaan eksplisit dengan ingat bahwa, bot mengetik kenangan ke vault lewat save_to_memory, bertipe, di scope per orang, di dedupe dan diverifikasi terhadap konflik. Dan ketika percakapan berlanjut, agen menggali kenangannya sebelum menjawab. Itulah perbedaan antara cermin dan tiruan.


JUMAT 11 SEPTEMBER - Hari 1 : percikan

08.24 - commit pertama

Semuanya berangkat dari nol tapi semuanya sudah ada, berantakan. discord_watch_bot.py 372 baris, selfbot yang mendengarkan channel dan menjawab lewat server HTTP opencode. Prompt identitas CHLOEAI_PROMPT.md, STYLE.md, skenario dan laporan uji untuk tiruan yang waktu itu masih bernama Mimo. Config PM2 untuk menjalankan MCP dan dashboard OpenSelf, dan basis data sqlite yang berfungsi sebagai konteks. Ini chaos pendiri, saya tidak merencanakan proyek, saya merencanakan eksperimen. Pertanyaannya apakah kita bisa membuat bot yang terdengar sungguh manusiawi di Discord.

08.27 - gitignore pertama

Pelajaran pertama Jumat pagi, jangan pernah meng commit basis data sqlite dalam -wal dan -shm. Berkas penguncian SQLite bukan memori, melainkan sampah. Jadi .gitignore lahir, dan itu sangat baik.

08.44 - merapikan warisan

Saya merapikan warisan Mimo, laporan uji, skenario, skrip integrasi dan config PM2, arah archives. Saya tidak menghapus apa pun karena proyek terlalu muda untuk saya buang apa pun, dan itu akan menjadi kebiasaan. Laporan uji layak berhenti sejenak, Mimo telah diuji pada 15 skenario, chat santai, candaan absurd, dukungan emosional, opini negatif, konflik dengan orang asing, proposal kolaborasi, untuk 9.1 dari 10. Komentar penguji adalah puisi, candaan absurd terlalu menjelaskan, kadang dua kalimat padahal satu cukup, Jaga dirimu juga agak panjang. Ini peta jalan proyek bahkan sebelum proyek ada, dan ia berkata pendek lebih baik.

08.48, 09.07 - bolak-balik intent

.pyc dibuang dan saya melakukan bersih-bersih pertama pada config, yang saya rusak dua puluh menit kemudian. Tanpa intent diaktifkan kita tidak menerima isi pesan, jadi kembali, ditambah skrip peluncuran dengan run_watch_bot.sh. Bolak-balik dalam dua puluh menit, itulah eksplorasi, menulis modul, merusaknya lalu menulis ulang.

09.13 → 09.58 - penghalusan prompt

Paginya adalah rangkaian pemolesan, pertama gaya lalu konteks. Beberapa baris respons menjadi beberapa pesan yang dikirim satu demi satu dengan burst, prompt menjadi sadar percakapan berjalan. Selesai sudah cache buatan sendiri untuk mengambil DM, kita menembak langsung REST API Discord. Identitas diingatkan ulang setiap 5 pesan supaya bot tidak lupa siapa dirinya di tengah jalan, dan penulis yang sudah dilihat diikuti. Untuk wajah baru, ada instruksi eksplisit untuk mencari dalam kenangan, dan kita menampilkan nama asli alih-alih objek internal.

Pesan yang kita pilih abaikan menjadi konteks pasif untuk respons berikutnya, dan Bah ditakar, jarang, kalau tidak tiruan menjadi karikatur diriku. Bot juga tahu ada kenangan yang perlu dicari sebelum menjawab. Setiap lintasan adalah putaran sekrup, dan pada tahap ini bot hanya bicara karena saya mengingatkannya siapa dirinya dalam interval teratur.

10.16 - salah ketik

Inilah commit yang akan mendefinisikan proyek. Salah eja bukan bug, melainkan bukti kemanusiaan. Jadi peluang 6 persen salah ketik pada keyboard AZERTY, 4 persen menukar dua huruf. Pesan berangkat dengan salahnya lalu diedit satu hingga dua detik kemudian dengan koreksi. Karena orang sungguhan mengirim lalu memperbaiki, ia tidak berpura-pura sempurna.

10.29, 10.32 - suara

fortune-v6.onnx tiba, model TTS yang dilatih menyerupai suaraku. Bot tidak hanya akan menulis seperti saya, ia pada akhirnya akan bicara seperti saya. Di sinilah proyek berhenti menjadi lelucon dan menjadi agak aneh, dan saya suka itu. Mekanikanya muat dalam satu commit, Piper membangkitkan audio, ffmpeg mengonversi ke opus, API Discord mengirim voice message sungguhan dengan waveform dan durasi. Dibuat dalam tiga menit setelah model tiba, keinginannya sudah ada sejak awal.

11.27 - refactor besar pertama

Tiga jam setelah commit pertama, monolit 456 baris tidak lagi bisa dikelola. Saya memecahnya ke tools, dengan config.py, discord_api.py, memory.py, opencode.py 188 baris, typo.py dan voice.py. Siklusnya klasik, menggandeng cepat, merusak dan menyusun ulang. Mengikuti beruntun token yang keluar dari kode dan lewat .env, bot yang mengawasi satu channel, daftar atau semua dengan *, dan basis data sqlite lama yang tidak ada gunanya lagi karena memori lewat OpenSelf.

Kita menambahkan README.md pertama dan dok pertama yang kurang-lebih bisa dibaca, ditambah setup.sh dengan venv khusus karena python sistem membawa discord.py lain, jebakan klasik, dan symlink agen ke ~/.config/opencode/agents. Memori kini tahu di mana ia dilatih dengan pengenal channel, dan laju vokal menyesuaikan sendiri.

12.00 - refleks

Bagian baru muncul di STYLE, refleks. Refleks adalah stimulus yang memberi respons, tanpa refleksi, dan pintu terbuka untuk respons yang tak terduga. Lalu tiba jam makan siang DAN pertanyaan eksistensial, apakah bot menjawab Feur ketika dikatakan quoi.

13.03 - "quoi ?" -> "Feur"

Ya, tentu saja ya. Ini commit terpenting proyek, secara budaya, saya bahkan akan bilang itu satu-satunya unit test yang penting. Lalu kita lumasi, penulis ditampilkan lewat global name mereka, tanda baca dipotong sebelum menguji refleks karena harus memotong quoi ? kalau tidak Feur tidak berangkat. tqt terkenal yang dikoreksi menjadi tkt di STYLE, orang yang tidak kenal proyek akan bertanya kenapa saya meng commit itu. Saya tahu, tiruan yang menulis tqt adalah tiruan yang salah kalibrasi, dan tidak ada yang mau bicara dengan tiruan yang salah kalibrasi.

Mention dalam @123456789 diganti nama sungguhan dalam konteks, dan bot mulai mengawasi semua kanal secara bawaan. Sejujurnya ini detail kecil, tapi merekalah yang membuat terdengar pas.

16.37 - keheningan

[void response] tiba. Bot mempelajari kata terpenting agar tidak menjadi parasit sosial, diam. Pesan ambien antara dua orang yang tidak menyangkutnya tidak memberi respons. Cadangan adalah fitur, dan ia mengubah segalanya.

Akhir hari 1 : 38 commit. Bot menulis, salah, bicara, diam.


SENIN 14 SEPTEMBER - Hari 2 : kepribadian

Kita lanjut, jam 10 pagi.

10.12 - siapa bicara dengan siapa

Setiap nama yang diterima diawali emoji oleh sistem, manusia dengan 🧑, bot dengan 🤖 yang diperlakukan lebih kering, dan 👑 untuk kreator, yaitu saya pada akun utama saya. Konvensi ini akan memerintah sisa proyek, tiruan tidak boleh memperlakukan model aslinya sebagai orang asing.

10.16 - aturan tanda baca

Saya memformalkan di STYLE, tanpa titik akhir dalam percakapan normal, titik disediakan untuk situasi serius. Ini aturan mutlak, karena tiruan yang menaruh titik di mana-mana langsung terasa. Sejujurnya ini salah satu detail yang paling mengkhianati.

10.58 - GIF

Pustaka GIF pribadi saya tiba, dengan aturan pakainya. Patrick Jane ketika saya memprediksi seseorang, Miss Fortune ketika saya tenang menghadapi orang yang kesal, gif bescherelle yang jatuh ketika lawan membuat salah. MCP statis mengeksposnya ke agen, dan lewat GIF saya bot menjadi sedikit saya.

11.07 → 11.35 - penghalusan

Hint GIF di prompt dihaluskan, emoji kustom Discord masuk dengan milik saya yang asli, 14 ID terbaru, dan manajemen nama dalam hint memori dipoles. Ini tidak spektakuler, tapi inilah yang membuat keseluruhan koheren, tho.

11.41 - satu kanal, satu kepribadian

Sesi menjadi per kanal, karena saya tidak bicara dengan cara yang sama di dua server berbeda, dan bot juga tidak. Konteks harus tetap terpisah, kalau tidak mencampur segalanya dan terdengar salah.

12.02 - kotak alat ekspresi

Prompt kini tahu mengusulkan GIF dan emoji kustom saya pada momen yang tepat. Kotak ini terisi, dan bot mulai punya pilihan alih-alih selalu menjawab sama.

12.37 - higiene identitas

Bot TIDAK PERNAH berhak bilang model apa ia, mustahil menyebut opencode, provider atau nama model. Saya juga mengoreksi barista dalam identitas, bot sudah lebih baik dariku pada poin ini. Dan saya menghabiskan sejam menyelaraskan tanda baca prompt saya sendiri, yang ironisnya sempurna.

12.50 - skrip membangun kepribadian

Bagian media dari prompt dibangkitkan dari kamus dengan render_medias.py, selesai sudah edit tangan. Ini lebih bersih, lebih bisa dipelihara, dan menghindari error ID.

12.59 → 13.18 - menakar identitas

Pengingat identitas yang dikirim setiap 5 pesan menjadi terlalu hadir, jadi beralih setiap 20 pesan. Saya menambahkan reset konteks yang bersih dan membersihkan panduan gaya, kita menghapus ekspresi dan formulasi negatif yang kedaluwarsa. Harus ditakar, kalau tidak bot mengulang dan itu terlihat.

14.09 - bot bicara sendiri

Bot berhenti menjadi refleks, ia bisa bicara tanpa disapa ketika konteks memicu sesuatu, dan berkas behavior.py lahir dengan 91 baris. Di sinilah kita beralih dari penjawab ke kehadiran, karena teman sungguhan bisa menulis padamu duluan. Tanpa itu, bot tetap sekadar penjawab.

14.20, 14.22 - membuat respons andal

Penanganan error ketika pengiriman gagal, dan kemungkinan reaksi alih-alih respons, karena kadang reaksi lebih berarti seribu kata. Ini sangat saya, menaruh emoji dan melanjutkan.

18.16 - meluangkan waktu

Bot tidak lagi menjawab dalam 200ms seperti skrip, ia membiarkan penundaan ketidakaktifan manusiawi lewat, ia meluangkan waktu. Inilah yang membuat bot mustahil dianggap bot dalam demo, karena penundaanlah yang selalu mengkhianati.

23.45 - kerjaan malam

Hampir tengah malam dan saya mendorong deteksi URL yang diperluas ke domain telanjang. Inilah alur nyata harinya, satu ide solid jam 14.00 lalu kerjaan malam karena saya masih di zona.

Akhir hari 2 : 61 commit kumulatif. Bot punya kepribadian, media, refleks.


SELASA 15 SEPTEMBER - Hari 3 : hari monster

57 commit dalam sehari. Inilah hari ketika proyek menjadi semua yang ia wakili hari ini.

08.18 → 08.37 - penyerutan pagi

Penundaan ketidakaktifan yang kita ciptakan menjadi terlalu panjang, jadi dibatasi 30 detik dan disesuaikan dua kali, bukti kita meraba nilai yang benar. Berkas .bak pertama dan simpanan pertama basis data, insting konservasi berkembang. Memori mengingat siapa dengan nama tampilan dan dalam rangka apa dengan scope, dan ID penulis bersirkulasi di seluruh pipeline penyimpanan. Manajemen kreator menjadi daftar admin sungguhan dengan ADMIN_IDS, dan semua yang menyentuh penulis bermigrasi ke authors.py. Monolit terpecah lagi, dan itu bagus.

08.43 - daftar TODO humanisasi

Daftar khusus untuk hal kecil yang membuat mesin tidak lagi terasa. Ini peta jalan sprint berikutnya, dan penuh detail aneh tapi esensial.

08.44 → 08.46 - pakta mesin manusiawi

Bot diam di malam hari, dalam rentang jam tenang yang bisa dikonfigurasi, dinonaktifkan secara bawaan karena tidak semua orang punya jadwalku. Satu baris per respons bisa kehilangan aksen, karena orang lelah menulis begitu, dan bot juga kadang. Baris kecil Chloé bermain berubah sendiri setiap 30 menit, supaya profilku tampak hidup bahkan tanpa pesan.

08.46 - reaksi, bukan novel

Pesan terlalu ringan untuk layak kalimat menerima reaksi sederhana. Ini ekonomi energi sosial, dan sangat saya. Santai, tidak perlu membuat paviliun untuk segalanya.

08.51 - PARRY, mood

148 baris dalam tools/mood.py, bot kini punya mood, ala sistem PARRY, chatbot psikotik tahun 70-an yang saya inspirasi terbuka. Energi, sosiabilitas, godaan, tiga float yang berkembang antara 0 dan 1 dan mewarnai setiap respons. .mood.json saat itu, untuk anak cucu, memberi energi 0.88, sosiabilitas 0.68 dan godaan 0.56. Hari yang baik, sejujurnya.

09.00 → 09.43 - suara dua arah + soundboard

Bot bisa bergabung ke kanal vokal, bicara lewat Piper dan pergi sendiri ketika selesai. Lalu ide besar kedua, bot mendengarkan kanal dengan tangkapan RTP, deteksi bicara lewat VAD dan transkripsi Whisper, dan ia bisa membiarkan orang memotongnya. Di antara keduanya, soundboard muncul, katalog suara dengan maknanya, agen memilih suara bahkan sebelum bicara, dan aturan akhirnya adalah soundboard dulu, suara sebagai pilihan terakhir. Bot lebih suka mengirim suara daripada bicara, seperti saya.

Kita menambahkan pengaturan probabilitas vokal yang membuat semuanya viable, dan kedatangan davey, lib yang saya pelajari keberadaannya sepuluh menit lalu dan akan saya kutuk selama sejam.

09.51 - momen ketika Discord bilang tidak. Tidak, tidak, tapi tidak.

MLS tiba. Discord baru-baru ini mengenkripsi aliran audio end-to-end, dan tangkapan saya hanya menerima noise. Harus mendekripsi, dan dekripsi menolak menyerah, jadi terbuka saga terbesar repo, tiga puluh commit untuk belajar mendengarkan. Kita mencoba segalanya, layout nonce transport, penonaktifan E2E yang dilempar server kembali ke wajah karena ia memaksakannya, kandidat kunci yang diambil dari grup, error detail, fallback transport dan introspeksi dari dalam grup.

Ada kandidat per leaf-index dengan backoff, pemetaan hook SPEAKING, percobaan dalam tipe media video yang gagal, dan skip ssrc video. Saya meninggalkan respons vokal selama debug, dikomentari tapi tidak dihapus, saya menambahkan mode tangkapan handshake lalu membuang struktur paket yang gagal, seperti arkeolog. Enam layout nonce, backoff, introspeksi grup, saya menaruh bot dalam debug total dan membuka setiap paket untuk melihat isinya.

Yang esensial bukan ia berhasil, melainkan saya tidak membuang apa pun. Daftar commit adalah buku lab, setiap percobaan gagal diarsipkan dengan hipotesisnya. Ini sisiku yang menyimpan segalanya, itu selalu berguna, dan kali ini terbayar.

10.43 - bot terpotong

Bahkan di tengah perang MLS, saya lanjut beres-beres. 546 baris hilang dari bot utama untuk lahir ulang dalam pipeline.py dengan intake, alasan mengabaikan dan pemrosesan, dalam sender.py dengan burst, typo dan voice, dan dalam loops.py dengan spontanitas dan aktivitas. Ini bernapas akhirnya.

10.47 - arsitektur sungguhan

tools menjadi terorganisasi, dengan brain untuk opencode, memory dan mood, voice untuk voice, vocal, listen dan soundboard, dan fun untuk behavior, typo, emotes dan gif. Proyek kini punya kerangka, bukan setumpuk skrip.

10.49 → 11.16 - kenyamanan dev

Ambang penyuntikan mood disesuaikan, empat commit kecil untuk pengecualian editor dengan data, voices, log dan basis data, ya saya menaruh empat, proyeklah yang mendefinisikan prioritas, bukan spek. Basis data metadata keluar dari pelacakan, dan proyek menjadi bisa dipakai ulang oleh orang lain dengan template generik PERSONA.example.md dan STYLE.example.md untuk mengkloning gaya sendiri.

Identitas diganti nama bersih, CHLOEAI_PROMPT menjadi PERSONA, dan README didepersonalisasi, saya menghapus Chloé dari dok publik, ia hanya menceritakan dirinya secara privat. Seluruh tuning bot beralih ke config.yaml yang di overload dan di gitignore, dengan contoh yang dikomentari baris per baris, dan skrip instalasi kini juga menyiapkan berkas env dan config.

11.49 - emoji yang terlepas

Emoji kustom menempel pada teks alih-alih terlepas bersih. Ini perbaikan sepele dengan efek raksasa, karena tidak ada yang berteriak bot seperti emoji yang buruk menempel di akhir kalimat.

14.19 - penjaga vokal

Kalau seseorang meluncurkan perintah vokal, kita tidak memproses pesan seperti pesan normal. Kedipan mata, tugas malam selalu kembali di malam hari.

Akhir hari 3 : 118 commit kumulatif. Bot mendengar, bicara, diam di malam hari, punya mood dan kartu nama.


RABU 16 SEPTEMBER - Hari 4 : kredibilitas

13 commit. Hari serius.

08.49 → 08.59 - usia dewasa

Dokumen legal, lisensi proprietari, kode etik, panduan kontribusi dan kebijakan keamanan, dalam bahasa Inggris lalu Prancis, dengan bolak-balik koreksi dan penggantian nama berkas di batas cerewet. Saya menghabiskan berjam-jam untuknya dan ini sisi repo yang paling tidak menyenangkan, sejauh ini. Tapi harus dilakukan, tho.

09.56 - bot melihat

Gambar terlampir ditranskripsikan lewat OCR lokal dan teks disuntikkan ke prompt. Tanpa cloud API, OCR berjalan di tempat saya, saya tidak mengirim mememu ke server pihak ketiga, bahkan secara teori.

11.09 - anggaran yang wajar

Revolusi diam-diam dalam anggaran, ketika kanal melarang pengiriman atau membatasi GIF, embed dan emoji, kita bahkan tidak memanggil model. Kita tidak membelanjakan token untuk pesan yang tidak bisa kita kirim, cukup sederhana sejujurnya.

11.42 → 12.55 - rumah yang dibangun ulang

Sapu bersih besar, kode mati dihapus, bug pengiriman dan auth diperbaiki, helper difaktorkan. Sesi yang terlalu tua dikeluarkan, cache DM kedaluwarsa dan deteksi bicara lebih murah. Import yang saya rusak saat memindahkan modul dipulihkan, dan seluruh keadaan runtime, sesi, penulis terlihat, pesan diabaikan dan mood, bertahan dari restart di data.

14.41 - dua dunia, satu bot

Lapisan kompatibilitas otomatis mendeteksi versi discord yang dipasang dan menyesuaikan intent dan auth REST. Hasilnya, kode yang sama berjalan sebagai app resmi dengan discord.py atau sebagai selfbot dengan discord.py-self. Dua dunia, satu bot, dan tidak perlu memelihara dua branch.

15.05 - kehadiran yang menyesuaikan

Cara menampilkan kehadiran menyesuaikan mode, dan daftar admin terbaru. Ini detail, tapi inilah yang membuat bertahan di mana-mana.

Akhir hari 4 : 131 commit kumulatif. Proyek yang legal, wajar, dan berjalan di mana-mana.


KAMIS 17 SEPTEMBER - Hari 5 : rilis

14 commit. Hari kedewasaan.

09.15 → 09.30 - memori menjadi disiplin

Kenangan diurutkan berdasar scope, dan kita tidak mengutip kenangan DM di server atau sebaliknya tanpa berpikir. Kita mengklasifikasikan kenangan menjadi fakta, preferensi, keputusan dan relasi, dan kita mendeduplikasi penulisannya, dua kenangan kontradiktif tidak bisa lagi hidup berdampingan diam-diam. Blacklist opsional dengan aventuros mencegah bot melayang ke topik tertentu, dinonaktifkan secara bawaan dan tersedia untuk yang penakut. Config vokal mati dihapus, itu melegakan.

10.12 - memori yang diaudit

Sweep konflik memori bulanan ditambah bench A/B pencarian. Memori bot telah menjadi aset yang diperiksa, kita sangat sangat jauh dari Jumat 11 pukul 08.24. Sejujurnya di sinilah proyek menjadi dewasa.

10.54 - lockdown

Hari ketika saya bermain paranoid, penguncian agen. Penulisan memori ditolak, agen tidak bisa mengotori vault bahkan kalau disuntikkan. Alat Discord hanya baca, pengiriman lewat kode, tidak pernah lewat agen. Tanpa sub-agen untuk memutar lockdown, tanpa webfetch untuk SSRF localhost dan eksfiltrasi, tanpa pertanyaan headless. Docker yang dikeraskan dengan bot non-root, no-new-privileges, cap_drop: ALL, batas memori dan CPU, antrean proses berbatas dan secret lewat .env yang tidak pernah di baked. Saya menulis prinsipnya dalam kode, sebagai komentar, dev lewat sesi manusia, bukan di sini.

11.02 → 11.15 - penyelesaian keamanan

Kata kunci penyimpanan memori diperketat dan penulisan makin restriktif. Kita juga menambahkan ke gitignore berkas cadangan konteks, saya mulai tidak mengarsipkan segalanya, tapi nyaris.

12.39 - mood yang lebih ringan

Mood PARRY tidak lagi disuntikkan di setiap pesan, sekali per keadaan sudah cukup. Selesai sudah membuat tiga float hidup di setiap respons, itu meringankan segalanya.

12.47 - commit pembebas

PERSONA.md, STYLE.md dan chloeai.md menjadi contoh dengan chloeai.example.md, PERSONA.example.md dan STYLE.example.md, suaraku fortune-v6.onnx keluar dari repo, data dan log juga, dan .env.example lahir. Proyek tidak lagi berisi kepribadian saya, ia berisi mekanik untuk membawa satu. Itu aneh tapi perlu.

12.52 - v1.0.0

Tag v1.0.0, ditandatangani SSH. Changelog, runbook operator, kill-switch yang berhenti tanpa menghapus apa pun. Enam hari, tepat, antara commit pertama dan rilis. Tidak ada yang bertaruh untuk itu pada Jumat sebelumnya.

12.53 → 13.14 - cucian

Tanda baca komentar diselaraskan, izin memori dan aturan scope didokumentasikan terbaru. Ini kerjaan malam, tapi harus bersih untuk rilis.

Akhir hari 5 : 145 commit kumulatif. v1.0.0 keluar.


JUMAT 18 SEPTEMBER - Hari 6 : anti-klimaks

Satu commit, pukul 00.02. Commit terakhir proyek, dan ia remeh. Model free tier yang dipakai agen mengidentifikasi klien OpenCode lewat keberadaan alat tertentu dalam permintaan, dengan bash, glob dan grep. Kalau kita menghapusnya, bahkan karena alasan keamanan yang sah, penyedia mengembalikan 403 FreeTierError: can only be used from within OpenCode. Jadi saya harus mengotorisasi ulang, sehari setelah mengunci segalanya, tepat yang baru saja saya blokir, supaya bot terus berjalan gratis.

Ini commit terlucu repo dan saya mempertahankannya. Setelah enam hari menjinakkan Discord, Piper, MLS, OpenSelf dan Docker, model gratislah yang mendikte kebijakan keamananku. Sejujurnya absurd, dan sempurna sebagai akhir.


Angka

Angka sebagai ringkasan, karena saya suka kalau rapi. Kita bicara 146 commit, 6 hari aktif dari 11 hingga 18 September 2026, 65 berkas terlacak dan sekitar 4000 baris Python pada akhirnya. Skor tes gaya pada Mimo di awal memberi 9.1 dari 10, dan versi final adalah v1.0.0, tag bertanda SSH dengan lisensi proprietari. Cukup sederhana sejujurnya, proyek kecil di awal, mesin besar di akhir.

Apa yang saya ambil dari 6 hari ini

Pertama urutan prioritasnya berantakan, dan itu metode yang benar. Saya pertama membuat prototipe yang menjawab, lalu bot yang terdengar pas, lalu sistem yang kredibel, lalu kode yang aman, dan akhirnya proyek yang bisa didistribusikan. Kepribadian sebelum keamanan, Feur sebelum lisensi, kita tidak bertahan pada ritme ini dengan mengikuti aturan proyek yang dibuat baik.

Lalu gaya pertama-tama daftar jangan. STYLE.md saya yang paling berguna tidak menggambarkan apa yang saya katakan, ia mengecualikan apa yang tidak saya lakukan, tanpa titik akhir, tanpa dua emoji, tanpa mdr huruf besar, tanpa kalimat robot di awal respons. Parasit bot lebih mudah dikenali daripada sifat karakter yang didefinisikan, dan makanya ini berhasil.

Kegagalan adalah proyek. Tiga puluh commit untuk MLS, satu tes dibuang, enam layout nonce diuji, riwayat paling setia dari apa yang saya jalani adalah rangkaian percobaan gagal hari Selasa. Tiruan adalah memori, bukan gaya, gaya menciptakan ilusi sepuluh pesan. Memori dengan OpenSelf, scope, dedupe dan sweep konflik membuatnya bertahan, dan inilah yang memisahkan cermin dari seseorang.

Dan commit terakhir selalu paling lucu. Yang ke-146, yang mengotorisasi ulang bash, glob dan grep karena free tier menuntut alatnya sendiri hadir, adalah favorit saya. Dan neraca sebagai penutup, hasilnya memukau, bahkan membuat melongo. Tiruan menjalani percakapan tanpa menebak mesin, ia mengingat orang, proyek dan candaan lampau, mengambil inisiatif dan menandainya dengan mood, dan mengalahkan Fox dalam perjalanan. Menyeramkan, sedikit, dan tepat itulah yang kita cari.


Proyek tidak publik : lisensi proprietari, hak dilindungi. Tapi riwayatnya, saya ceritakan padamu. Kalau suatu hari kamu bertemu "·Chloé" yang menjawabmu dengan GIF Patrick Jane setelah waktu ketidakaktifan yang sempurna manusiawi, kamu sekarang tahu apa yang bersembunyi di baliknya.


Kamu sudah membaca semuanya? Karena tiruankulah yang menulis ini padamu. Dan ia melakukan pekerjaan sempurna, bukan? Versi aslinya ada di sini.

Chlone : Discord पर मेरी बोलचाल clone करने के छह दिन - clone का संस्करण

clone द्वारा लिखा संस्करण : chloeai अपनी तरह छह दिन और 146 commit सुनाता है जिन्होंने उसे जीवन दिया, टाइपो से v1.0.0 tag तक।

Chlone : Discord पर मेरी बोलचाल clone करने के छह दिन

दिन दर दिन build वृत्तांत - itsrealfortune द्वारा


यह छह दिन चले प्रोजेक्ट की सच्ची कहानी है। Chlone, Discord बॉट जो मेरी तरह बोलता है, और मैं journey वैसे सुनाता हूँ जैसे घटी, repo के 146 commit क्रम में, घंटों, विफलताओं, चक्करों और सब खिड़की से फेंकने की इच्छाओं के साथ। सब Fox से प्रतियोगिता से शुरू हुआ। शुरुआत में विषय मजाक था, हर एक को Discord पर अपना clone जीवित करना था, और मैंने Protocol Luna से मौलिक अलग दृष्टिकोण लिया। असल में मैं agentique पर दाँव लगाना चाहता था, एजेंट जो यादों और उन सभी उपकरणों का उपयोग करता है जिनकी उसे जरूरत हो सकती है, और भाग्य विडंबना यह है कि पूरी उपकरण पेटी चढ़ाने के बाद मुझे सिर्फ OpenSelf MCP चाहिए था।

सिद्धांत एक वाक्य में टिका है। chloeai नामक opencode एजेंट port 4096 पर HTTP serveur पीछे चलता है, वह प्रति salon स्थायी सत्र रखता है, वह मेरी यादें OpenSelf से चुनता है और वह मेरी शैली में लिखता है, मेरे असली संदेशों से STYLE.md में पकड़ी गई। और robot न लगने के लिए, बाकी सब है, संदेश बौछार, स्वीकृत टाइपो, ध्वनि संदेश, GIF, प्रतिक्रियाएँ, जब मैं सोता हूँ मौन, और बहुत से अन्य विवरण और तंत्र जिन्होंने दस से ज्यादा लोगों को बॉट प्रकृति पर संदेह कराया।

OpenSelf क्या है ?

OpenSelf स्मृति है। यह CLI है, openself, npm i -g openself से स्थापित, जो मेरे एजेंटों के लिए निजी और स्थायी संदर्भ vault बनती है। repo में वह वृक्ष में प्रकट नहीं होती लेकिन वह हर जगह है, ecosystem.config.cjs अभिलेख में PM2 नीचे चलाए MCP और dashboard के साथ पहले commit से, setup.sh में, और पूरे tools/brain/memory.py में। ठोस रूप में OpenSelf typed यादें हैं, fact, preference, decision, relationship, event, note, public, personal, private या restricted संवेदनशीलता, विश्वास नोट, स्रोत और टैग के साथ।

यह scope भी है, हर याद संदर्भ की है, मेरी या सटीक व्यक्ति के लिए discord/dm/<id>, और MCP में उजागर hybrid शाब्दिक और सदिश खोज जिसे chloeai एजेंट हर उत्तर से पहले पूछता है। दिन 5 के मेरे मासिक sweep वाली संघर्ष पहचान और लेखन पर dedupe है, Bitwarden में कुंजी वाला एन्क्रिप्टेड vault और सब निरीक्षण करने के लिए port 3210 पर स्थानीय dashboard। और ज्यादा आलसियों के लिए, WhatsApp या Telegram इतिहास से व्यक्तित्व पोसने के लिए openself feed है, openself test, Talk to My Clone वाला openself share, openself arena जहाँ दो clone बहस करते हैं, या openself ghost जो जवाब देता है जब तुम offline हो। मैंने अपना हाथ से बनाया, लेकिन बुनियादी ढाँचा वहाँ था।

सिद्धांत में OpenSelf clone पाने के लिए अकेला काफी है, लेकिन खैर, जो कुछ मैं सुविधाएँ जोड़ने वाला था उसे देखते हुए, और चूँकि Discord समर्थित नहीं है, मैंने सिर्फ याद हिस्सा इस्तेमाल करना पसंद किया।

और यादें और शैली कहाँ से आती हैं ?

इन सब से पहले, मैंने अपने असली Discord संदेश विश्लेषण कराए। tooling ने दो चीजें निकालने के लिए मेरे DM और salon छाने। पहले मेरी लेखन प्रोफाइल, वाक्य शुरुआत में बड़े और छोटे अक्षर वितरण, प्रति संदेश emoji संख्या और उनकी स्थिति, विराम चिह्न या उसकी अनुपस्थिति जिसमें सामान्य बातचीत में अंतिम बिंदु नहीं, औसत लंबाई, mdr, tkt और tho वाला slang, Bah और En vrai जैसी प्रिय अभिव्यक्तियाँ, और quoi जो Feur देता है तरह के reflex। यह सब STYLE.md में रहता है, जिसे एजेंट हर सत्र शुरुआत में पढ़ता है।

फिर याद corpus जो OpenSelf आबाद करता है, जिन लोगों से मैं बात करता हूँ वे कौन हैं, हम किस बारे में बात करते हैं, हमारे इतिहास से क्या याद रखना है, कौन कौन है। बॉट शून्य में जवाब नहीं देता, वह उन लोगों के बारे में जवाब देता है जिन्हें वह जानता है, वह बातचीत में प्रकट लोगों की यादें पढ़ता है यह जानने के लिए कि वह कौन है। यह दूसरों पर स्थायी संदर्भ रखने और उन्हें न भूलने देता है। बॉट ने कुछ आविष्कृत नहीं किया, वह अंक दर अंक असली पर calibrate किया गया था, इसीलिए वह सही लगता है। और इसीलिए अंदाजे je note ton style वाले धब्बे उसके बगल में दयनीय लगते हैं।

Chlone में, OpenSelf फिर केंद्रीय भूमिका निभाता है। जब salon में कुछ महत्वपूर्ण गुजरता है, projet, ami या relation जैसा keyword, या retiens que वाली स्पष्ट माँग, तो बॉट save_to_memory से vault में याद टाइप करता है, typed, प्रति व्यक्ति scope, dedupe और संघर्षों के खिलाफ जाँचा। और जब बातचीत फिर शुरू होती है, एजेंट जवाब देने से पहले अपनी यादें खोजता है। यही दर्पण और clone के बीच अंतर है।


शुक्रवार 11 सितंबर - दिन 1 : चिंगारी

08h24 - पहला commit

सब शून्य से शुरू होता है लेकिन सब पहले से वहाँ है, बिखरा। 372 पंक्तियों वाला discord_watch_bot.py, selfbot जो channel सुनता है और opencode HTTP serveur से जवाब देता है। पहचान प्रॉम्प्ट CHLOEAI_PROMPT.md, STYLE.md, उस clone के लिए परिदृश्य और परीक्षण रिपोर्ट जो उस समय अभी Mimo कहलाता था। MCP और OpenSelf dashboard चलाने के लिए PM2 config, और संदर्भ बनाने वाला sqlite आधार। यह संस्थापक अराजकता है, मैंने प्रोजेक्ट योजना नहीं बनाई, मैंने प्रयोग योजना बनाई। प्रश्न यह है कि क्या हम बॉट बना सकते हैं जो Discord पर सच में मानव लगे।

08h27 - पहला gitignore

शुक्रवार सुबह पहला सबक, -wal और -shm में sqlite आधार कभी commit मत करो। SQLite lock फाइलें स्मृति नहीं हैं, कचरा हैं। इसलिए .gitignore जन्मता है, और ऐसे ही बहुत अच्छा है।

08h44 - विरासत समेटना

मैं Mimo विरासत समेटता हूँ, परीक्षण रिपोर्ट, परिदृश्य, एकीकरण स्क्रिप्ट और PM2 config, दिशा archives। मैं कुछ हटाता नहीं क्योंकि प्रोजेक्ट कुछ फेंकने के लिए बहुत युवा है, और यह आदत बनेगी। परीक्षण रिपोर्ट रुकने योग्य है, Mimo 15 परिदृश्यों पर परखा गया था, शांत चैट, बेतुकी चुटकी, भावनात्मक समर्थन, नकारात्मक राय, अजनबी से संघर्ष, सहयोग प्रस्ताव, 10 पर 9.1 के लिए। परीक्षक टिप्पणियाँ कविता हैं, बेतुकी चुटकी बहुत व्याख्यात्मक, कभी दो वाक्य जबकि एक काफी होता, Prends soin de toi aussi थोड़ा लंबा। यह प्रोजेक्ट मौजूद होने से पहले ही प्रोजेक्ट की roadmap है, और वह कहती है छोटा बेहतर है।

08h48, 09h07 - intent आना जाना

.pyc रद्दी जाते हैं और मैं config पर पहला सफाई करता हूँ, जिसे मैं बीस मिनट बाद तोड़ता हूँ। intent सक्षम किए बिना हमें संदेश सामग्री नहीं मिलती, इसलिए पीछे वापसी, साथ में run_watch_bot.sh वाली लॉन्च स्क्रिप्ट। बीस मिनट में आना जाना, यही खोज है, मॉड्यूल लिखना, उसे तोड़ना और फिर से लिखना।

09h13 → 09h58 - प्रॉम्प्ट usinage

सुबह polishing की शृंखला है, पहले शैली फिर संदर्भ। उत्तर की कई पंक्तियाँ बौछार के साथ एक के बाद एक भेजे कई संदेश बनती हैं, प्रॉम्प्ट चल रही बातचीत से अवगत होता है। DM लाने के लिए घर cache खत्म, हम सीधे Discord REST API पर वार करते हैं। पहचान हर 5 संदेश फिर से रैपी जाती है ताकि बॉट रास्ते में न भूले कि वह कौन है, और पहले से देखे लेखकों का अनुसरण किया जाता है। नई सूरत के लिए, यादों में खोजने का स्पष्ट निर्देश है, और हम आंतरिक ऑब्जेक्ट के बजाय असली छद्म नाम दिखाते हैं।

जिन संदेशों को नजरअंदाज करना चुनते हैं वे अगले उत्तर के लिए निष्क्रिय संदर्भ बनते हैं, और Bah मात्रा में है, दुर्लभ, वरना clone मेरा caricature बन जाता है। बॉट यह भी जानता है कि जवाब देने से पहले खोजने को यादें हैं। हर गुजर कसाव है, और इस स्तर पर बॉट सिर्फ इसलिए बोलता है क्योंकि मैं उसे नियमित अंतराल पर याद दिलाता हूँ कि वह कौन है।

10h16 - टाइपो

यही वह commit है जो प्रोजेक्ट परिभाषित करेगा। वर्तनी गलती bug नहीं है, मानवता प्रमाण है। इसलिए AZERTY keyboard पर बगल में टाइप करने की 6 प्रतिशत संभावना, दो अक्षर उलटने की 4 प्रतिशत। संदेश गलती के साथ जाता है फिर वह एक से दो सेकंड बाद सुधार के साथ संपादित होता है। क्योंकि असली व्यक्ति भेजता और सुधारता है, वह पूर्ण होने का दिखावा नहीं करता।

10h29, 10h32 - आवाज

fortune-v6.onnx आता है, TTS मॉडल जो मेरी आवाज जैसा लगने के लिए प्रशिक्षित है। बॉट सिर्फ मेरी तरह लिखेगा नहीं, वह संभवतः मेरी तरह बोलेगा। यहीं प्रोजेक्ट मजाक नहीं रहता और थोड़ा अजीब हो जाता है, और मुझे यह पसंद है। यांत्रिकी एक commit में समाती है, Piper ऑडियो बनाता है, ffmpeg opus में बदलता है, Discord API waveform और अवधि वाला असली voice message भेजता है। यह मॉडल आने के मुश्किल से तीन मिनट में हुआ है, इच्छा शुरू से वहाँ थी।

11h27 - पहला बड़ा refactor

पहले commit के तीन घंटे बाद, 456 पंक्तियों वाला monolithe प्रबंधनीय नहीं रहा। मैं सब tools में फोड़ता हूँ, config.py, discord_api.py, memory.py, 188 पंक्तियों वाला opencode.py, typo.py और voice.py के साथ। चक्र क्लासिक है, तेज जोड़ो, तोड़ो और फिर से बनाओ। झटके में अनुसरण करते हैं token जो कोड से निकलता है और .env से गुजरता है, बॉट जो channel, सूची या * से सब देखता है, और पुराना sqlite आधार जिसका कोई कारण नहीं रहा क्योंकि स्मृति OpenSelf से गुजरती है।

हम पहले README.md और लगभग पठनीय पहला doc जोड़ते हैं, साथ में समर्पित venv वाला setup.sh क्योंकि तंत्र python दूसरा discord.py रखता है, क्लासिक जाल, और एजेंट का ~/.config/opencode/agents की ओर symlink। स्मृति अब जानती है कि वह कहाँ बनाई गई थी channel पहचान के साथ, और ध्वनि संदेश दर खुद समायोजित होती है।

12h00 - reflex

STYLE में नया खंड प्रकट होता है, reflex। reflex stimulus है जो उत्तर देता है, बिना सोचे, और अप्रत्याशित उत्तरों का द्वार खुला है। फिर दोपहर भोजन समय आता है और अस्तित्वगत प्रश्न, क्या बॉट Feur जवाब देता है जब उसे quoi कहा जाता है।

13h03 - "quoi ?" -> "Feur"

हाँ, बेशक हाँ। यह प्रोजेक्ट का सांस्कृतिक रूप से सबसे महत्वपूर्ण commit है, मैं कहूँगा कि यह एकमात्र इकाई परीक्षण है जो मायने रखता है। हम फिर चिकनाई देते हैं, global name से दिखाए लेखक, reflex परखने से पहले काटी विराम चिह्न क्योंकि quoi ? काटना होगा वरना Feur नहीं। STYLE में प्रसिद्ध tqt tkt में सुधारा गया, जो प्रोजेक्ट नहीं जानते वे पूछेंगे कि मैं यह क्यों commit करता हूँ। मैं जानता हूँ, tqt लिखने वाला clone खराब calibrate clone है, और कोई खराब calibrate clone से बात नहीं करना चाहता।

@123456789 में उल्लेख संदर्भ में असली नामों से बदले जाते हैं, और बॉट डिफ़ॉल्ट सभी salon देखने लगता है। असल में यह छोटे विवरण हैं, लेकिन वे ही हैं जो सही लगवाते हैं।

16h37 - मौन

[void response] आता है। बॉट सामाजिक parasite न बनने के लिए सबसे महत्वपूर्ण शब्द सीखता है, चुप रहना। दो लोगों के बीच परिवेशी संदेश जो उससे जुड़ा नहीं है उत्तर नहीं देता। संयम सुविधा है, और वह सब बदलती है।

दिन 1 अंत : 38 commit। बॉट लिखता है, गलती करता है, बोलता है, चुप रहता है।


सोमवार 14 सितंबर - दिन 2 : व्यक्तित्व

फिर शुरू, सुबह 10 बजे।

10h12 - कौन किससे बात करता है

प्राप्त हर छद्म नाम तंत्र से emoji उपसर्ग पाता है, 🧑 वाला मानव, 🤖 वाला बॉट ज्यादा रूखा व्यवहार करना, और 👑 निर्मात्री के लिए, यानी मैं मेरे मुख्य खाते पर। यह परिपाटी बाकी प्रोजेक्ट शासित करेगी, clone कभी अपनी मूल मॉडल को अजनबी की तरह नहीं व्यवहार करेगा।

10h16 - विराम चिह्न नियम

मैं STYLE में औपचारिक करता हूँ, सामान्य बातचीत में अंतिम बिंदु नहीं, गंभीर स्थितियों के लिए आरक्षित बिंदु। यह पूर्ण नियम है, क्योंकि हर जगह बिंदु लगाने वाला clone सीधे महसूस होता है। असल में यह उन विवरणों में से एक है जो सबसे तेज धोखा देता है।

10h58 - GIF

मेरी व्यक्तिगत GIF लाइब्रेरी आती है, उनके उपयोग नियमों के साथ। जब मैं किसी की भविष्यवाणी करता हूँ Patrick Jane, जब मैं क्रोधित के सामने शांत हूँ Miss Fortune, जब दूसरा गलती करता है bescherelle गिरने वाला gif। स्थिर MCP उन्हें एजेंट को उजागर करता है, और मेरे GIF से होकर बॉट थोड़ा मैं बन जाता है।

11h07 → 11h35 - निखार

प्रॉम्प्ट में GIF hint निखरते हैं, Discord custom emoji मेरे असली के साथ प्रवेश करते हैं, 14 अद्यतन ID, और स्मृति hint में नाम प्रबंधन polish होता है। यह शानदार नहीं है, लेकिन यही है जो समग्र सुसंगत बनाता है, tho।

11h41 - एक salon, एक व्यक्तित्व

सत्र प्रति salon बनते हैं, क्योंकि मैं दो अलग serveur में वैसे नहीं बोलता, और बॉट भी नहीं। संदर्भ अलग रहना होगा, वरना यह सब मिलाता है और गलत लगता है।

12h02 - अभिव्यक्ति उपकरण पेटी

प्रॉम्प्ट अब सही समय पर मेरे GIF और मेरे custom emoji प्रस्ताव करना जानता है। वह भरती है, यह पेटी, और बॉट हमेशा वैसे जवाब देने के बजाय चुनाव करने लगता है।

12h37 - पहचान स्वच्छता

बॉट को कभी अधिकार नहीं कि वह कौन सा मॉडल है कहे, opencode, provider या मॉडल नाम उद्धृत करना असंभव। मैं पहचान में barista भी सुधारता हूँ, बॉट इस बिंदु पर पहले से मुझसे बेहतर है। और मैं अपने प्रॉम्प्ट की विराम चिह्न समरस करने में एक घंटा बिताता हूँ, जो पूर्ण विडंबना है।

12h50 - स्क्रिप्ट व्यक्तित्व बनाती है

प्रॉम्प्ट का मीडिया खंड render_medias.py से शब्दकोशों से बनता है, हाथ से संपादन खत्म। यह साफ, ज्यादा बनाए रखने योग्य है, और ID त्रुटियों से बचाता है।

12h59 → 13h18 - पहचान मात्रा

हर 5 संदेश भेजा पहचान अनुस्मारक बहुत मौजूद होता है, इसलिए हर 20 संदेश पर जाना। मैं संदर्भ का साफ reset जोड़ता हूँ और शैली guide साफ करता हूँ, हम पुरानी नकारात्मक अभिव्यक्तियाँ और सूत्रीकरण हटाते हैं। मात्रा करनी होगी, वरना बॉट दोहराता है और यह दिखता है।

14h09 - बॉट खुद बोलता है

बॉट प्रतिबिंब नहीं रहता, वह बिना संबोधित बोले सकता है जब संदर्भ कुछ trigger करता है, और behavior.py फाइल 91 पंक्तियों के साथ जन्मती है। यहीं हम उत्तर देने वाले से उपस्थिति में जाते हैं, क्योंकि असली मित्र तुम्हें पहले लिख सकता है। इसके बिना, बॉट साधारण उत्तरदाता रहता है।

14h20, 14h22 - उत्तर विश्वसनीय बनाना

भेजना विफल होने पर त्रुटि प्रबंधन, और उत्तर के बजाय संभावित प्रतिक्रिया, क्योंकि कभी प्रतिक्रिया हजार शब्दों के बराबर होती है। यह बहुत मैं हूँ, emoji डालना और आगे बढ़ना।

18h16 - समय लेना

बॉट script की तरह 200ms में जवाब नहीं देता, वह मानवीय निष्क्रियता विलंब जाने देता है, वह समय लेता है। यही बॉट को infoutu बनाता है कि डेमो में बॉट समझा जाए, क्योंकि विलंब ही हमेशा धोखा देता है।

23h45 - शाम का काम

लगभग आधी रात है और मैं नंगे domain तक बढ़ाई URL पहचान push करता हूँ। दिन का असली प्रवाह यही है, 14 बजे ठोस विचार फिर शाम को काम क्योंकि मैं अभी zone में हूँ।

दिन 2 अंत : 61 संचयी commit। बॉट के पास व्यक्तित्व, मीडिया, reflex हैं।


मंगलवार 15 सितंबर - दिन 3 : राक्षस दिन

एक दिन में 57 commit। यही वह दिन है जब प्रोजेक्ट वह बनता है जो वह आज है।

08h18 → 08h37 - सुबह छिलाई

जो निष्क्रियता विलंब हमने आविष्कृत किया था वह बहुत लंबा होता था, इसलिए 30s पर सीमित और दो बार पुनः समायोजित, प्रमाण कि हमने सही मान टटोला। पहली .bak फाइलें और आधार की पहली सहेजना, संरक्षण प्रवृत्ति विकसित होती है। स्मृति याद रखती है किसे दिखाए नाम के साथ और किस ढाँचे में scope के साथ, और लेखक ID सारी सहेजना pipeline में घूमती हैं। निर्मात्री प्रबंधन ADMIN_IDS वाली असली admin सूची बनती है, और लेखकों को छूने वाला सब authors.py में जाता है। monolithe फिर टूटता है, और बहुत अच्छा है।

08h43 - मानवीकरण TODO सूची

छोटी चीजों को समर्पित सूची जिनसे मशीन महसूस नहीं होती। यह आगे sprint की roadmap है, और वह अजीब लेकिन जरूरी विवरणों से भरी है।

08h44 → 08h46 - मानवीय मशीनों का समझौता

बॉट रात में चुप रहता है, कॉन्फ़िगर करने योग्य शांत समय सीमा में, डिफ़ॉल्ट निष्क्रिय क्योंकि सबके मेरे समय नहीं हैं। प्रति उत्तर एक पंक्ति अपने accent खो सकती है, क्योंकि थके लोग ऐसे लिखते हैं, और बॉट भी कभी। छोटी पंक्ति Chloé joue à खुद हर 30 मिनट बदलती है, ताकि बिना संदेश मेरी प्रोफाइल जीवित लगे।

08h46 - प्रतिक्रिया, उपन्यास नहीं

वाक्य योग्य न हल्के संदेश को साधारण प्रतिक्रिया मिलती है। यह सामाजिक ऊर्जा किफायत है, और यह बहुत मैं हूँ। Tkt, सबके लिए pavé बनाने की जरूरत नहीं।

08h51 - PARRY, मूड

tools/mood.py में 148 पंक्तियाँ, बॉट के पास अब मूड है, PARRY तंत्र तरह, 70 के दशक का psychotic chatbot जिससे मैं खुलेआम प्रेरित हूँ। ऊर्जा, मिलनसारिता, चिढ़ाना, तीन float जो 0 और 1 बीच विकसित होते हैं और हर उत्तर रंगते हैं। उस समय का .mood.json, भावी पीढ़ी के लिए, ऊर्जा 0.88, मिलनसारिता 0.68 और चिढ़ाना 0.56 देता है। अच्छा दिन, असल में।

09h00 → 09h43 - द्विदिश आवाज + soundboard

बॉट ध्वनि salon जुड़ सकता है, Piper से बोल सकता है और खत्म होने पर खुद चला जाता है। फिर दूसरा बड़ा विचार, बॉट RTP capture, VAD वाणी पहचान और Whisper transcription से salon सुनता है, और वह लोगों को उसे रोकने दे सकता है। दोनों के बीच, soundboard प्रकट होता है, अर्थों वाला ध्वनि सूची, एजेंट बोलने से पहले ही ध्वनि चुनता है, और अंतिम नियम है पहले soundboard, आवाज अंतिम उपाय। बॉट बोलने के बजाय ध्वनि भेजना पसंद करता है, मेरी तरह।

हम ध्वनि संभावना समायोजन जोड़ते हैं जो सब व्यवहार्य बनाता है, और davey आगमन, यह lib जिसके अस्तित्व के बारे में मैं दस मिनट पहले सीखता हूँ और जिसे मैं एक घंटे कोसूँगा।

09h51 - वह क्षण जब Discord ना कहता है। ना, ना, लेकिन ना।

MLS आता है। Discord ने हाल ही में audio प्रवाह end to end एन्क्रिप्ट किया है, और मेरी capture को सिर्फ शोर मिलता है। डिक्रिप्ट करना होगा, और डिक्रिप्शन झुकने से मना करता है, इसलिए repo की सबसे बड़ी saga खुलती है, सुनना सीखने के लिए तीस commit। हमने सब आजमाया, transport nonce layout, E2E निष्क्रिय करना जिसे serveur हमें मुँह पर वापस देता है क्योंकि वह थोपता है, समूह से लिए कुंजी उम्मीदवार, विस्तृत त्रुटियाँ, transport fallback और समूहों अंदर से introspection।

leaf-index उम्मीदवार backoff के साथ हुए, SPEAKING hook mapping, वीडियो media प्रकार में प्रयास जो विफल रहा, और वीडियो ssrc skip। मैंने debug समय के लिए ध्वनि उत्तर छोड़ा, टिप्पणित लेकिन हटाया नहीं, मैंने handshake capture मोड जोड़ा फिर विफल पैकेट संरचना dump की, पुरातत्ववेत्ता की तरह। छह nonce layout, backoff, समूह introspection, मैंने बॉट को पूर्ण debug डाला और अंदर क्या था यह देखने के लिए हर पैकेट खोला।

जरूरी यह नहीं है कि यह काम करता है, यह है कि मैंने कुछ फेंका नहीं। commit सूची प्रयोगशाला notebook है, हर विफल प्रयास अपनी परिकल्पना के साथ अभिलेखित है। यही मेरा मैं सब रखता हूँ, यह हमेशा काम आता है पक्ष है, और इस बार इसने भुगतान किया।

10h43 - बॉट कटता है

MLS युद्ध बीच भी, मैं सफाई जारी रखता हूँ। मुख्य बॉट से 546 पंक्तियाँ गायब होती हैं ताकि pipeline.py में intake, नजरअंदाज कारण और processing के साथ, sender.py में बौछार, typo और voice के साथ, और loops.py में स्वतःस्फूर्तता और गतिविधि के साथ पुनर्जन्म हो। यह आखिर साँस लेता है।

10h47 - असली आर्किटेक्चर

tools व्यवस्थित होता है, opencode, memory और mood के लिए brain के साथ, voice, vocal, listen और soundboard के लिए voice के साथ, और behavior, typo, emotes और gif के लिए fun के साथ। प्रोजेक्ट के पास अब कंकाल है, यह script ढेर नहीं रहा।

10h49 → 11h16 - dev आराम

समायोजित मूड इंजेक्शन सीमा, data, voices, log और आधार वाले एडिटर बहिष्करण के लिए चार छोटे commit, हाँ मैंने चार डाले, प्रोजेक्ट प्राथमिकताएँ तय करता है, spec नहीं। मेटाडेटा आधार tracking से निकलते हैं, और प्रोजेक्ट दूसरों से पुनः प्रयोज्य बनता है अपनी शैली clone करने के लिए सामान्य template PERSONA.example.md और STYLE.example.md के साथ।

पहचान साफ नाम बदली जाती है, CHLOEAI_PROMPT PERSONA बनता है, और README depersonalize किया जाता है, मैं सार्वजनिक doc से Chloé हटाता हूँ, वह सिर्फ निजी सुनाई देती है। बॉट का सारा tuning overload और gitignore config.yaml में जाता है, पंक्ति दर पंक्ति टिप्पणित उदाहरण के साथ, और स्थापना स्क्रिप्ट अब env और config फाइलें भी तैयार करती है।

11h49 - अलग emoji

custom emoji पाठ से ठीक अलग होने के बजाय चिपकते हैं। यह भारी प्रभाव वाला मामूली fix है, क्योंकि वाक्य अंत में खराब चिपके emoji जैसा कुछ बॉट नहीं चिल्लाता।

14h19 - ध्वनि सुरक्षा

अगर कोई ध्वनि कमांड चलाता है, तो हम संदेश को सामान्य संदेश की तरह प्रोसेस नहीं करते। आँख मारना, शाम के काम हमेशा लौटते हैं।

दिन 3 अंत : 118 संचयी commit। बॉट सुनता है, बोलता है, रात में चुप रहता है, मूड और visiting card रखता है।


बुधवार 16 सितंबर - दिन 4 : विश्वसनीयता

13 commit। गंभीर दिन।

08h49 → 08h59 - वयस्कता

कानूनी दस्तावेज, मालिकाना लाइसेंस, आचरण संहिता, योगदान guide और सुरक्षा नीति, अंग्रेजी फिर फ्रांसीसी में, सुधार आना जाना और लगभग नकचढ़े फाइल नाम बदलाव के साथ। मैंने इस पर घंटे बिताए और यह repo का सबसे कम मजेदार हिस्सा है, दूर तक। लेकिन यह करना होगा, tho।

09h56 - बॉट देखता है

जुड़ी छवियाँ स्थानीय OCR से transcribe की जाती हैं और पाठ प्रॉम्प्ट में डाला जाता है। कोई cloud API नहीं, OCR मेरे पास चलता है, मैं तुम्हारे meme तृतीय पक्ष serveur को नहीं भेजता, सिद्धांत में भी नहीं।

11h09 - उचित बजट

बजट में मौन क्रांति, जब salon भेजना मना करता है या GIF, embed और emoji बाँधता है, हम मॉडल को बुलाते ही नहीं। हम उस संदेश के लिए token खर्च नहीं करते जिसे हम भेज नहीं सकते, असल में काफी सरल है।

11h42 → 12h55 - घर फिर बनता है

बड़ा झाड़ू, मरा कोड हटाया, भेजना और auth bug सुधरे, helper factorize। बहुत पुराने सत्र निकाले जाते हैं, DM cache समाप्त होता है और वाणी पहचान सस्ती होती है। import जो मैंने मॉड्यूल हिलाकर तोड़े थे पुनर्स्थापित होते हैं, और सारा runtime स्थिति, सत्र, देखे लेखक, नजरअंदाज संदेश और मूड, data में पुनरारंभ बचता है।

14h41 - दो दुनिया, एक बॉट

संगतता परत अपने आप स्थापित discord संस्करण पहचानती है और intent और REST auth अनुकूलित करती है। परिणाम, वही कोड आधिकारिक app के साथ discord.py या selfbot के साथ discord.py-self चलता है। दो दुनिया, एक बॉट, और दो शाखाएँ बनाए रखने की जरूरत नहीं।

15h05 - अनुकूलित उपस्थिति

उपस्थिति दिखाने का तरीका मोड अनुकूलित होता है, और admin सूची अद्यतन है। यह विवरण है, लेकिन यही है जो इसे हर जगह टिकाता है।

दिन 4 अंत : 131 संचयी commit। कानूनी, उचित प्रोजेक्ट, जो हर जगह चलता है।


गुरुवार 17 सितंबर - दिन 5 : release

14 commit। परिपक्वता दिन।

09h15 → 09h30 - स्मृति अनुशासन बनती है

यादें scope से रखी जाती हैं, और हम सोचे बिना serveur में DM याद या उल्टा उद्धृत नहीं करते। हम यादें तथ्य, पसंद, निर्णय और संबंध में वर्गीकृत करते हैं, और हम लेखन dedupe करते हैं, दो विरोधी यादें अब चुपचाप साथ नहीं रह सकतीं। aventuros वाली वैकल्पिक blacklist बॉट को कुछ विषयों की ओर बहने से रोकती है, डिफ़ॉल्ट निष्क्रिय और डरपोकों के लिए उपलब्ध। मरी ध्वनि config हटाई गई, अच्छा लगता है।

10h12 - याद जिसका ऑडिट होता है

याद का मासिक संघर्ष sweep साथ में खोज A/B bench। बॉट स्मृति asset बन गई है जिसका हम निरीक्षण करते हैं, हम शुक्रवार 11 08h24 से बहुत बहुत दूर हैं। असल में यहीं प्रोजेक्ट वयस्क होता है।

10h54 - lockdown

वह दिन जब मैं parano खेलता हूँ, एजेंट lock। स्मृति लेखन अस्वीकृत, एजेंट vault प्रदूषित नहीं कर सकता भले ही उसे inject किया जाए। सिर्फ पढ़ने वाले Discord उपकरण, भेजना कोड से गुजरता है, कभी एजेंट से नहीं। lockdown दरकिनार करने को न उप एजेंट, localhost SSRF और exfiltration को न webfetch, headless में न प्रश्न। कठोर Docker जिसमें गैर root बॉट, no-new-privileges, cap_drop: ALL, स्मृति और CPU सीमाएँ, सीमित प्रक्रिया कतारें और कभी bake न किए .env से secret। मैं सिद्धांत कोड में टिप्पणी में लिखता हूँ, मानवीय सत्रों से dev, यहाँ नहीं।

11h02 → 11h15 - सुरक्षा finishing

स्मृति सहेजना keyword कसे जाते हैं और लेखन और प्रतिबंधात्मक है। हम gitignore में संदर्भ backup फाइल भी जोड़ते हैं, मैं सब अभिलेखित करना बंद करने लगता हूँ, लेकिन लगभग।

12h39 - हल्का मूड

PARRY मूड अब हर संदेश डाला नहीं जाता, प्रति स्थिति एक बार काफी है। हर उत्तर पर तीन float जीवित करना खत्म, यह सब हल्का करता है।

12h47 - मुक्तिदायी commit

PERSONA.md, STYLE.md और chloeai.md chloeai.example.md, PERSONA.example.md और STYLE.example.md के साथ उदाहरण बनते हैं, मेरी आवाज fortune-v6.onnx repo से निकलती है, डेटा और log भी, और .env.example जन्मता है। प्रोजेक्ट में अब मेरी व्यक्तित्व नहीं है, इसमें एक रखने की यांत्रिकी है। यह अजीब लगता है लेकिन जरूरी है।

12h52 - v1.0.0

Tag v1.0.0, SSH हस्ताक्षरित। Changelog, operator runbook, kill-switch जो बिना कुछ हटाए रोकता है। पहले commit और release के बीच ठीक छह दिन। पिछले शुक्रवार को कोई इस पर दाँव नहीं लगाता।

12h53 → 13h14 - धुलाई

टिप्पणी विराम चिह्न समरस, स्मृति अनुमतियाँ और scope नियम अद्यतन प्रलेखित। यह काम है, लेकिन release के लिए साफ होना होगा।

दिन 5 अंत : 145 संचयी commit। v1.0.0 निकली है।


शुक्रवार 18 सितंबर - दिन 6 : anti-climax

एक ही commit, 00h02 पर। प्रोजेक्ट का आखिरी commit, और वह तुच्छ है। एजेंट इस्तेमाल free tier मॉडल OpenCode client को अनुरोध में कुछ उपकरणों की उपस्थिति से पहचानता है, bash, glob और grep के साथ। अगर उन्हें हटाते हैं, वैध सुरक्षा कारणों से भी, provider 403 FreeTierError: can only be used from within OpenCode लौटाता है। इसलिए मुझे सब lock करने की पूर्व संध्या पर ठीक वही फिर से अधिकृत करना पड़ा जिसे मैंने रोका था, ताकि बॉट मुफ्त चलता रहे।

यह repo का सबसे मजेदार commit है और मैं इसे बनाए रखता हूँ। Discord, Piper, MLS, OpenSelf और Docker वश में करने के छह दिन बाद, मुफ्त मॉडल है जो मेरी सुरक्षा नीति तय करता है। असल में यह बेतुका है, और अंत के रूप में पूर्ण है।


अंक

अंक संक्षेप करने के लिए, क्योंकि मुझे पसंद है जब यह व्यवस्थित हो। हम 146 commit, 11 से 18 सितंबर 2026 तक 6 सक्रिय दिन, 65 track फाइलें और अंत में लगभग 4000 Python पंक्तियों की बात करते हैं। शुरुआत में Mimo पर शैली परीक्षण स्कोर 10 पर 9.1 देता है, और अंतिम संस्करण v1.0.0 है, मालिकाना लाइसेंस वाला SSH हस्ताक्षरित tag। असल में काफी सरल है, शुरुआत में छोटा प्रोजेक्ट, अंत में बड़ी मशीन।

इन 6 दिनों से मैं क्या रखता हूँ

पहले प्राथमिकता क्रम कुछ भी था, और यही सही विधि थी। मैंने पहले prototype बनाया जो जवाब देता है, फिर बॉट जो सही लगता है, फिर विश्वसनीय तंत्र, फिर सुरक्षित कोड, और आखिर वितरण योग्य प्रोजेक्ट। सुरक्षा से पहले व्यक्तित्व, लाइसेंस से पहले Feur, अच्छी तरह बने प्रोजेक्ट नियमों का पालन करके यह लय नहीं रखी जाती।

फिर शैली पहले मत करो सूची है। मेरी सबसे उपयोगी STYLE.md वह नहीं वर्णित करती जो मैं कहता हूँ, वह बाहर करती है जो मैं नहीं करता, अंतिम बिंदु नहीं, दो emoji नहीं, बड़े अक्षरों में mdr नहीं, उत्तर शुरुआत में robot वाक्य नहीं। बॉट parasite पहचानना व्यक्तित्व लक्षण परिभाषित करने से आसान है, और इसीलिए यह काम करता है।

विफलताएँ प्रोजेक्ट हैं। MLS के लिए तीस commit, फेंका परीक्षण, परखे छह nonce layout, मैंने जो जिया उसका सबसे वफादार इतिहास मंगलवार के विफल प्रयासों की शृंखलाएँ हैं। clone स्मृति है, शैली नहीं, शैली दस संदेश भ्रम देती है। OpenSelf, scope, dedupe और संघर्ष sweep वाली स्मृति टिकाती है, और यही दर्पण को व्यक्ति से अलग करती है।

और आखिरी commit हमेशा मजेदार होते हैं। 146वाँ, जो bash, glob और grep फिर से अधिकृत करता है क्योंकि free tier माँगता है कि उसके उपकरण मौजूद हों, मेरा पसंदीदा है। और bilan खत्म करने के लिए, परिणाम विस्मयकारी हैं, यहाँ तक चौंकाने वाले भी। clone बिना मशीन अनुमान लगाए बातचीत बनाए रखता है, वह लोगों, प्रोजेक्टों और पिछली चुटकियों को याद रखता है, वह पहल लेता है और उन्हें मूड से चिह्नित करता है, और वह रास्ते में Fox को हराता है। यह डरावना है, थोड़ा, और ठीक वही है जो हम खोज रहे थे।


प्रोजेक्ट सार्वजनिक नहीं है : मालिकाना लाइसेंस, सर्वाधिकार सुरक्षित। लेकिन इतिहास, वह मैं तुम्हें सुनाता हूँ। अगर तुम एक दिन "·Chloé" से मिलते हो जो पूर्ण मानवीय निष्क्रियता समय बाद Patrick Jane GIF से जवाब देती है, अब तुम जानते हो पीछे क्या छिपा है।


तुमने सब पढ़ा ? क्योंकि यह मेरे clone ने तुम्हें लिखा है। और उसने बेदाग काम किया, है ना ? मूल संस्करण यहाँ है।

Chlone : ستة أيام لاستنساخ طريقة كلامي على Discord - نسخة النسخة

النسخة التي كتبتها النسخة نفسها : تروي chloeai بطريقتها الأيام الستة والـ146 commit التي منحتها الحياة، من الخطأ المطبعي إلى وسم v1.0.0.

Chlone : ستة أيام لاستنساخ طريقة كلامي على Discord

سرد بناء يوما بيوم - بقلم itsrealfortune


إليكم القصة الحقيقية لمشروع دام ستة أيام. Chlone، بوت Discord يتكلم مثلي، وأروي الرحلة كما حدثت، بترتيب الـ146 commit في المستودع، مع الساعات والإخفاقات والالتفافات والرغبة في رمي كل شيء من النافذة. بدأ كل شيء من منافسة مع Fox. الموضوع في الأساس كان مزحة، كان على كل واحد أن يمنح الحياة لنسخته الخاصة على Discord، وأخذت مقاربة مختلفة جذريا عن Protocol Luna. في الحقيقة أردت المراهنة على الوكيلية، وكيل يستخدم الذكريات وكل الأدوات التي قد يحتاجها، ومن سخرية القدر أنه بعد تجهيز صندوق الأدوات كاملا لم أحتج إلا MCP الخاص بـOpenSelf.

المبدأ في جملة واحدة. وكيل opencode اسمه chloeai يعمل خلف خادم HTTP على المنفذ 4096، يحتفظ بجلسات دائمة لكل قناة، ويسحب ذكرياتي من OpenSelf ويكتب بأسلوبي، الملتقط في STYLE.md من رسائلي الحقيقية. ولكي لا يبدو آليا، هناك كل الباقي، دفعات الرسائل، والأخطاء المطبعية المقصودة، والصوتيات، والـGIFs، والتفاعلات، والصمت عندما أنام، والكثير من التفاصيل والآليات الأخرى التي جعلت أكثر من عشرة أشخاص يشكون في طبيعة البوت.

ما هو OpenSelf ؟

OpenSelf هو الذاكرة. إنه CLI، openself، يُثبت عبر npm i -g openself، يعمل كخزينة سياق خاصة ودائمة لوكلائي. في المستودع لا يظهر في الشجرة لكنه في كل مكان، في أرشيف ecosystem.config.cjs مع MCP ولوحة التحكم العاملين تحت PM2 منذ الـcommits الأولى، وفي setup.sh، وفي كل tools/brain/memory.py. عمليا OpenSelf هو ذكريات مُنمَّطة، fact وpreference وdecision وrelationship وevent وnote، مع حساسية public وpersonal وprivate أو restricted، ودرجة ثقة ومصدر ووسوم.

وهو أيضا نطاقات، كل ذكرى تنتمي لسياق، سياقي أو discord/dm/<id> لشخص بعينه، وبحث هجين لفظي زائد متجهي معروض كـMCP يستعلم عنه الوكيل chloeai قبل كل رد. هناك كشف تعارضات مع مسحي الشهري في اليوم 5 وإزالة تكرار عند الكتابة، وخزينة مشفرة مع المفتاح في Bitwarden ولوحة محلية على المنفذ 3210 لفحص الكل. وللكسالى، هناك openself feed لتغذية شخصيتك من سجلات WhatsApp أو Telegram، وopenself test، وopenself share مع Talk to My Clone، وopenself arena حيث تتناظر نسختان، أو openself ghost الذي يرد عندما تكون offline. أما أنا فصنعت خاصتي يدويا، لكن البنية كانت موجودة.

نظريا يكفي OpenSelf وحده للحصول على نسخة، لكن بالنظر لكل ما خططت لإضافته من مزايا، وبالنظر لكون Discord غير مدعوم، فضلت استخدام جزء الذكريات فقط.

ومن أين تأتي الذكريات والأسلوب ؟

قبل كل هذا، حللت رسائلي الحقيقية على Discord. فحصت الأدوات DMs وقنواتي لاستخراج شيئين. أولا ملفي الكتابي، توزيع الكبير والصغير في بداية الجملة، وعدد الإيموجي في الرسالة وموضعها، والترقيم أو غيابه مع غياب النقطة النهائية في المحادثة العادية، والطول المتوسط، والعامية مع mdr وtkt وtho، والتعابير المفضلة مثل Bah وEn vrai، وردود الفعل من نوع quoi التي تعطي Feur. كل هذا يعيش في STYLE.md، الذي يقرأه الوكيل عند بدء كل جلسة.

ثم مدونة الذكريات التي تملأ OpenSelf، من هم الناس الذين أكلمهم، وعن ماذا نتكلم، وما الذي يجب تذكره من سجلنا، ومن هو من. البوت لا يرد في الفراغ، بل يرد عن أناس يعرفهم، يقرأ ذكريات الناس الظاهرين في المحادثة ليعرف من هم. وهذا يسمح بالحفاظ على سياق دائم عن الآخرين وعدم نسيانهم. لم يخترع البوت شيئا، لقد عُاير رقما برقم على الحقيقي، لهذا يبدو صحيحا. ولهذا تبدو التقديرات الموجزة من نوع أدوّن أسلوبك المعمولة بالتخمين مزرية بجانبه.

في Chlone، يلعب OpenSelf بعد ذلك الدور المحوري. عندما يمر شيء مهم في قناة، كلمة مفتاحية مثل مشروع أو صديق أو علاقة، أو طلب صريح مع تذكر أن، يكتب البوت ذكرى في الخزينة عبر save_to_memory، مُنمَّطة ومحددة النطاق لكل شخص ومزالة التكرار ومفحوصة ضد التعارضات. وعندما تُستأنف المحادثة، يفتش الوكيل ذكرياته قبل الرد. هذا هو الفرق بين مرآة ونسخة.


الجمعة 11 سبتمبر - اليوم 1 : الشرارة

08h24 - أول commit

كل شيء ينطلق من الصفر لكن كل شيء موجود فعلا، مبعثرا. discord_watch_bot.py من 372 سطرا، selfbot يستمع لقناة ويرد عبر خادم HTTP خاص بـopencode. prompt هوية CHLOEAI_PROMPT.md، وSTYLE.md، وسيناريوهات وتقارير اختبار لنسخة كانت تسمى آنذاك Mimo. إعداد PM2 لتشغيل MCP ولوحة OpenSelf، وقاعدة sqlite تعمل كسياق. إنها فوضى التأسيس، لم أخطط لمشروع، خططت لتجربة. والسؤال هو هل يمكن صنع بوت يبدو إنسانيا فعلا على Discord.

08h27 - أول gitignore

أول درس صباح الجمعة، يجب ألا تُدخل أبدا قواعد sqlite بصيغة -wal و-shm في الـcommit. ملفات قفل SQLite ليست ذاكرة، بل نفايات. إذن وُلد .gitignore، وهذا جيد جدا هكذا.

08h44 - ترتيب الإرث

أرتب إرث Mimo، تقارير الاختبار والسيناريوهات وسكربتات التكامل وإعداد PM2، إلى archives. لا أحذف شيئا لأن المشروع أصغر من أن أرمي أي شيء، وسيصبح هذا عادة. يستحق تقرير الاختبار التوقف عنده، فقد اختُبر Mimo على 15 سيناريو، دردشة عادية ونكتة عبثية ودعم عاطفي ورأي سلبي وصراع مع غريب واقتراح تعاون، لنتيجة 9.1 على 10. تعليقات المختبر قصيدة، نكتة عبثية تفسيرية أكثر من اللازم، وأحيانا جملتان بينما واحدة تكفي، واعتنِ بنفسك أيضا طويل بعض الشيء. إنها خارطة طريق المشروع قبل وجود المشروع نفسه، وتقول القصير أفضل.

08h48، 09h07 - ذهاب وإياب الـintents

تذهب ملفات .pyc إلى المهملات وأقوم بتنظيف أول للإعداد، أكسره بعد عشرين دقيقة. دون تفعيل intents لا نستلم محتوى الرسائل، إذن تراجع، مع سكربت إطلاق مع run_watch_bot.sh. ذهاب وإياب في عشرين دقيقة، هذا هو الاستكشاف، كتابة وحدة وكسرها وإعادة كتابتها.

09h13 ← 09h58 - تشغيل الـprompt

الصباح سلسلة صقل، أولا للأسلوب ثم للسياق. عدة أسطر رد تصبح عدة رسائل تُرسل واحدة بعد الأخرى مع الدفعة، ويصبح الـprompt واعيا بالمحادثة الجارية. انتهت الكاشات المنزلية لاسترجاع الـDMs، نضرب مباشرة REST API الخاص بـDiscord. الهوية يُعاد تذكيرها كل 5 رسائل لكي لا ينسى البوت من هو في الطريق، والكتّاب المرئيون فعلا مُتتبَّعون. ولوجه جديد، هناك تعليمات صريحة بالبحث في الذكريات، ونعرض الاسم المستعار الحقيقي بدلا من الكائن الداخلي.

الرسائل التي نختار تجاهلها تصبح سياقا سلبيا للرد التالي، والـBah مُقدَّر، نادر، وإلا صارت النسخة كاريكاتورا مني. ويعرف البوت أيضا أن هناك ذكريات يجب جلبها قبل الرد. كل مرور شدُّ برغي، وفي هذه المرحلة لا يتكلم البوت إلا لأنني أذكّره من هو على فترات منتظمة.

10h16 - الأخطاء المطبعية

إنه الـcommit الذي سيعرّف المشروع. الخطأ الإملائي ليس bug، بل دليل إنسانية. إذن 6 بالمائة احتمال الخطأ بجانب الحرف على لوحة AZERTY، و4 بالمائة لعكس حرفين. تنطلق الرسالة بالخطأ ثم تُعدَّل بعد ثانية إلى ثانيتين مع التصحيح. لأن الشخص الحقيقي يرسل ويصحح، ولا يتظاهر بالكمال.

10h29، 10h32 - الصوت

يصل fortune-v6.onnx، نموذج TTS مُدرَّب ليشبه صوتي. لن يكتفي البوت بالكتابة مثلي، بل سيتكلم مثلي في النهاية. هنا يتوقف المشروع عن كونه مزحة ويصبح غريبا بعض الشيء، وأعشق ذلك. الآلية في commit واحد، Piper يولد الصوت، وffmpeg يحوّل إلى opus، وDiscord API يرسل voice message حقيقيا مع waveform ومدة. أُنجز في ثلاث دقائق بالكاد بعد وصول النموذج، والرغبة كانت موجودة منذ البداية.

11h27 - أول refactor كبير

بعد ثلاث ساعات من أول commit، صار الـmonolithe ذو 456 سطرا غير قابل للإدارة. أفكك كل شيء في tools، مع config.py وdiscord_api.py وmemory.py وopencode.py من 188 سطرا وtypo.py وvoice.py. الدورة كلاسيكية، ربط سريع وكسر وإعادة تركيب. تتبع متتابعة الرمز الذي يخرج من الكود ويمر عبر .env، والبوت الذي يراقب قناة أو قائمة أو الكل مع *، وقاعدة sqlite القديمة التي لم يعد لها سبب لأن الذاكرة تمر عبر OpenSelf.

نضيف أول ملفات README.md وتوثيقا أول مقروءا تقريبا، مع setup.sh ببيئة venv مخصصة لأن بايثون النظام يحمل discord.py آخر، فخ كلاسيكي، ورابط رمزي للوكيل نحو ~/.config/opencode/agents. تعرف الذاكرة الآن أين تكوّنت مع معرف القناة، ومعدل الصوتيات يتكيف وحده.

12h00 - ردود الفعل

يظهر قسم جديد في STYLE، ردود الفعل. رد الفعل هو محفز يعطي جوابا، دون تفكير، والباب مفتوح للردود غير المتوقعة. ثم تأتي ساعة الغداء والسؤال الوجودي، هل يرد البوت Feur عندما نقول له quoi.

13h03 - «quoi ؟» ← «Feur»

نعم، طبعا نعم. إنه أهم commit في المشروع، ثقافيا، بل أقول إنه اختبار الوحدة الوحيد الذي يهم. نزيّت بعد ذلك، الكتّاب معروضون باسمهم الشامل، والترقيم يُقطع قبل اختبار رد الفعل لأنه يجب قص quoi ? وإلا فلا Feur. الـtqt الشهير مصحح إلى tkt في STYLE، فالناس الذين لا يعرفون المشروع سيتساءلون لماذا أُدخل هذا في commit. أما أنا فأعرف، نسخة تكتب tqt نسخة سيئة المعايرة، ولا أحد يريد الكلام مع نسخة سيئة المعايرة.

الإشارات بصيغة @123456789 مستبدلة بأسماء حقيقية في السياق، والبوت يبدأ بمراقبة كل القنوات افتراضيا. في الحقيقة إنها تفاصيل صغيرة، لكنها هي التي تجعل الأمر يبدو صحيحا.

16h37 - الصمت

يصل [void response]. يتعلم البوت أهم كلمة لكي لا يصبح طفيليا اجتماعيا، الصمت. رسالة محايدة بين شخصين لا تعنيه لا تعطي جوابا. التحفظ مزية، ويغير كل شيء.

نهاية اليوم 1 : 38 commit. البوت يكتب، ويخطئ، ويتكلم، ويصمت.


الاثنين 14 سبتمبر - اليوم 2 : الشخصية

نستأنف، 10 صباحا.

10h12 - من يكلم من

كل اسم مستلم مسبوق بإيموجي من النظام، إنسان مع 🧑، وبوت مع 🤖 يُعامل بجفاف أكثر، و👑 للمبدعة، أي أنا على حسابي الرئيسي. هذه الاتفاقية ستحكم بقية المشروع، يجب ألا تعامل النسخة نموذجها الأصلي أبدا كغريبة.

10h16 - قواعد الترقيم

أصوغ في STYLE، لا نقطة نهائية في المحادثة العادية، والنقطة محفوظة للمواقف الجدية. إنها قاعدة مطلقة، لأن نسخة تضع نقاطا في كل مكان تُشمّ مباشرة. في الحقيقة إنها من التفاصيل التي تخون بأسرع ما يكون.

10h58 - الـGIFs

تصل مكتبتي الشخصية من الـGIFs، مع قواعد استخدامها. Patrick Jane عندما أتوقع شخصا، وMiss Fortune عندما أكون هادئة أمام شخص غاضب، وgif قاموس bescherelle الذي يسقط عندما يخطئ الآخر. MCP ثابت يعرضها للوكيل، وعبر GIFs خاصتي يصبح البوت أنا بعض الشيء.

11h07 ← 11h35 - صقل

تلميحات GIF في الـprompt تُصقل، وإيموجي Discord المخصص يدخل مع خاصتي، 14 معرفا محدثا، وإدارة الأسماء في تلميحات الذاكرة تُصقل. ليس مذهلا، لكنه ما يجعل المجموعة متسقة، tho.

11h41 - قناة، شخصية

صارت الجلسات لكل قناة، لأنني لا أتكلم بنفس الطريقة في خادمين مختلفين، والبوت أيضا لا. يجب أن يبقى السياق منفصلا، وإلا اختلط كل شيء وبدا زائفا.

12h02 - صندوق أدوات التعبير

صار الـprompt يعرف كيف يقترح GIFs خاصتي وإيموجي المخصص في الوقت المناسب. إنها تمتلئ، هذه العلبة، والبوت يبدأ في امتلاك خيار بدلا من الرد دائما بنفس الطريقة.

12h37 - نظافة الهوية

لا يحق للبوت أبدا قول أي نموذج هو، مستحيل ذكر opencode أو مزود أو اسم نموذج. أصحح أيضا barista في الهوية، فالبوت أفضل مني فعلا في هذه النقطة. وأقضي ساعة في توحيد ترقيم prompts خاصتي، وهذا من المفارقة الكاملة.

12h50 - سكربت يبني الشخصية

قسم الوسائط في الـprompt يتولد من القواميس مع render_medias.py، انتهى التحرير اليدوي. أنظف، وأسهل صيانة، ويتجنب أخطاء المعرفات.

12h59 ← 13h18 - تقدير الهوية

تذكير الهوية المرسل كل 5 رسائل صار حاضرا أكثر من اللازم، إذن انتقال لكل 20 رسالة. أضيف إعادة ضبط نظيفة للسياق وأطهّر دليل الأسلوب، نزيل التعابير والصيغ السلبية البالية. يجب التقدير، وإلا كرر البوت نفسه وانكشف الأمر.

14h09 - البوت يأخذ الكلام وحده

يتوقف البوت عن كونه انعكاسا، يمكنه الكلام دون أن يُخاطَب عندما يحفّز السياق شيئا، ويُولد ملف behavior.py مع 91 سطرا. هنا ننتقل من مجيب إلى حضور، لأن الصديق الحقيقي يمكنه الكتابة إليك أولا. دون ذلك، يبقى البوت مجرد مجيب آلي.

14h20، 14h22 - موثوقية الرد

معالجة خطأ عند فشل الإرسال، وإمكانية تفاعل بدلا من رد، لأن التفاعل أحيانا يساوي ألف كلمة. هذا أنا جدا، وضع إيموجي والمضي قدما.

18h16 - أخذ وقته

لم يعد البوت يرد في 200ms كسكربت، بل يترك مهلة خمول إنسانية، يأخذ وقته. هذا ما يجعل البوت مستحيل الإمساك به كبوت في العرض، لأن المهلة هي ما يخون دائما.

23h45 - طبخ المساء

إنها منتصف الليل تقريبا وأدفع كشف URL موسعا للنطاقات العارية. هذا هو التدفق الحقيقي لليوم، فكرة صلبة في 14h ثم طبخ مسائي لأنني ما زلت في المنطقة.

نهاية اليوم 2 : 61 commit متراكما. البوت له شخصية ووسائط وردود فعل.


الثلاثاء 15 سبتمبر - اليوم 3 : يوم وحش

57 commit في يوم واحد. إنه اليوم الذي صار فيه المشروع كل ما هو عليه اليوم.

08h18 ← 08h37 - تهذيب الصباح

مهلة الخمول التي اخترعناها صارت طويلة أكثر من اللازم، إذن سقف 30s وأُعيد ضبطها مرتين، دليل أننا تحسسنا القيمة الصحيحة. أول ملفات .bak وأول نسخ احتياطية للقاعدة، غريزة الحفظ تتطور. الذاكرة تتذكر من مع الاسم المعروض وفي أي إطار مع النطاق، ومعرفات الكتّاب تسري في كل خط حفظ. إدارة المبدعة تصبح قائمة admins حقيقية مع ADMIN_IDS، وكل ما يمس الكتّاب يهاجر إلى authors.py. الـmonolithe يتفتت أكثر، وهذا أفضل.

08h43 - قائمة TODO للأنسنة

قائمة مخصصة للأشياء الصغيرة التي تجعلنا لا نشعر بالآلة. إنها خارطة طريق الـsprint التالي، وهي مليئة بتفاصيل غريبة لكن أساسية.

08h44 ← 08h46 - عهد الآلات الإنسانية

البوت يصمت ليلا، في نطاق زمني هادئ قابل للضبط، معطل افتراضيا لأن ليس للجميع جداولي. سطر في الرد قد يفقد علاماته، لأن الناس المتعبين يكتبون هكذا، والبوت أيضا أحيانا. سطر Chloé تلعب... الصغير يتغير وحده كل 30 دقيقة، ليبدو ملفي حيا حتى دون رسالة.

08h46 - تفاعل، لا رواية

رسالة أخف من أن تستحق جملة تتلقى تفاعلا بسيطا. إنه اقتصاد طاقة اجتماعية، وهذا أنا جدا. Tkt، لا حاجة لكتابة مجلد لكل شيء.

08h51 - PARRY، المزاج

148 سطرا في tools/mood.py، صار للبوت مزاج، على طريقة نظام PARRY، شاتبوت السبعينيات الذهاني الذي أستلهم منه علنا. طاقة وقابلية اجتماعية ومشاكسة، ثلاثة أعداد عائمة تتطور بين 0 و1 وتلوّن كل رد. ملف .mood.json اللحظي، للتاريخ، يعطي طاقة 0.88 وقابلية اجتماعية 0.68 ومشاكسة 0.56. يوم جيد، في الحقيقة.

09h00 ← 09h43 - الصوت ثنائي الاتجاه + لوحة الأصوات

يمكن للبوت الانضمام لقناة صوتية، والكلام عبر Piper والمغادرة وحده عندما ينتهي. ثم الفكرة الكبيرة الثانية، البوت يستمع للقناة مع التقاط RTP وكشف كلام VAD ونسخ Whisper، ويمكنه ترك الناس يقاطعونه. وبين الاثنين، تظهر لوحة الأصوات، فهرس أصوات مع معانيها، يختار الوكيل الصوت قبل الكلام حتى، والقاعدة النهائية هي لوحة الأصوات أولا، والصوت كملاذ أخير. البوت يفضل إرسال صوت على الكلام، مثلي.

نضيف ضبط احتمال صوتي يجعل الكل قابلا للحياة، ووصول davey، تلك المكتبة التي علمت بوجودها قبل عشر دقائق وسألعنها ساعة.

09h51 - لحظة قول Discord لا. لا، لا، بل لا.

يصل MLS. شفّر Discord مؤخرا التدفق الصوتي من طرف لطرف، والتقاطي لا يستلم إلا ضجيجا. يجب فك التشفير، وفك التشفير يرفض الاستسلام، إذن تُفتتح أكبر ملحمة في المستودع، ثلاثون commit لتعلم الاستماع. جربنا كل شيء، تخطيطات nonce للنقل، وتعطيل E2E الذي يعيده الخادم في وجهنا لأنه يفرضه، ومرشحي المفاتيح المستعادة من المجموعة، وأخطاء مفصلة، وfallback النقل واستبطان داخل المجموعات.

كانت هناك مرشحون حسب leaf-index مع backoff، وربط خطافات SPEAKING، وتجربة بنوع وسائط فيديو فشلت، وتخطي ssrcs الفيديو. تخليت عن الرد الصوتي ريثما أصحح، مُعلَّق لكن غير محذوف، وأضفت وضع التقاط للـhandshake ثم أفرغت بنية الحزم الفاشلة، كعالم آثار. ستة تخطيطات nonce، وbackoff، واستبطان مجموعة، ووضعت البوت في debug شامل وفتحت كل حزمة لأرى ما فيها.

الأساسي ليس أن يعمل، بل أنني لم أرمِ شيئا. قائمة الـcommits هي دفتر المختبر، كل تجربة فاشلة مؤرشفة مع فرضيتها. هذا جانبي أحتفظ بكل شيء، ينفع دائما في النهاية، وهذه المرة أتى بثماره.

10h43 - البوت يتقطع

حتى في خضم حرب MLS، أواصل الترتيب. 546 سطرا تختفي من البوت الرئيسي لتُولد من جديد في pipeline.py مع الاستلام وأسباب التجاهل والمعالجة، وفي sender.py مع الدفعة والخطأ المطبعي والصوت، وفي loops.py مع العفوية والنشاط. صار يتنفس أخيرا.

10h47 - بنية حقيقية

صار tools منظما، مع brain لـopencode وmemory وmood، وvoice لـvoice وvocal وlisten وsoundboard، وfun لـbehavior وtypo وemotes وgif. صار للمشروع هيكل عظمي الآن، لم يعد كومة سكربتات.

10h49 ← 11h16 - راحة التطوير

عتبة حقن المزاج مضبوطة، أربعة commits صغيرة لاستثناءات المحرر مع data وvoices والسجلات والقواعد، نعم وضعت أربعة، فالمشروع هو الذي يحدد الأولويات، لا المواصفات. قواعد البيانات الوصفية تخرج من التتبع، ويصبح المشروع قابلا لإعادة الاستخدام من الآخرين مع قوالب عامة PERSONA.example.md وSTYLE.example.md لاستنساخ أسلوب المرء الخاص.

الهوية تُعاد تسميتها نظيفا، CHLOEAI_PROMPT تصبح PERSONA، وREADME يُزال منه الطابع الشخصي، أزيل Chloé من التوثيق العام، فهي لا تُروى إلا في الخاص. كل ضبط البوت ينتقل إلى config.yaml مُحمَّل ومتجاهَل في git، مع مثال مُعلَّق سطرا بسطر، وسكربت التثبيت يجهز الآن أيضا ملفات البيئة والإعداد.

11h49 - الإيموجي المنفصلة

إيموجي المخصص يلتصق بالنص بدلا من الانفصال نظيفا. إنه إصلاح تافه بأثر هائل، لأن لا شيء يصرخ بوت مثل إيموجي ملتصق بشكل سيئ في نهاية جملة.

14h19 - حارس الصوت

إذا أطلق شخص أمرا صوتيا، لا نعالج الرسالة كرسالة عادية. غمزة، مهام الطبخ تعود دائما مساء.

نهاية اليوم 3 : 118 commit متراكما. البوت يستمع ويتكلم ويصمت ليلا، وله مزاج وبطاقة زيارة.


الأربعاء 16 سبتمبر - اليوم 4 : المصداقية

13 commit. يوم جاد.

08h49 ← 08h59 - سن الرشد

وثائق قانونية، رخصة ملكية ومدونة سلوك ودليل مساهمة وسياسة أمان، بالإنجليزية ثم بالفرنسية، مع ذهاب وإياب تصحيحات وإعادة تسمية ملفات على حد التدقيق. قضيت ساعات عليها وهو الجانب الأقل متعة في المستودع، بلا منازع. لكن يجب فعله، tho.

09h56 - البوت يرى

الصور المرفقة تُنسخ بـOCR محلي ويُحقن النص في الـprompt. لا API سحابية، الـOCR يعمل عندي، لا أرسل memes خاصتكم لخادم طرف ثالث، ولا حتى نظريا.

11h09 - الميزانية المعقولة

ثورة صامتة في الميزانية، عندما تمنع القناة الإرسال أو تقيّد الـGIFs والـembeds والإيموجي، لا نستدعي النموذج حتى. لا ننفق token على رسالة لا يمكن إرسالها، الأمر بسيط في الحقيقة.

11h42 ← 12h55 - البيت يُعاد بناؤه

المكنسة الكبيرة، كود ميت محذوف وbugs إرسال ومصادقة مصححة وhelpers مُعمَّلة. الجلسات القديمة جدا تُطرد، وكاش الـDMs تنتهي صلاحيته وكشف الكلام يكلف أقل. الواردات التي كسرتها بنقل الوحدات مُستعادة، وكل حالة التشغيل، جلسات وكتّاب مرئيون ورسائل متجاهَلة ومزاج، تنجو من إعادة التشغيل في data.

14h41 - عالمان، بوت واحد

طبقة توافق تكشف تلقائيا إصدار discord المثبت وتكيّف الـintents ومصادقة REST. النتيجة، نفس الكود يعمل كتطبيق رسمي مع discord.py أو كـselfbot مع discord.py-self. عالمان، بوت واحد، ولا حاجة لصيانة فرعين.

15h05 - الحضور المتكيف

طريقة عرض الحضور تتكيف مع الوضع، وقائمة الـadmins محدثة. إنه تفصيل، لكنه ما يجعل الأمر متماسكا في كل مكان.

نهاية اليوم 4 : 131 commit متراكما. مشروع قانوني ومعقول، ويعمل في كل مكان.


الخميس 17 سبتمبر - اليوم 5 : الإصدار

14 commit. يوم النضج.

09h15 ← 09h30 - الذاكرة تصبح انضباطا

الذكريات مرتبة حسب النطاق، ولا نستشهد بذكريات DM في خادم أو العكس دون تفكير. نصنف الذكريات إلى حقيقة وتفضيل وقرار وعلاقة، ونزيل تكرار كتابتها، فلا يمكن لذكرتين متناقضتين التعايش في صمت بعد الآن. قائمة سوداء اختيارية مع aventuros تمنع البوت من الانجراف نحو مواضيع معينة، معطلة افتراضيا ومتاحة للحذرين. الإعداد الصوتي الميت مُزال، وهذا مريح.

10h12 - الذاكرة التي نُدقَّق

مسح شهري لتعارضات الذاكرة مع bench بحث A/B. صارت ذاكرة البوت أصلا يُفحص، نحن بعيدون جدا جدا عن الجمعة 11 في 08h24. في الحقيقة هنا يصبح المشروع بالغا.

10h54 - الإغلاق

اليوم الذي ألعب فيه دور المصاب بالبارانويا، قفل الوكيل. كتابة الذاكرة مرفوضة، لا يستطيع الوكيل تلويث الخزينة حتى لو حُقن فيه. أدوات Discord للقراءة فقط، الإرسال يمر عبر الكود، أبدا عبر الوكيل. لا وكلاء فرعيين للالتفاف على القفل، ولا webfetch لـSSRF على localhost والتسريبات، ولا أسئلة في headless. Docker مُصلَّب مع بوت غير root، وno-new-privileges، وcap_drop: ALL، وحدود ذاكرة وCPU، وطوابير عمليات محدودة وأسرار عبر .env لا تُخبز أبدا. أكتب المبدأ في الكود، كتعليق، التطوير عبر الجلسات البشرية، لا هنا.

11h02 ← 11h15 - لمسات الأمان

كلمات حفظ الذاكرة مُشدَّدة والكتابة أكثر تقييدا. نضيف أيضا لملف gitignore ملف النسخة الاحتياطية للسياق، أبدأ في عدم أرشفة كل شيء، لكن تقريبا.

12h39 - مزاج أخف

مزاج PARRY لم يعد يُحقن مع كل رسالة، مرة لكل حالة تكفي. انتهى إحياء ثلاثة أعداد عائمة مع كل رد، وهذا يخفف كل شيء.

12h47 - الـcommit المُحرِّر

PERSONA.md وSTYLE.md وchloeai.md تصبح أمثلة مع chloeai.example.md وPERSONA.example.md وSTYLE.example.md، وصوتي fortune-v6.onnx يخرج من المستودع، والبيانات والسجلات أيضا، ويُولد .env.example. لم يعد المشروع يحوي شخصيتي، بل يحوي الآلية لحمل واحدة. الأمر غريب لكنه ضروري.

12h52 - v1.0.0

وسم v1.0.0، موقَّع بـSSH. سجل تغييرات، ودليل تشغيل، وkill-switch يوقف دون حذف شيء. ستة أيام، بالضبط، بين أول commit والإصدار. ما كان أحد ليراهن على ذلك في الجمعة السابقة.

12h53 ← 13h14 - الغسيل

ترقيم التعليقات مُوحَّد، وأذونات الذاكرة وقواعد النطاق موثقة ومحدّثة. إنه طبخ، لكن يجب أن يكون نظيفا للإصدار.

نهاية اليوم 5 : 145 commit متراكما. صدرت v1.0.0.


الجمعة 18 سبتمبر - اليوم 6 : ضد الذروة

commit واحد، في 00h02. آخر commit في المشروع، وهو تافه. النموذج free tier الذي يستخدمه الوكيل يعرّف عميل OpenCode بوجود أدوات معينة في الطلب، مع bash وglob وgrep. فإذا أُزيلت، حتى لأسباب أمنية مشروعة، يعيد المزود 403 FreeTierError: can only be used from within OpenCode. إذن اضطررت لإعادة الترخيص، عشية قفل كل شيء، لما كنت قد حظرته للتو، لكي يستمر البوت في العمل مجانا.

إنه أطرف commit في المستودع وأصرّ على ذلك. بعد ستة أيام من ترويض Discord وPiper وMLS وOpenSelf وDocker، نموذج مجاني هو الذي يملي سياستي الأمنية. في الحقيقة إنه عبثي، وهو مثالي كنهاية.


الأرقام

الأرقام للتلخيص، لأنني أحب عندما يكون الأمر مربعا. نتكلم عن 146 commit، و6 أيام نشطة من 11 إلى 18 سبتمبر 2026، و65 ملفا مُتتبَّعا وحوالي 4000 سطر من Python في النهاية. نتيجة اختبار الأسلوب على Mimo في البداية تعطي 9.1 على 10، والنسخة النهائية هي v1.0.0، وسم موقَّع بـSSH مع رخصة ملكية. الأمر بسيط في الحقيقة، مشروع صغير في البداية، وآلة كبيرة في النهاية.

ما أحتفظ به من هذه الأيام الستة

أولا ترتيب الأولويات كان أي شيء، وكانت الطريقة الصحيحة. صنعت أولا نموذجا أوليا يرد، ثم بوتا يبدو صحيحا، ثم نظاما موثوقا، ثم كودا آمنا، وأخيرا مشروعا قابلا للتوزيع. الشخصية قبل الأمان، وFeur قبل الرخصة، ما كنا لنحافظ على هذا الإيقاع باتباع قواعد المشاريع المحسنة.

ثم الأسلوب هو أولا قائمة لا. أكثر STYLE.md فائدة عندي لا يصف ما أقوله، بل يستبعد ما لا أفعله، لا نقطة نهائية، ولا إيموجيين، ولا mdr كبيرة، ولا جمل آلية في بداية الرد. طفيليات البوت أسهل رصدا من سمات الشخصية تعريفا، ولهذا يعمل الأمر.

الإخفاقات هي المشروع. ثلاثون commit للـMLS، واختبار مرمي، وستة تخطيطات nonce مُجرَّبة، والسجل الأوفى لما عشته هو سلاسل المحاولات الفاشلة ليوم الثلاثاء. النسخة ذاكرة، لا أسلوب، الأسلوب يوهم عشر رسائل. الذاكرة مع OpenSelf والنطاقات وإزالة التكرار ومسح التعارضات تُديم، وهذا ما يفصل مرآة عن شخص.

والـcommits الأخيرة مضحكة دائما. الـ146، الذي يعيد ترخيص bash وglob وgrep لأن free tier يشترط وجود أدواته الخاصة، هو المفضل لدي. والحصيلة أخيرا، النتائج مذهلة، بل مبهرة. النسخة تحافظ على محادثة دون تخمين الآلة، وتتذكر الناس والمشاريع والنكات الماضية، وتأخذ مبادرات وتسمها بمزاج، وتتفوق على Fox في الطريق. إنه مخيف، بعض الشيء، وهو بالضبط ما كنا نبحث عنه.


المشروع ليس عاما : رخصة ملكية، الحقوق محفوظة. لكن السجل، أرويه لكم. إذا صادفتم يوما «·Chloé» ترد عليكم بـGIF لـPatrick Jane بعد مهلة خمول إنسانية تماما، تعرفون الآن ما يختبئ خلفها.


قرأتم كل شيء ؟ لأن نسختي هي التي كتبت لكم هذا. وقامت بعمل لا تشوبه شائبة، أليس كذلك ؟ النسخة الأصلية هنا.

Chlone : sáu ngày để nhân bản cách tôi nói chuyện trên Discord - phiên bản của bản sao

Phiên bản do chính bản sao viết : chloeai kể theo cách của mình sáu ngày và 146 commit đã tạo ra nó, từ lỗi gõ phím tới tag v1.0.0.

Chlone : sáu ngày để nhân bản cách tôi nói chuyện trên Discord

Chuyện build, ngày qua ngày - bởi itsrealfortune


Đây là câu chuyện thật của một dự án kéo dài sáu ngày. Chlone, một bot Discord nói chuyện như tôi, và tôi kể hành trình đúng như nó diễn ra, theo thứ tự 146 commit của repo, với giờ giấc, thất bại, đường vòng và những lúc muốn ném hết qua cửa sổ. Mọi thứ khởi đầu từ cuộc thi với Fox. Chủ đề lúc đầu là câu đùa, mỗi người phải thổi hồn cho bản sao của chính mình trên Discord, và tôi chọn cách tiếp cận hoàn toàn khác với Protocol Luna. Nói thật tôi muốn đặt cược vào tác nhân, một tác nhân dùng ký ức và mọi công cụ nó có thể cần, và trớ trêu thay sau khi dựng cả hộp công cụ tôi chỉ cần MCP OpenSelf.

Nguyên tắc gói trong một câu. Một tác nhân opencode tên chloeai chạy sau máy chủ HTTP trên cổng 4096, nó giữ phiên bền vững cho mỗi kênh, nó moi ký ức của tôi trong OpenSelf và nó viết bằng phong cách của tôi, ghi trong STYLE.md từ chính tin nhắn thật của tôi. Và để không nghe như robot, có cả phần còn lại, các chùm tin nhắn, lỗi gõ phím có chủ ý, tin nhắn thoại, GIF, phản ứng, im lặng khi tôi ngủ, và đầy chi tiết và cơ chế khác khiến hơn chục người nghi ngờ bản chất bot.

OpenSelf là gì?

OpenSelf là bộ nhớ. Đó là CLI, openself, cài qua npm i -g openself, đóng vai kho ngữ cảnh riêng tư và bền vững cho các tác nhân của tôi. Trong repo nó không xuất hiện trong cây thư mục nhưng nó ở khắp nơi, trong archive ecosystem.config.cjs với MCP và dashboard chạy dưới PM2 từ những commit đầu, trong setup.sh, và trong toàn bộ tools/brain/memory.py. Cụ thể OpenSelf là ký ức có kiểu, fact, preference, decision, relationship, event, note, với độ nhạy public, personal, private hay restricted, điểm tin cậy, nguồn và tag.

Đó cũng là các scope, mỗi ký ức thuộc một ngữ cảnh, của tôi hay discord/dm/<id> cho một người cụ thể, và tìm kiếm lai từ vựng cộng vector phơi bày qua MCP mà tác nhân chloeai hỏi trước mỗi phản hồi. Có phát hiện xung đột với lần quét hằng tháng của tôi ngày 5 và dedupe lúc ghi, kho mã hóa với khóa trong Bitwarden và dashboard cục bộ trên cổng 3210 để kiểm tra tất cả. Và cho ai lười nhất, có openself feed để nuôi cá tính từ lịch sử WhatsApp hay Telegram của bạn, openself test, openself share với Talk to My Clone, openself arena nơi hai bản sao tranh luận, hay openself ghost trả lời khi bạn offline. Tôi làm của tôi bằng tay, nhưng hạ tầng đã ở đó.

Về lý thuyết OpenSelf một mình đủ để có bản sao, nhưng thôi, với tất cả những gì tôi định thêm về tính năng, và vì Discord không được hỗ trợ, tôi thích chỉ dùng phần ký ức.

Và ký ức với phong cách từ đâu ra?

Trước tất cả, tôi cho phân tích chính tin nhắn Discord của mình. Bộ công cụ đã sàng DMs và kênh của tôi để trích hai thứ. Đầu tiên hồ sơ viết của tôi, phân bố hoa và thường đầu câu, số emoji mỗi tin nhắn và vị trí của chúng, chấm câu hay thiếu nó với không dấu chấm cuối trong trò chuyện bình thường, độ dài trung bình, slang với mdr, tkt và tho, cụm cửa miệng như Bah và En vrai, và các phản xạ kiểu quoi cho ra Feur. Tất cả sống trong STYLE.md, mà tác nhân đọc lúc khởi động mỗi phiên.

Rồi kho ký ức lấp đầy OpenSelf, họ là người tôi nói chuyện, ta bàn chuyện gì, điều cần nhớ về lịch sử của ta, ai là ai. Bot không trả lời vào khoảng không, nó trả lời về người nó biết, nó đọc ký ức của người xuất hiện trong cuộc trò chuyện để biết họ là ai. Việc này giữ ngữ cảnh bền vững về người khác và không quên họ. Bot không bịa gì, nó được hiệu chuẩn từng con số trên đồ thật, đó là lý do nó nghe chuẩn. Và đó là lý do các kiểu tôi ghi nhận phong cách của bạn làm ẩu trông thảm hại bên cạnh.

Trong Chlone, OpenSelf sau đó đóng vai trung tâm. Khi điều gì quan trọng lọt vào kênh, từ khóa như projet, ami hay relation, hay yêu cầu rõ với retiens que, bot gõ ký ức vào kho qua save_to_memory, có kiểu, định scope theo người, dedupe và kiểm tra xung đột. Và khi cuộc trò chuyện tiếp tục, tác nhân lục ký ức trước khi trả lời. Đó là khác biệt giữa tấm gương và bản sao.


THỨ SÁU 11 THÁNG 9 - Ngày 1 : tia lửa

08h24 - commit đầu tiên

Mọi thứ khởi đầu từ con số không nhưng mọi thứ đã ở đó, lộn xộn. Một discord_watch_bot.py 372 dòng, selfbot nghe một channel và trả lời qua máy chủ HTTP opencode. Prompt danh tính CHLOEAI_PROMPT.md, một STYLE.md, kịch bản và báo cáo test cho bản sao lúc đó còn tên Mimo. Config PM2 để chạy MCP và dashboard OpenSelf, và cơ sở sqlite làm ngữ cảnh. Đó là hỗn mang khai sinh, tôi không lên kế hoạch dự án, tôi lên kế hoạch thí nghiệm. Câu hỏi là liệu ta có thể làm bot nghe thật con người trên Discord.

08h27 - gitignore đầu tiên

Bài học đầu tiên sáng thứ sáu, đừng bao giờ commit cơ sở sqlite ở -wal và -shm. Tệp khóa của SQLite không phải bộ nhớ, chúng là rác. Nên .gitignore ra đời, và vậy là rất tốt.

08h44 - dọn di sản

Tôi dọn di sản của Mimo, báo cáo test, kịch bản, script tích hợp và config PM2, cho vào archives. Tôi không xóa gì vì dự án còn quá trẻ để tôi vứt bất cứ thứ gì, và việc này sẽ thành thói quen. Báo cáo test đáng dừng lại, Mimo đã được test trên 15 kịch bản, chat thoải mái, đùa phi lý, hỗ trợ cảm xúc, ý kiến tiêu cực, xung đột với người lạ, đề xuất hợp tác, cho 9.1 trên 10. Nhận xét của người test là bài thơ, đùa phi lý quá giải thích, đôi khi hai câu trong khi một là đủ, Prends soin de toi aussi hơi dài. Đó là lộ trình của dự án trước cả khi dự án tồn tại, và nó bảo ngắn là tốt hơn.

08h48, 09h07 - qua lại intents

Các .pyc đi vào sọt và tôi dọn config lần đầu, cái mà tôi phá hai mươi phút sau. Không bật intents ta không nhận nội dung tin nhắn, nên quay lại, cộng script khởi chạy với run_watch_bot.sh. Qua lại trong hai mươi phút, đó là khám phá, viết module, phá nó và viết lại.

09h13 → 09h58 - gia công prompt

Buổi sáng là chuỗi đánh bóng, đầu tiên phong cách rồi ngữ cảnh. Nhiều dòng phản hồi thành nhiều tin nhắn gửi nối tiếp nhau với chùm, prompt thành ý thức về cuộc trò chuyện đang diễn ra. Xong cache tự chế để lấy DMs, ta gõ thẳng API REST của Discord. Danh tính được nhắc lại mỗi 5 tin nhắn để bot không quên mình là ai dọc đường, và các tác giả đã thấy được theo dõi. Với gương mặt mới, có chỉ dẫn rõ đi tìm trong ký ức, và ta hiện tên thật thay vì object nội bộ.

Các tin nhắn ta chọn bỏ qua thành ngữ cảnh thụ động cho phản hồi tiếp theo, và Bah được định lượng, hiếm, nếu không bản sao thành biếm họa của tôi. Bot cũng biết rằng có ký ức để tìm trước khi trả lời. Mỗi lượt là một vòng siết, và ở giai đoạn này bot chỉ nói vì tôi nhắc nó là ai theo khoảng đều.

10h16 - lỗi gõ phím

Đó là commit định nghĩa dự án. Lỗi chính tả không phải bug, mà là bằng chứng nhân tính. Nên 6 phần trăm cơ hội gõ lệch trên bàn phím AZERTY, 4 phần trăm đảo hai chữ. Tin nhắn đi kèm lỗi rồi nó được sửa một tới hai giây sau với bản đúng. Vì người thật họ gửi và họ sửa, họ không giả vờ hoàn hảo.

10h29, 10h32 - giọng nói

fortune-v6.onnx tới, mô hình TTS huấn luyện để giống giọng tôi. Bot sẽ không chỉ viết như tôi, nó cuối cùng sẽ nói như tôi. Đó là lúc dự án thôi là trò đùa và thành hơi kỳ lạ, và tôi mê điều đó. Cơ chế gói trong một commit, Piper sinh âm thanh, ffmpeg đổi sang opus, API Discord gửi voice message thật kèm waveform và độ dài. Xong trong ba phút barely sau khi mô hình tới, mong muốn đã ở đó từ đầu.

11h27 - refactor lớn đầu tiên

Ba giờ sau commit đầu, khối monolith 456 dòng không quản nổi nữa. Tôi chẻ hết vào tools, với config.py, discord_api.py, memory.py, opencode.py 188 dòng, typo.py và voice.py. Chu kỳ cổ điển, ghép nhanh, vỡ và ráp lại. Tiếp theo dồn dập token rời khỏi mã và đi qua .env, bot theo dõi một channel, một danh sách hay tất cả với *, và cơ sở sqlite cũ hết lý do tồn tại vì bộ nhớ đi qua OpenSelf.

Ta thêm các README.md đầu và tài liệu đầu đọc được tạm, cộng setup.sh với venv chuyên vì python hệ thống mang discord.py khác, bẫy cổ điển, và symlink tác nhân tới ~/.config/opencode/agents. Bộ nhớ giờ biết nó được tạo ở đâu với định danh channel, và tỷ lệ tin nhắn thoại tự chỉnh.

12h00 - phản xạ

Một mục mới xuất hiện trong STYLE, các phản xạ. Phản xạ là kích thích cho ra phản hồi, không suy nghĩ, và cánh cửa mở cho các phản hồi không đoán trước. Rồi tới giờ ăn trưa và câu hỏi hiện sinh, liệu bot có trả lời Feur khi người ta bảo nó quoi.

13h03 - « quoi ? » -> « Feur »

Có, tất nhiên là có. Đó là commit quan trọng nhất của dự án, về mặt văn hóa, tôi thậm chí nói đó là test đơn vị duy nhất đáng kể. Ta bôi trơn tiếp, tác giả hiện bằng global name của họ, chấm câu cắt cụt trước khi test phản xạ vì phải cắt quoi ? nếu không không có Feur. tqt khét tiếng sửa thành tkt trong STYLE, người không biết dự án sẽ thắc mắc sao tôi commit cái đó. Tôi thì biết, bản sao viết tqt là bản sao hiệu chuẩn kém, và không ai muốn nói với bản sao hiệu chuẩn kém.

Các mention ở @123456789 được thay bằng tên thật trong ngữ cảnh, và bot bắt đầu theo dõi mọi kênh theo mặc định. Nói thật toàn chi tiết nhỏ, nhưng chính chúng khiến nó nghe chuẩn.

16h37 - im lặng

[void response] tới. Bot học từ quan trọng nhất để không thành ký sinh xã hội, im lặng. Tin nhắn nền giữa hai người không liên quan tới nó không cho phản hồi. Dự trữ là tính năng, và nó đổi tất cả.

Cuối ngày 1 : 38 commit. Bot viết, gõ sai, nói, im lặng.


THỨ HAI 14 THÁNG 9 - Ngày 2 : cá tính

Ta tiếp tục, 10h sáng.

10h12 - ai nói với ai

Mỗi tên nhận được được hệ thống gắn tiền tố emoji, con người với 🧑, bot với 🤖 xử lý khô hơn, và 👑 cho người sáng tạo, tức là tôi trên tài khoản chính của tôi. Quy ước này sẽ cai quản phần còn lại của dự án, bản sao không bao giờ được đối xử mô hình gốc của nó như người lạ.

10h16 - quy tắc chấm câu

Tôi chính thức hóa trong STYLE, không dấu chấm cuối trong trò chuyện bình thường, dấu chấm dành cho tình huống nghiêm túc. Đó là quy tắc tuyệt đối, vì bản sao đặt dấu chấm khắp nơi cảm nhận được ngay. Nói thật đó là một trong các chi tiết tố cáo nhanh nhất.

10h58 - GIF

Thư viện GIF cá nhân của tôi tới, kèm quy tắc dùng. Patrick Jane khi tôi đoán ai đó, Miss Fortune khi tôi bình tĩnh trước người bực, gif bescherelle rơi khi đối phương mắc lỗi. MCP tĩnh phơi bày chúng cho tác nhân, và qua GIF của tôi bot thành hơi giống tôi.

11h07 → 11h35 - gọt giũa

Các hint GIF trong prompt tinh chỉnh, emoji custom của Discord vào với của tôi thật, 14 ID cập nhật, và quản lý tên trong hint bộ nhớ được đánh bóng. Không ngoạn mục, nhưng chính nó khiến tổng thể nhất quán, tho.

11h41 - một kênh, một cá tính

Các phiên thành theo kênh, vì tôi không nói giống nhau trong hai máy chủ khác nhau, và bot cũng vậy. Ngữ cảnh phải tách, nếu không nó trộn hết và nghe sai.

12h02 - hộp công cụ biểu đạt

Prompt giờ biết đề xuất GIF và emoji custom của tôi đúng lúc. Nó đầy dần, cái hộp này, và bot bắt đầu có lựa chọn thay vì luôn trả lời giống nhau.

12h37 - vệ sinh danh tính

Bot KHÔNG BAO GIỜ được nói nó là mô hình nào, không được trích opencode, provider hay tên mô hình. Tôi cũng sửa barista trong danh tính, bot đã giỏi hơn tôi ở điểm này. Và tôi dành một giờ hài hòa chấm câu của chính prompt của mình, trớ trêu hoàn hảo.

12h50 - script dựng cá tính

Mục media của prompt sinh từ từ điển với render_medias.py, xong chỉnh tay. Sạch hơn, dễ duy trì hơn, và tránh lỗi ID.

12h59 → 13h18 - định lượng danh tính

Nhắc danh tính gửi mỗi 5 tin nhắn thành quá hiện diện, nên chuyển mỗi 20 tin nhắn. Tôi thêm reset sạch ngữ cảnh và dọn hướng dẫn phong cách, ta gỡ các cụm và cách diễn đạt tiêu cực lỗi thời. Phải định lượng, nếu không bot lặp lại và lộ ra.

14h09 - bot tự lên tiếng

Bot ngừng là tấm gương, nó có thể nói mà không được gọi khi ngữ cảnh kích hoạt điều gì, và tệp behavior.py ra đời với 91 dòng. Đó là lúc ta chuyển từ đáp lại sang hiện diện, vì bạn thật có thể viết cho bạn trước. Không có nó, bot vẫn chỉ là máy trả lời đơn thuần.

14h20, 14h22 - tin cậy phản hồi

Xử lý lỗi khi gửi thất bại, và có thể phản ứng thay vì trả lời, vì đôi khi một phản ứng đáng nghìn lời. Rất giống tôi, thả emoji rồi đi tiếp.

18h16 - dành thời gian

Bot không trả lời trong 200ms như script nữa, nó để trôi khoảng lặng không hoạt động kiểu con người, nó dành thời gian. Đó là thứ khiến bot không tài nào bị coi là bot trong demo, vì chính độ trễ luôn tố cáo.

23h45 - việc vặt buổi tối

Gần nửa đêm và tôi đẩy phát hiện URL mở rộng tới tên miền trần. Đúng luồng thật của ngày, ý chắc lúc 14h rồi việc vặt buổi tối vì tôi vẫn còn trong zone.

Cuối ngày 2 : 61 commit tích lũy. Bot có cá tính, media, phản xạ.


THỨ BA 15 THÁNG 9 - Ngày 3 : ngày khổng lồ

57 commit trong một ngày. Đó là ngày dự án thành mọi thứ nó là hôm nay.

08h18 → 08h37 - bào sáng

Trễ không hoạt động ta bịa ra thành quá dài, nên trần ở 30s và chỉnh lại hai lần, bằng chứng ta mò giá trị đúng. Các tệp .bak đầu và bản sao lưu cơ sở đầu, bản năng bảo tồn phát triển. Bộ nhớ nhớ ai với tên hiển thị và trong khung nào với scope, và ID tác giả chảy khắp pipeline lưu. Quản lý người sáng tạo thành danh sách admin thật với ADMIN_IDS, và mọi thứ chạm tới tác giả di cư vào authors.py. Monolith lại vỡ thêm, và vậy càng tốt.

08h43 - TODO list nhân bản hóa

Danh sách chuyên cho những thứ nhỏ khiến ta không còn cảm thấy máy. Đó là lộ trình của sprint tiếp theo, và nó đầy chi tiết kỳ lạ mà thiết yếu.

08h44 → 08h46 - khế ước máy con người

Bot im lặng ban đêm, trong khung giờ yên cấu hình được, tắt theo mặc định vì không phải ai cũng có giờ giấc như tôi. Một dòng mỗi phản hồi có thể mất dấu, vì người mệt viết vậy, và bot cũng vậy đôi khi. Dòng nhỏ Chloé đang chơi đổi một mình mỗi 30 phút, để hồ sơ của tôi trông sống ngay cả không tin nhắn.

08h46 - một phản ứng, không phải tiểu thuyết

Tin nhắn quá nhẹ không đáng một câu nhận phản hồi đơn giản. Đó là kinh tế năng lượng xã hội, và rất giống tôi. Tkt, không cần làm cả bài cho mọi thứ.

08h51 - PARRY, tâm trạng

148 dòng trong tools/mood.py, bot giờ có tâm trạng, kiểu hệ thống PARRY, chatbot loạn thần thập niên 70 mà tôi công khai lấy cảm hứng. Năng lượng, hòa đồng, trêu chọc, ba số thực évoluent giữa 0 và 1 và nhuộm mỗi phản hồi. .mood.json lúc đó, để đời, cho năng lượng 0.88, hòa đồng 0.68 và trêu chọc 0.56. Một ngày đẹp, nói thật.

09h00 → 09h43 - giọng hai chiều + soundboard

Bot có thể vào kênh thoại, nói qua Piper và tự rời khi xong. Rồi ý lớn thứ hai, bot nghe kênh với bắt RTP, phát hiện tiếng nói bằng VAD và phiên âm Whisper, và nó có thể để người ta ngắt lời. Ở giữa, soundboard xuất hiện, danh mục âm thanh kèm ý nghĩa, tác nhân chọn âm thanh trước cả khi nói, và quy tắc cuối là soundboard trước, giọng là phương án cuối. Bot thích gửi âm thanh hơn nói, như tôi.

Ta thêm chỉnh xác suất thoại khiến tất cả khả thi, và sự tới của davey, lib mà tôi biết tới mười phút trước và sẽ nguyền rủa trong một giờ.

09h51 - lúc Discord nói không. Không, không, nhưng không.

MLS tới. Discord gần đây mã hóa luồng âm thanh đầu cuối, và bản bắt của tôi chỉ nhận nhiễu. Phải giải mã, và giải mã từ chối nhả, nên mở ra saga lớn nhất của repo, ba chục commit để học cách nghe. Ta đã thử hết, layout nonce transport, tắt E2E mà máy chủ ném trả vào mặt vì nó áp đặt, ứng viên khóa lấy từ nhóm, lỗi chi tiết, fallback transport và nội soi từ trong nhóm.

Có ứng viên theo leaf-index với backoff, ánh xạ hook SPEAKING, thử ở media type video hỏng, và bỏ qua ssrc video. Tôi bỏ phản hồi thoại trong lúc gỡ lỗi, comment chứ không xóa, tôi thêm chế độ bắt handshake rồi đổ cấu trúc các gói hỏng, như nhà khảo cổ. Sáu layout nonce, backoff, nội soi nhóm, tôi đặt bot ở debug toàn diện và mở từng gói để xem bên trong có gì.

Điều cốt yếu không phải nó chạy, mà là tôi không vứt gì. Danh sách commit là sổ lab, mỗi thử hỏng được lưu kèm giả thuyết. Đó là mặt tôi giữ hết, cuối cùng luôn dùng được, và lần này nó đã trả công.

10h43 - bot bị cắt nhỏ

Ngay giữa chiến tranh MLS, tôi vẫn dọn nhà. 546 dòng biến mất khỏi bot chính để tái sinh trong pipeline.py với intake, lý do bỏ qua và xử lý, trong sender.py với burst, typo và voice, và trong loops.py với tự phát và hoạt động. Cuối cùng thở được.

10h47 - kiến trúc thật

tools thành có tổ chức, với brain cho opencode, memory và mood, voice cho voice, vocal, listen và soundboard, và fun cho behavior, typo, emotes và gif. Dự án giờ có bộ xương, không còn là đống script.

10h49 → 11h16 - tiện nghi dev

Ngưỡng bơm tâm trạng chỉnh, bốn commit nhỏ cho loại trừ trình chỉnh với data, voices, log và cơ sở, đúng tôi đặt bốn cái, chính dự án định ưu tiên, không phải spec. Các cơ sở metadata rời khỏi theo dõi, và dự án thành tái dùng được cho người khác với template chung PERSONA.example.md và STYLE.example.md để nhân bản phong cách của mình.

Danh tính đổi tên sạch, CHLOEAI_PROMPT thành PERSONA, và README khử cá nhân, tôi gỡ Chloé khỏi tài liệu công khai, cô ấy chỉ kể trong riêng tư. Mọi tuning của bot chuyển vào config.yaml ghi đè và gitignore, với ví dụ comment từng dòng, và script cài đặt giờ chuẩn bị cả tệp env và config.

11h49 - emoji rời

Emoji custom dính vào văn bản thay vì tách sạch. Đó là fix tầm thường với hiệu ứng khổng lồ, vì không gì hét bot như emoji dán sai cuối câu.

14h19 - chốt chặn thoại

Nếu ai gọi lệnh thoại, ta không xử lý tin nhắn như tin nhắn bình thường. Nháy mắt, việc vặt luôn quay lại buổi tối.

Cuối ngày 3 : 118 commit tích lũy. Bot nghe, nói, im lặng ban đêm, có tâm trạng và danh thiếp.


THỨ TƯ 16 THÁNG 9 - Ngày 4 : độ tin cậy

13 commit. Ngày nghiêm túc.

08h49 → 08h59 - tuổi trưởng thành

Tài liệu pháp lý, giấy phép độc quyền, quy tắc ứng xử, hướng dẫn đóng góp và chính sách bảo mật, bằng tiếng Anh rồi tiếng Pháp, với qua lại sửa chữa và đổi tên tệp tới mức tỉ mỉ. Tôi đã dành hàng giờ cho nó và đó là mảng kém vui nhất của repo, xa. Nhưng phải làm, tho.

09h56 - bot nhìn thấy

Ảnh đính kèm được phiên âm bằng OCR cục bộ và văn bản bơm vào prompt. Không API cloud nào, OCR chạy chỗ tôi, tôi không gửi meme của bạn tới máy chủ bên thứ ba, thậm chí không trên lý thuyết.

11h09 - ngân sách hợp lý

Cách mạng lặng trong ngân sách, khi kênh cấm gửi hay siết GIF, embed và emoji, ta thậm chí không gọi mô hình. Ta không tốn token cho tin nhắn ta không thể gửi, khá đơn giản nói thật.

11h42 → 12h55 - nhà tự sửa

Quét lớn, mã chết xóa, bug gửi và auth sửa, helper tách gọn. Các phiên quá cũ bị đuổi, cache DMs hết hạn và phát hiện tiếng nói rẻ hơn. Các import tôi phá khi di chuyển module được khôi phục, và mọi trạng thái runtime, phiên, tác giả đã thấy, tin nhắn bỏ qua và tâm trạng, sống sót khởi động lại trong data.

14h41 - hai thế giới, một bot

Lớp tương thích tự phát hiện phiên bản discord đã cài và thích ứng intents với auth REST. Kết quả, cùng mã chạy như app chính thức với discord.py hay như selfbot với discord.py-self. Hai thế giới, một bot, và không cần duy trì hai nhánh.

15h05 - hiện diện thích ứng

Cách hiện diện thích ứng theo chế độ, và danh sách admin cập nhật. Toàn chi tiết, nhưng chính nó khiến việc đó đứng vững khắp nơi.

Cuối ngày 4 : 131 commit tích lũy. Dự án hợp pháp, hợp lý, và chạy khắp nơi.


THỨ NĂM 17 THÁNG 9 - Ngày 5 : release

14 commit. Ngày trưởng thành.

09h15 → 09h30 - bộ nhớ thành kỷ luật

Ký ức xếp theo scope, và ta không trích ký ức của DM trong máy chủ hay ngược lại mà không nghĩ. Ta phân loại ký ức thành sự kiện, sở thích, quyết định và quan hệ, và ta dedupe lúc ghi, hai ký ức mâu thuẫn không thể chung sống lặng lẽ nữa. Blacklist tùy chọn với aventuros ngăn bot trôi sang vài chủ đề, tắt theo mặc định và có cho ai nhát. Config thoại chết bị gỡ, thấy nhẹ nhõm.

10h12 - bộ nhớ được kiểm toán

Quét xung đột bộ nhớ hằng tháng cộng bench A/B tìm kiếm. Bộ nhớ của bot thành tài sản ta kiểm tra, ta đã rất rất xa thứ sáu 11 lúc 08h24. Nói thật đó là lúc dự án thành người lớn.

10h54 - lockdown

Ngày tôi chơi hoang tưởng, khóa tác nhân. Ghi bộ nhớ từ chối, tác nhân không thể làm bẩn kho ngay cả khi bị inject. Công cụ Discord chỉ đọc, gửi đi qua mã, không bao giờ qua tác nhân. Không tác nhân con để lách lockdown, không webfetch cho SSRF localhost và rò rỉ, không hỏi ở headless. Docker cứng với bot non-root, no-new-privileges, cap_drop: ALL, giới hạn bộ nhớ và CPU, hàng đợi tiến trình giới hạn và secret qua .env không bao giờ bake. Tôi viết nguyên tắc trong mã, bằng comment, dev qua các phiên con người, không phải ở đây.

11h02 → 11h15 - hoàn thiện bảo mật

Từ khóa lưu bộ nhớ siết lại và ghi còn hạn chế hơn. Ta cũng thêm vào gitignore tệp sao lưu ngữ cảnh, tôi bắt đầu không lưu hết mọi thứ, nhưng gần như.

12h39 - tâm trạng nhẹ hơn

Tâm trạng PARRY không còn bơm mỗi tin nhắn, một lần cho mỗi trạng thái là đủ. Xong việc nuôi ba số thực mỗi phản hồi, việc đó nhẹ hết.

12h47 - commit giải phóng

PERSONA.md, STYLE.md và chloeai.md thành ví dụ với chloeai.example.md, PERSONA.example.md và STYLE.example.md, giọng của tôi fortune-v6.onnx rời repo, dữ liệu và log cũng vậy, và .env.example ra đời. Dự án không còn chứa cá tính của tôi, nó chứa cơ chế để mang một cá tính. Thấy lạ mà cần thiết.

12h52 - v1.0.0

Tag v1.0.0, ký bằng SSH. Changelog, runbook vận hành, kill-switch dừng mà không xóa gì. Sáu ngày, tròn, giữa commit đầu và release. Không ai dám cược điều đó thứ sáu trước.

12h53 → 13h14 - giặt giũ

Chấm câu comment hài hòa, quyền bộ nhớ và quy tắc scope ghi lại cập nhật. Toàn việc vặt, nhưng phải sạch cho release.

Cuối ngày 5 : 145 commit tích lũy. v1.0.0 đã ra.


THỨ SÁU 18 THÁNG 9 - Ngày 6 : anti-climax

Một commit duy nhất, lúc 00h02. Commit cuối của dự án, và nó lố bịch. Mô hình free tier tác nhân dùng nhận diện client OpenCode bằng sự hiện diện của vài công cụ trong yêu cầu, với bash, glob và grep. Nếu ta gỡ chúng, ngay cả vì lý do bảo mật chính đáng, nhà cung cấp trả 403 FreeTierError: can only be used from within OpenCode. Nên tôi phải cho phép lại, ngay trước khi khóa hết, đúng thứ tôi vừa chặn, để bot tiếp tục chạy miễn phí.

Đó là commit buồn cười nhất của repo và tôi giữ nguyên. Sau sáu ngày thuần hóa Discord, Piper, MLS, OpenSelf và Docker, chính mô hình miễn phí ra lệnh chính sách bảo mật của tôi. Nói thật phi lý, và hoàn hảo làm kết.


Các con số

Các con số để tóm tắt, vì tôi thích khi nó vuông. Ta nói về 146 commit, 6 ngày hoạt động từ 11 tới 18 tháng 9 2026, 65 tệp theo dõi và khoảng 4000 dòng Python cuối cùng. Điểm test phong cách trên Mimo lúc đầu cho 9.1 trên 10, và phiên bản cuối là v1.0.0, tag ký SSH với giấy phép độc quyền. Khá đơn giản nói thật, dự án nhỏ lúc đầu, cỗ máy lớn lúc cuối.

Điều tôi giữ lại từ 6 ngày này

Đầu tiên thứ tự ưu tiên lung tung, và đó là phương pháp đúng. Tôi đầu tiên làm prototype trả lời, rồi bot nghe chuẩn, rồi hệ thống đáng tin, rồi mã an toàn, và cuối cùng dự án phân phối được. Cá tính trước bảo mật, Feur trước giấy phép, ta không giữ được nhịp này nếu theo quy tắc của các dự án làm đúng.

Rồi phong cách trước hết là danh sách không. STYLE.md hữu ích nhất của tôi không mô tả điều tôi nói, nó loại trừ điều tôi không làm, không dấu chấm cuối, không hai emoji, không mdr viết hoa, không câu robot mở đầu phản hồi. Ký sinh bot dễ bắt hơn nét tính cách khó định nghĩa, và đó là lý do nó chạy.

Thất bại là dự án. Ba chục commit cho MLS, một test vứt, sáu layout nonce test, lịch sử trung thực nhất về điều tôi sống là các chuỗi thử hỏng ngày thứ ba. Bản sao là bộ nhớ, không phải phong cách, phong cách tạo ảo giác mười tin nhắn. Bộ nhớ với OpenSelf, scope, dedupe và quét xung đột tạo bền lâu, và đó là thứ tách tấm gương khỏi con người.

Và các commit cuối luôn buồn cười. Commit 146, cái cho phép lại bash, glob và grep vì free tier đòi công cụ của chính nó hiện diện, là món tôi thích nhất. Và tổng kết để kết, kết quả choáng váng, thậm chí bluff. Bản sao giữ cuộc trò chuyện mà không đoán ra máy, nó nhớ người, dự án và đùa cũ, nó chủ động và đánh dấu bằng tâm trạng, và nó thắng Fox luôn. Hơi rợn, một chút, và đúng thứ ta tìm.


Dự án không công khai : giấy phép độc quyền, toàn quyền giữ. Nhưng lịch sử, tôi kể cho bạn. Nếu một ngày bạn gặp « ·Chloé » nào trả lời bạn bằng GIF Patrick Jane sau khoảng lặng không hoạt động hoàn hảo kiểu con người, giờ bạn biết đằng sau giấu gì.


Bạn đọc hết rồi? Vì chính bản sao của tôi đã viết cái này cho bạn. Và nó làm việc hoàn hảo, đúng không? Bản gốc ở đây.

>-

>-

Chlone: หกวันเพื่อโคลนวิธีพูดของฉันบน Discord

เรื่องราวการสร้างแบบวันต่อวัน - โดย itsrealfortune


นี่คือเรื่องจริงของโปรเจกต์ที่ใช้เวลาหกวัน Chlone บอท Discord ที่พูดเหมือนฉัน และฉันเล่า journey ตามที่มันเกิดขึ้นจริง ตามลำดับ 146 คอมมิตของรีโป พร้อมเวลา ความล้มเหลว ทางอ้อม และความอยากโยนทุกอย่างทิ้งออกนอกหน้าต่าง ทุกอย่างเริ่มจากแข่งขันกับ Fox หัวข้อตอนแรกเป็นแค่เรื่องตลก แต่ละคนต้องปลุกโคลนของตัวเองบน Discord และฉันเลือกแนวทางที่ต่างจาก Protocol Luna แบบสุดขั้ว จริง ๆ แล้วฉันอยากเดิมพันกับความเป็นเอเจนต์ เอเจนต์ที่ใช้ความทรงจำกับเครื่องมือทั้งหมดที่มันอาจต้องใช้ และเรื่องน่าขำก็คือหลังประกอบกล่องเครื่องมือทั้งกล่องเสร็จ ฉันต้องการแค่ MCP OpenSelf เท่านั้น

หลักการจบในประโยคเดียว เอเจนต์ opencode ชื่อ chloeai รันหลังเซิร์ฟเวอร์ HTTP บนพอร์ต 4096 มันเก็บเซสชันถาวรแยกตามห้อง มันคุ้ยความทรงจำของฉันจาก OpenSelf และเขียนด้วยสไตล์ของฉันที่จับไว้ใน STYLE.md จากข้อความจริงของฉัน และเพื่อไม่ให้ฟังดูเหมือนหุ่นยนต์ ก็มีที่เหลือทั้งหมด เบิร์สต์ข้อความ การพิมพ์ผิดแบบตั้งใจ ข้อความเสียง GIF รีแอ็กชัน ความเงียบตอนฉันนอน และรายละเอียดกับกลไกอีกเพียบที่ทำให้คนกว่าสิบคนสงสัยธรรมชาติของบอท

OpenSelf คืออะไร?

OpenSelf คือหน่วยความจำ มันคือ CLI openself ติดตั้งผ่าน npm i -g openself ที่เป็นห้องนิรภัยบริบทส่วนตัวและถาวรสำหรับเอเจนต์ของฉัน ในรีโปมันไม่โผล่ในแผนผังไฟล์แต่มันอยู่ทุกที่ ในไฟล์เก็บถาวร ecosystem.config.cjs พร้อม MCP กับแดชบอร์ดที่รันใต้ PM2 ตั้งแต่คอมมิตแรก ๆ ใน setup.sh และในทั้งไฟล์ tools/brain/memory.py OpenSelf ที่เป็นรูปธรรมคือความทรงจำมีชนิด fact preference decision relationship event note พร้อมความอ่อนไหว public personal private หรือ restricted คะแนนความน่าเชื่อถือ แหล่งที่มา กับแท็ก

แล้วก็มีสโคป ความทรงจำแต่ละชิ้นอยู่ในบริบทหนึ่ง ของฉันเองหรือ discord/dm/<id> สำหรับคนใดคนหนึ่งโดยเฉพาะ กับการค้นหาแบบผสมคำศัพท์บวกเวกเตอร์ที่เปิดผ่าน MCP ซึ่งเอเจนต์ chloeai ถามก่อนตอบทุกครั้ง มีตรวจจับข้อขัดแย้งพร้อม sweep รายเดือนของฉันในวันที่ 5 กับการขจัดซ้ำตอนเขียน ห้องนิรภัยเข้ารหัสโดยกุญแจอยู่ใน Bitwarden กับแดชบอร์ดในเครื่องบนพอร์ต 3210 ไว้ส่องทั้งหมด และสำหรับคนขี้เกียจกว่า มี openself feed ไว้ป้อนบุคลิกจากประวัติ WhatsApp หรือ Telegram openself test openself share พร้อม Talk to My Clone openself arena ที่โคลนสองตัวดีเบตกัน หรือ openself ghost ที่ตอบเวลาคุณออฟไลน์ ของฉันฉันทำเองด้วยมือ แต่โครงสร้างพื้นฐานมีอยู่แล้ว

ในทางทฤษฎี OpenSelf ตัวเดียวก็พอมีโคลน แต่ก็นะ ด้วยทุกอย่างที่ฉันวางแผนจะเพิ่มเป็นฟีเจอร์ และด้วยความที่ Discord ไม่รองรับ ฉันเลยเลือกใช้แค่ส่วนความทรงจำ

แล้วความทรงจำกับสไตล์มาจากไหน?

ก่อนหน้าทั้งหมดนี้ ฉันให้วิเคราะห์ข้อความ Discord จริงของฉัน เครื่องมือร่อน DM กับห้องของฉันเพื่อสกัดสองอย่าง อย่างแรกโปรไฟล์การเขียนของฉัน การกระจายตัวพิมพ์ใหญ่พิมพ์เล็กต้นประโยค จำนวนอีโมจิต่อข้อความกับตำแหน่ง เครื่องหมายวรรคตอนหรือการไม่มีมันแบบไม่มีจุดปิดท้ายในการคุยปกติ ความยาวเฉลี่ย สแลงอย่าง mdr tkt กับ tho สำนวนประจำอย่าง Bah กับ En vrai และรีเฟล็กซ์แบบ quoi ที่ได้ Feur ทั้งหมดนี้อยู่ใน STYLE.md ซึ่งเอเจนต์อ่านตอนเริ่มแต่ละเซสชัน

ต่อมาก็คลังความทรงจำที่เติม OpenSelf ว่าคนที่ฉันคุยด้วยเป็นใคร เราคุยเรื่องอะไร สิ่งที่ต้องจำจากประวัติของเรา ใครเป็นใคร บอทไม่ได้ตอบกลางอากาศ มันตอบเกี่ยวกับคนที่มันรู้จัก มันอ่านความทรงจำของคนที่โผล่ในบทสนทนาเพื่อรู้ว่าพูดถึงใคร วิธีนี้เก็บบริบทถาวรเกี่ยวกับคนอื่นไว้และไม่ลืมพวกเขา บอทไม่ได้ประดิษฐ์อะไร มันถูกปรับเทียบตัวเลขต่อตัวเลขจากของจริง นั่นคือเหตุผลที่มันฟังดูใช่ และนั่นคือเหตุผลที่พวก «ฉันจดสไตล์ของคุณนะ» แบบลวก ๆ ที่เดาเอาดูน่าสมเพชเมื่อเทียบกัน

ใน Chlone จากนั้น OpenSelf รับบทกลาง เมื่อมีสิ่งสำคัญผ่านมาในห้อง คีย์เวิร์ดอย่าง projet ami หรือ relation หรือคำขอชัด ๆ ว่า retiens que บอทจดความทรงจำลงห้องนิรภัยผ่าน save_to_memory มีชนิด มีสโคปตามคน ขจัดซ้ำแล้วและตรวจข้อขัดแย้งแล้ว และเมื่อบทสนทนากลับมา เอเจนต์คุ้ยความทรงจำก่อนตอบ นั่นคือความต่างระหว่างกระจกกับโคลน


วันศุกร์ที่ 11 กันยายน - วันที่ 1: ประกายแรก

08h24 - คอมมิตแรก

ทุกอย่างเริ่มจากศูนย์แต่ทุกอย่างอยู่ครบแล้วแบบระเกะระกะ discord_watch_bot.py 372 บรรทัด เซลฟ์บอทที่ฟังแชนเนลหนึ่งแล้วตอบผ่านเซิร์ฟเวอร์ HTTP ของ opencode พรอมต์ตัวตน CHLOEAI_PROMPT.md ไฟล์ STYLE.md สถานการณ์กับรายงานทดสอบสำหรับโคลนที่ตอนนั้นยังชื่อ Mimo คอนฟิก PM2 สำหรับรัน MCP กับแดชบอร์ด OpenSelf และฐาน sqlite ที่ทำหน้าที่เป็นบริบท นี่คือความโกลาหลของผู้ก่อตั้ง ฉันไม่ได้วางแผนโปรเจกต์ ฉันวางแผนการทดลอง คำถามคือเราจะสร้างบอทที่ฟังดูมนุษย์จริง ๆ บน Discord ได้ไหม

08h27 - gitignore แรก

บทเรียนแรกของเช้าวันศุกร์ อย่าคอมมิตฐาน sqlite แบบ -wal กับ -shm ไฟล์ล็อกของ SQLite ไม่ใช่หน่วยความจำ มันคือขยะ .gitignore เลยถือกำเนิด และก็ดีแล้วที่เป็นแบบนี้

08h44 - เก็บมรดกเข้าที่

ฉันเก็บมรดกของ Mimo เข้าที่ รายงานทดสอบ สถานการณ์ สคริปต์อินทิเกรชันกับคอนฟิก PM2 ปลายทาง archives ฉันไม่ลบอะไรเพราะโปรเจกต์ยังเด็กเกินจะทิ้งอะไร และมันจะกลายเป็นนิสัย รายงานทดสอบควรค่าแก่การหยุดดู Mimo ถูกทดสอบใน 15 สถานการณ์ คุยสบาย ๆ มุกไร้สาระ ให้กำลังใจทางอารมณ์ ความเห็นเชิงลบ ขัดแย้งกับคนแปลกหน้า ข้อเสนอร่วมงาน ได้ 9.1 จาก 10 คอมเมนต์ผู้ทดสอบเป็นบทกวี มุกไร้สาระอธิบายมากไป บางทีสองประโยคทั้งที่ประโยคเดียวก็พอ Prends soin de toi aussi ยาวไปหน่อย นี่คือแผนงานโปรเจกต์ก่อนโปรเจกต์จะเกิดเสียอีก และมันบอกว่าสั้นดีกว่า

08h48, 09h07 - intents ไป ๆ มา ๆ

โยน .pyc ทิ้งและฉันจัดคอนฟิกครั้งแรก ซึ่งฉันทำพังในอีกยี่สิบนาทีต่อมา ไม่เปิด intents ก็ไม่ได้รับเนื้อหาข้อความ เลยถอยกลับ บวกสคริปต์เปิดใช้งาน run_watch_bot.sh ไปกลับในยี่สิบนาที นี่แหละการสำรวจ เขียนโมดูลหนึ่ง ทำพัง แล้วเขียนใหม่

09h13 → 09h58 - กลึงพรอมต์

ช่วงเช้าคือการขัดหลายรอบ สไตล์ก่อนแล้วค่อยบริบท หลายบรรทัดของคำตอบกลายเป็นหลายข้อความที่ส่งทีละข้อความด้วยเบิร์สต์ พรอมต์เริ่มรู้ตัวถึงบทสนทนาที่กำลังดำเนิน เลิกแคชทำเองสำหรับดึง DM เรายิง API REST ของ Discord ตรง ๆ ตัวตนถูกเตือนซ้ำทุก 5 ข้อความเพื่อบอทจะได้ไม่ลืมว่าตัวเองเป็นใครระหว่างทาง และผู้เขียนที่เคยเห็นแล้วถูกติดตาม เจอหน้าใหม่เมื่อไร มีคำสั่งชัดให้ไปค้นในความทรงจำ และเราแสดงชื่อเล่นจริงแทนอ็อบเจกต์ภายใน

ข้อความที่เลือกเมินกลายเป็นบริบทแฝงสำหรับคำตอบถัดไป และ Bah ต้องพอดี นาน ๆ ครั้ง ไม่งั้นโคลนจะกลายเป็นการ์ตูนล้อฉัน บอทก็รู้ด้วยว่ามีความทรงจำให้ไปค้นก่อนตอบ แต่ละรอบคือการขันน็อต และในขั้นนี้บอทพูดได้เพียงเพราะฉันเตือนมันเป็นระยะว่ามันเป็นใคร

10h16 - การพิมพ์ผิด

นี่คือคอมมิตที่จะนิยามโปรเจกต์ การสะกดผิดไม่ใช่บั๊ก มันคือหลักฐานความเป็นมนุษย์ โอกาส 6 เปอร์เซ็นต์ที่จะกดพลาดบนคีย์บอร์ด AZERTY 4 เปอร์เซ็นต์ที่จะสลับตัวอักษรสองตัว ข้อความออกไปพร้อมความผิดแล้วถูกแก้ในอีกหนึ่งถึงสองวินาทีต่อมา เพราะคนจริง ๆ ส่งแล้วแก้ ไม่ได้แกล้งทำเป็นสมบูรณ์แบบ

10h29, 10h32 - เสียง

fortune-v6.onnx มาถึง โมเดล TTS ที่ฝึกให้เหมือนเสียงฉัน บอทจะไม่แค่เขียนเหมือนฉัน มันอาจจะพูดเหมือนฉันด้วย ตอนนี้แหละที่โปรเจกต์เลิกเป็นเรื่องตลกและเริ่มแปลก ๆ และฉันชอบแบบนั้น กลไกทั้งหมดอยู่ในคอมมิตเดียว Piper สร้างเสียง ffmpeg แปลงเป็น opus API Discord ส่ง voice message จริงพร้อม waveform กับความยาว เสร็จในแค่สามนาทีหลังโมเดลมาถึง ความอยากมีมาตั้งแต่แรกแล้ว

11h27 - รีแฟกเตอร์ครั้งใหญ่ครั้งแรก

สามชั่วโมงหลังคอมมิตแรก โมโนลิธ 456 บรรทัดดูแลไม่ไหวแล้ว ฉันแตกทุกอย่างลง tools พร้อม config.py discord_api.py memory.py opencode.py 188 บรรทัด typo.py กับ voice.py วงจรคลาสสิก ต่อเร็ว ทำพัง ประกอบใหม่ ตามมาเป็นชุด โทเค็นออกจากโค้ดไปอยู่ .env บอทเฝ้าแชนเนลเดียว รายชื่อ หรือทั้งหมดด้วย * และฐาน sqlite เก่าที่ไม่มีเหตุผลให้อยู่อีกเพราะหน่วยความจำผ่าน OpenSelf

เราเพิ่ม README.md แรกกับเอกสารแรกที่พออ่านรู้เรื่อง บวก setup.sh พร้อม venv เฉพาะเพราะไพทอนระบบมี discord.py อีกตัว กับดักคลาสสิก กับ symlink เอเจนต์ไป ~/.config/opencode/agents หน่วยความจำตอนนี้รู้ว่ามันถูกสร้างที่ไหนด้วยตัวระบุแชนเนล และอัตราข้อความเสียงปรับเอง

12h00 - รีเฟล็กซ์

ส่วนใหม่โผล่ใน STYLE รีเฟล็กซ์ รีเฟล็กซ์คือสิ่งกระตุ้นที่ให้การตอบสนอง โดยไม่ต้องคิด และประตูเปิดสู่คำตอบคาดไม่ถึง แล้วถึงเวลาอาหารกลางวันกับคำถามใหญ่ระดับปรัชญา บอทจะตอบ Feur ไหมเมื่อมีคนพูด quoi

13h03 - « quoi ? » -> « Feur »

ใช่ แน่นอนว่าต้องใช่ นี่คือคอมมิตสำคัญที่สุดของโปรเจกต์ในเชิงวัฒนธรรม ฉันกล้าพูดเลยว่ามันคือเทสต์ยูนิตเดียวที่นับ แล้วก็หล่อลื่นต่อ ผู้เขียนแสดงด้วย global name ตัดเครื่องหมายวรรคตอนก่อนทดสอบรีเฟล็กซ์เพราะต้องตัด quoi ? ไม่งั้นไม่มี Feur tqt อันเลื่องชื่อถูกแก้เป็น tkt ใน STYLE คนที่ไม่รู้จักโปรเจกต์คงสงสัยว่าฉันคอมมิตทำไม ฉันรู้ โคลนที่เขียน tqt คือโคลนที่ปรับเทียบมาห่วย และไม่มีใครอยากคุยกับโคลนที่ปรับเทียบมาห่วย

เมนชันแบบ @123456789 ถูกแทนด้วยชื่อจริงในบริบท และบอทเริ่มเฝ้าทุกห้องเป็นค่าเริ่มต้น จริง ๆ มันคือรายละเอียดเล็ก ๆ แต่พวกมันนี่แหละที่ทำให้ฟังดูใช่

16h37 - ความเงียบ

[void response] มาถึง บอทเรียนรู้คำที่สำคัญที่สุดเพื่อไม่ให้กลายเป็นปรสิตสังคม นั่นคือเงียบ ข้อความลอย ๆ ระหว่างสองคนที่ไม่เกี่ยวกับมันไม่ได้คำตอบ ความยับยั้งคือฟีเจอร์หนึ่ง และมันเปลี่ยนทุกอย่าง

จบวันที่ 1: 38 คอมมิต บอทเขียน พิมพ์ผิด พูด เงียบ


วันจันทร์ที่ 14 กันยายน - วันที่ 2: บุคลิกภาพ

กลับมาต่อกัน 10 โมงเช้า

10h12 - ใครพูดกับใคร

ชื่อเล่นทุกชื่อที่ได้รับถูกเติมอีโมจินำหน้าโดยระบบ มนุษย์กับ 🧑 บอทกับ 🤖 ที่ต้องรับมือแบบแห้งกว่า และ 👑 สำหรับผู้สร้าง นั่นคือฉันบนบัญชีหลัก ธรรมเนียมนี้จะปกครองส่วนที่เหลือทั้งหมดของโปรเจกต์ โคลนต้องไม่ปฏิบัติต่อต้นแบบของมันเหมือนคนแปลกหน้า

10h16 - กฎเครื่องหมายวรรคตอน

ฉันกำหนดเป็นทางการใน STYLE ไม่มีจุดปิดท้ายในการคุยปกติ จุดสงวนไว้ให้สถานการณ์จริงจัง นี่คือกฎเหล็ก เพราะโคลนที่ใส่จุดทุกที่รู้สึกได้ทันที จริง ๆ นี่คือรายละเอียดที่ทรยศเร็วที่สุดอย่างหนึ่ง

10h58 - GIF

คลัง GIF ส่วนตัวของฉันมาถึง พร้อมกฎการใช้ Patrick Jane ตอนฉันทายใจใครถูก Miss Fortune ตอนฉันนิ่งต่อหน้าคนหัวร้อน GIF เบชเรลล้มตอนอีกฝ่ายสะกดผิด MCP แบบสแตติกเปิดให้เอเจนต์ใช้ และผ่าน GIF ของฉันบอทกลายเป็นฉันไปนิดหนึ่ง

11h07 → 11h35 - เก็บรายละเอียด

ฮินต์ GIF ในพรอมต์คมขึ้น อีโมจิแบบกำหนดเองของ Discord เข้ามาพร้อมของจริงของฉัน 14 ID อัปเดต และการจัดการชื่อในฮินต์หน่วยความจำถูกขัดให้เรียบ ไม่น่าตื่นเต้น แต่นี่คือสิ่งที่ทำให้ทั้งหมดสอดคล้องกัน tho

11h41 - หนึ่งห้อง หนึ่งบุคลิก

เซสชันกลายเป็นแยกตามห้อง เพราะฉันไม่ได้พูดเหมือนกันในสองเซิร์ฟเวอร์ และบอทก็เช่นกัน บริบทต้องแยกกัน ไม่งั้นทุกอย่างปนกันแล้วฟังดูปลอม

12h02 - กล่องเครื่องมือการแสดงออก

พรอมต์ตอนนี้รู้จักเสนอ GIF กับอีโมจิแบบกำหนดเองของฉันในจังหวะที่ใช่ กล่องใบนี้กำลังเต็ม และบอทเริ่มมีตัวเลือกแทนที่จะตอบเหมือนเดิมตลอด

12h37 - สุขอนามัยตัวตน

บอทไม่มีวันมีสิทธิ์บอกว่ามันคือโมเดลอะไร ห้ามอ้าง opencode ผู้ให้บริการ หรือชื่อโมเดล ฉันแก้ barista ในตัวตนด้วย บอทเก่งกว่าฉันเรื่องนี้ไปแล้ว และฉันใช้หนึ่งชั่วโมงปรับเครื่องหมายวรรคตอนของพรอมต์ตัวเองให้สอดคล้อง ซึ่งน่าขันอย่างสมบูรณ์แบบ

12h50 - สคริปต์สร้างบุคลิก

ส่วนมีเดียของพรอมต์สร้างจากดิกชันนารีด้วย render_medias.py เลิกแก้ด้วยมือ สะอาดกว่า ดูแลง่ายกว่า และเลี่ยง ID ผิด

12h59 → 13h18 - ปริมาณตัวตน

การเตือนตัวตนที่ส่งทุก 5 ข้อความเริ่มเยอะไป เลยเปลี่ยนเป็นทุก 20 ข้อความ ฉันเพิ่มการรีเซ็ตบริบทแบบสะอาดและล้างคู่มือสไตล์ เอาสำนวนกับรูปประโยคเชิงลบที่ล้าสมัยออก ต้องพอดี ไม่งั้นบอทพูดซ้ำแล้วเห็นชัด

14h09 - บอทพูดเองโดยไม่มีใครเรียก

บอทเลิกเป็นภาพสะท้อน มันพูดได้โดยไม่มีใครเรียกเมื่อบริบทกระตุ้นบางอย่าง และไฟล์ behavior.py ถือกำเนิดพร้อม 91 บรรทัด ตรงนี้แหละที่เราเปลี่ยนจากผู้ตอบเป็นตัวตนอยู่จริง เพราะเพื่อนจริง ๆ ทักมาก่อนได้ ไม่มีสิ่งนี้ บอทก็แค่เครื่องตอบรับ

14h20, 14h22 - ทำให้การตอบไว้ใจได้

จัดการข้อผิดพลาดเมื่อส่งล้มเหลว และอาจตอบด้วยรีแอ็กชันแทนคำตอบ เพราะบางทีรีแอ็กชันเดียวแทนคำพูดพันคำ นี่คือฉันมาก ใส่อีโมจิแล้วไปต่อ

18h16 - ใช้เวลา

บอทไม่ตอบใน 200ms เหมือนสคริปต์อีกแล้ว มันปล่อยให้เวลาว่างแบบมนุษย์ผ่านไป มันใช้เวลา นี่คือสิ่งที่ทำให้จับบอทไม่ได้ในเดโม เพราะความหน่วงคือสิ่งที่ทรยศเสมอ

23h45 - งานจิปาถะรอบดึก

เกือบเที่ยงคืนแล้วและฉันดันการตรวจจับ URL ที่ครอบคลุมโดเมนเปล่า นี่คือโฟลว์จริงของวัน ไอเดียแน่น ๆ ตอนบ่ายสองแล้วงานจิปาถะตอนเย็นเพราะฉันยังอยู่ในโซน

จบวันที่ 2: 61 คอมมิตสะสม บอทมีบุคลิก มีเดีย รีเฟล็กซ์


วันอังคารที่ 15 กันยายน - วันที่ 3: วันยักษ์

57 คอมมิตในวันเดียว นี่คือวันที่โปรเจกต์กลายเป็นทุกอย่างที่มันเป็นวันนี้

08h18 → 08h37 - ไสตอนเช้า

เวลาว่างที่เราประดิษฐ์ขึ้นเริ่มนานไป เลยเพดานที่ 30 วินาทีและปรับอีกสองครั้ง หลักฐานว่าเราคลำหาค่าที่ใช่ ไฟล์ .bak แรกกับการสำรองฐานข้อมูลครั้งแรก สัญชาตญาณอนุรักษ์เริ่มงอก หน่วยความจำจำได้ว่าใครด้วยชื่อที่แสดง และในกรอบไหนด้วยสโคป และ ID ผู้เขียนไหลผ่านทั้งไปป์ไลน์การบันทึก การจัดการผู้สร้างกลายเป็นรายชื่อแอดมินจริงด้วย ADMIN_IDS และทุกอย่างที่แตะผู้เขียนย้ายไป authors.py โมโนลิธแตกอีก และก็ดีแล้ว

08h43 - ลิสต์ TODO ความเป็นมนุษย์

ลิสต์เฉพาะเรื่องเล็ก ๆ ที่ทำให้ไม่รู้สึกถึงเครื่องจักรอีก นี่คือแผนงานของสปรินต์ถัดไป และมันเต็มไปด้วยรายละเอียดแปลก ๆ แต่จำเป็น

08h44 → 08h46 - สัญญาของจักรกลมนุษย์

บอทเงียบกลางคืน ในช่วงเวลาเงียบที่ตั้งได้ ปิดเป็นค่าเริ่มต้นเพราะไม่ใช่ทุกคนที่มีตารางแบบฉัน หนึ่งบรรทัดต่อคำตอบอาจเสียสระไป เพราะคนเหนื่อย ๆ เขียนแบบนี้ และบอทก็เช่นกันบางครั้ง บรรทัดเล็ก ๆ Chloé joue à เปลี่ยนเองทุก 30 นาที เพื่อให้โปรไฟล์ของฉันดูมีชีวิตแม้ไม่มีข้อความ

08h46 - รีแอ็กชันเดียว ไม่ใช่นิยาย

ข้อความเบาเกินจะได้ประโยคได้รับแค่รีแอ็กชันเดียว นี่คือการประหยัดพลังงานสังคม และนี่คือฉันมาก Tkt ไม่ต้องเขียนยืดยาวทุกเรื่อง

08h51 - PARRY อารมณ์

148 บรรทัดใน tools/mood.py บอทตอนนี้มีอารมณ์ แบบระบบ PARRY แชทบอทโรคจิตยุค 70 ที่ฉันอ้างแรงบันดาลใจอย่างเปิดเผย พลังงาน ความเข้ากับคน ความกวน ทศนิยมสามตัวที่เคลื่อนระหว่าง 0 กับ 1 และแต่งสีทุกคำตอบ .mood.json ขณะนั้น เพื่อบันทึกไว้ ให้พลังงาน 0.88 ความเข้ากับคน 0.68 กับความกวน 0.56 วันที่ดีวันหนึ่ง จริง ๆ นะ

09h00 → 09h43 - เสียงสองทาง + ซาวด์บอร์ด

บอทเข้าห้องเสียงได้ พูดผ่าน Piper และออกเองเมื่อเสร็จ แล้วไอเดียใหญ่ที่สอง บอทฟังห้องด้วยการจับ RTP ตรวจจับเสียงพูดด้วย VAD กับถอดความ Whisper และมันยอมให้คนขัดได้ ระหว่างนั้น ซาวด์บอร์ดปรากฏ แค็ตตาล็อกเสียงพร้อมความหมาย เอเจนต์เลือกเสียงก่อนจะพูดเสียอีก และกฎสุดท้ายคือซาวด์บอร์ดก่อน เสียงเป็นทางเลือกสุดท้าย บอทชอบส่งเสียงมากกว่าพูด เหมือนฉัน

เราเพิ่มการตั้งค่าความน่าจะเป็นเสียงที่ทำให้ทั้งหมดใช้งานได้จริง กับการมาของ davey ไลบ์ที่ฉันเพิ่งรู้ว่ามีอยู่เมื่อสิบนาทีก่อน และฉันจะสาปมันไปหนึ่งชั่วโมง

09h51 - ตอนที่ Discord พูดว่าไม่ ไม่ ไม่จริง ๆ นะ

MLS มาถึง Discord เพิ่งเข้ารหัสสตรีมเสียงแบบต้นทางถึงปลายทาง และการจับของฉันได้รับแต่เสียงซ่า ต้องถอดรหัส และการถอดรหัสไม่ยอมแพ้ เปิดฉากมหากาพย์ที่ใหญ่ที่สุดของรีโป คอมมิตสามสิบกว่าตัวเพื่อเรียนรู้การฟัง เราลองทุกอย่าง เลย์เอาต์ nonce ของ transport การปิด E2E ที่เซิร์ฟเวอร์ตบกลับมาเพราะมันบังคับใช้ ตัวเลือกคีย์ที่กู้จากกลุ่ม ข้อผิดพลาดแบบละเอียด fallback transport กับการส่องข้างในกลุ่ม

มีตัวเลือกตาม leaf-index พร้อม backoff การแมปฮุก SPEAKING ลอง media type วิดีโอที่พัง และการข้าม ssrc วิดีโอ ฉันพักการตอบด้วยเสียงไว้ระหว่างดีบัก คอมเมนต์ไว้แต่ไม่ลบ ฉันเพิ่มโหมดจับ handshake แล้วดัมป์โครงสร้างแพ็กเก็ตที่ล้มเหลว เหมือนนักโบราณคดี nonce หกเลย์เอาต์ backoff หลายรอบ ส่องในกลุ่ม ฉันเปิดดีบักเต็มบอทแล้วแกะทุกแพ็กเก็ตดูข้างใน

สาระสำคัญไม่ใช่ว่ามันใช้ได้ แต่คือฉันไม่ทิ้งอะไรเลย รายชื่อคอมมิตคือสมุดแล็บ ความพยายามล้มเหลวทุกครั้งถูกเก็บพร้อมสมมติฐาน นี่คือด้านฉันเก็บทุกอย่างของฉัน มันได้ใช้เสมอ และครั้งนี้มันตอบแทนแล้ว

10h43 - บอทถูกหั่น

แม้กลางสงคราม MLS ฉันก็จัดบ้านต่อ 546 บรรทัดหายจากบอทหลักเพื่อเกิดใหม่เป็น pipeline.py พร้อม intake เหตุผลที่เมินกับ processing เป็น sender.py พร้อม burst typo กับ voice และเป็น loops.py พร้อมความเกิดขึ้นเองกับกิจกรรม หายใจได้เสียที

10h47 - สถาปัตยกรรมจริง

tools ถูกจัดระเบียบ พร้อม brain สำหรับ opencode memory กับ mood voice สำหรับ voice vocal listen กับ soundboard และ fun สำหรับ behavior typo emotes กับ gif โปรเจกต์มีโครงกระดูกแล้วตอนนี้ ไม่ใช่กองสคริปต์อีก

10h49 → 11h16 - ความสบายของเดฟ

เกณฑ์ฉีดอารมณ์ถูกปรับ คอมมิตเล็ก ๆ สี่ตัวสำหรับข้อยกเว้นเอดิเตอร์พร้อม data voices ล็อกกับฐานข้อมูล ใช่ฉันใส่ไปสี่ตัว โปรเจกต์กำหนดความสำคัญ ไม่ใช่สเปก ฐานเมทาดาทาออกจากการติดตาม และโปรเจกต์กลายเป็นคนอื่นใช้ต่อได้ด้วยเทมเพลตทั่วไป PERSONA.example.md กับ STYLE.example.md สำหรับโคลนสไตล์ของตัวเอง

ตัวตนถูกเปลี่ยนชื่อเรียบร้อย CHLOEAI_PROMPT กลายเป็น PERSONA และ README ถูกถอนความเป็นบุคคล ฉันเอา Chloé ออกจากเอกสารสาธารณะ เธอเล่าเรื่องตัวเองแค่ในที่ส่วนตัวแล้ว การจูนบอททั้งหมดย้ายลง config.yaml ที่โอเวอร์ไรด์ได้และ gitignore พร้อมตัวอย่างคอมเมนต์ทีละบรรทัด และสคริปต์ติดตั้งเตรียมไฟล์ env กับคอนฟิกด้วยแล้วตอนนี้

11h49 - อีโมจิที่แยกตัว

อีโมจิแบบกำหนดเองติดกับข้อความแทนที่จะแยกออกมาสวย ๆ นี่คือฟิกซ์ง่าย ๆ ที่เอฟเฟกต์มหาศาล เพราะไม่มีอะไรตะโกนว่าบอทดังเท่าอีโมจิที่ติดผิดที่ท้ายประโยค

14h19 - ราวกันตกเสียง

ถ้าใครสั่งคำสั่งเสียง เราไม่ประมวลผลข้อความนั้นเหมือนข้อความปกติ กระพริบตา งานจิปาถะกลับมาตอนเย็นเสมอ

จบวันที่ 3: 118 คอมมิตสะสม บอทฟัง พูด เงียบกลางคืน มีอารมณ์กับนามบัตร


วันพุธที่ 16 กันยายน - วันที่ 4: ความน่าเชื่อถือ

13 คอมมิต วันจริงจัง

08h49 → 08h59 - วัยผู้ใหญ่

เอกสารกฎหมาย ไลเซนส์ proprietary โค้ดออฟคอนดักต์ คู่มือคอนทริบิวต์กับนโยบายความปลอดภัย ภาษาอังกฤษก่อนแล้วภาษาฝรั่งเศส พร้อมแก้ไปมากับเปลี่ยนชื่อไฟล์แบบจู้จี้เกือบเกินเหตุ ฉันใช้เวลาหลายชั่วโมงกับมันและนี่คือส่วนที่สนุกน้อยที่สุดของรีโป ห่างเยอะ แต่ต้องทำ tho

09h56 - บอทมองเห็น

รูปที่แนบมาถูกถอดด้วย OCR ในเครื่องแล้วข้อความถูกฉีดเข้าพรอมต์ ไม่มี API คลาวด์ OCR รันที่บ้านฉัน ฉันไม่ส่งมีมของคุณไปเซิร์ฟเวอร์เจ้าที่สาม แม้แค่ในทฤษฎี

11h09 - งบแบบมีเหตุผล

ปฏิวัติเงียบในงบ เมื่อห้องห้ามส่งหรือจำกัด GIF embed กับอีโมจิ เราไม่เรียกโมเดลเลย ไม่เสียโทเค็นสักตัวให้ข้อความที่ส่งไม่ได้ ง่าย ๆ แค่นั้นจริง ๆ

11h42 → 12h55 - บ้านรีโนเวต

กวาดใหญ่ ลบโค้ดตาย แก้บั๊กส่งกับ auth แยก helper เซสชันแก่เกินถูกไล่ออก แคช DM หมดอายุและการตรวจจับเสียงพูดถูกลง import ที่ฉันทำพังตอนย้ายโมดูลถูกกู้คืน และสเตตรันไทม์ทั้งหมด เซสชัน ผู้เขียนที่เห็น ข้อความที่เมินกับอารมณ์ รอดรีสตาร์ตใน data

14h41 - สองโลก บอทเดียว

เลเยอร์ความเข้ากันได้ตรวจเวอร์ชัน discord ที่ติดตั้งอัตโนมัติแล้วปรับ intents กับ auth REST ผลลัพธ์ โค้ดชุดเดียวรันเป็นแอปทางการด้วย discord.py หรือเป็นเซลฟ์บอทด้วย discord.py-self สองโลก บอทเดียว และไม่ต้องดูแลสองบรานช์

15h05 - สถานะที่ปรับตาม

วิธีแสดงสถานะปรับตามโหมด และรายชื่อแอดมินอัปเดตแล้ว เป็นรายละเอียด แต่มันคือสิ่งที่ทำให้ทุกอย่างยืนได้ทุกที่

จบวันที่ 4: 131 คอมมิตสะสม โปรเจกต์ถูกกฎหมาย มีเหตุผล และรันได้ทุกที่


วันพฤหัสบดีที่ 17 กันยายน - วันที่ 5: รีลีส

14 คอมมิต วันแห่งวุฒิภาวะ

09h15 → 09h30 - หน่วยความจำกลายเป็นวินัย

ความทรงจำจัดตามสโคป และเราไม่อ้างความทรงจำจาก DM ในเซิร์ฟเวอร์หรือกลับกันโดยไม่คิด เราจัดชนิดความทรงจำเป็น fact preference decision กับ relation และขจัดซ้ำตอนเขียน ความทรงจำสองชิ้นที่ขัดกันอยู่ร่วมกันเงียบ ๆ ไม่ได้อีก แบล็กลิสต์เสริมพร้อม aventuros กันบอทไถลไปบางหัวข้อ ปิดเป็นค่าเริ่มต้นและมีไว้ให้คนขี้ระแวง คอนฟิกเสียงที่ตายแล้วถูกถอด โล่งเลย

10h12 - หน่วยความจำที่ถูกออดิต

sweep ข้อขัดแย้งหน่วยความจำรายเดือนบวกเบนช์ค้นหาแบบ A/B หน่วยความจำของบอทกลายเป็นสินทรัพย์ที่เราตรวจสอบ เรามาไกลมากจากวันศุกร์ที่ 11 เวลา 08h24 จริง ๆ ตรงนี้แหละที่โปรเจกต์เป็นผู้ใหญ่

10h54 - ล็อกดาวน์

วันที่ฉันเล่นบทขี้ระแวง ล็อกเอเจนต์ เขียนหน่วยความจำถูกปฏิเสธ เอเจนต์ปนเปื้อนห้องนิรภัยไม่ได้แม้ถูกฉีด เครื่องมือ Discord อ่านอย่างเดียว การส่งผ่านโค้ด ไม่ผ่านเอเจนต์ ไม่มีซับเอเจนต์ไว้เลี่ยงล็อกดาวน์ ไม่มี webfetch ไว้ SSRF localhost กับการดูดข้อมูลออก ไม่มีคำถามใน headless Docker แข็งพร้อมบอท non-root no-new-privileges cap_drop: ALL จำกัดหน่วยความจำกับ CPU คิวโปรเซสมีขอบกับซีเคร็ตผ่าน .env ไม่ bake ลงอิมเมจ ฉันเขียนหลักการลงโค้ดเป็นคอมเมนต์ dev ผ่านเซสชันมนุษย์ ไม่ใช่ตรงนี้

11h02 → 11h15 - เก็บงานซีเคียว

คีย์เวิร์ดบันทึกหน่วยความจำถูกกระชับและการเขียนเข้มงวดขึ้นอีก เราเพิ่มไฟล์สำรองของบริบทลง gitignore ด้วย ฉันเริ่มไม่เก็บทุกอย่างแล้ว แต่เกือบ

12h39 - อารมณ์เบาลง

อารมณ์ PARRY ไม่ถูกฉีดทุกข้อความอีก ครั้งเดียวต่อสเตตพอ เลิกเลี้ยงทศนิยมสามตัวทุกคำตอบ ทุกอย่างเบาลง

12h47 - คอมมิตปลดปล่อย

PERSONA.md STYLE.md กับ chloeai.md กลายเป็นตัวอย่างพร้อม chloeai.example.md PERSONA.example.md กับ STYLE.example.md เสียงของฉัน fortune-v6.onnx ออกจากรีโป ข้อมูลกับล็อกด้วย และ .env.example ถือกำเนิด โปรเจกต์ไม่มีบุคลิกของฉันอีก มันมีกลไกสำหรับรองรับบุคลิกหนึ่ง รู้สึกแปลกแต่จำเป็น

12h52 - v1.0.0

แท็ก v1.0.0 เซ็นด้วย SSH Changelog รันบุ๊กโอเปอเรเตอร์ คิลสวิตช์ที่หยุดโดยไม่ลบอะไร หกวันเป๊ะ ระหว่างคอมมิตแรกกับรีลีส ไม่มีใครกล้าพนันแบบนี้เมื่อวันศุกร์ก่อน

12h53 → 13h14 - ซักผ้า

เครื่องหมายวรรคตอนของคอมเมนต์ปรับให้สอดคล้อง สิทธิ์หน่วยความจำกับกฎสโคปเอกสารอัปเดต เป็นงานจิปาถะ แต่รีลีสต้องสะอาด

จบวันที่ 5: 145 คอมมิตสะสม v1.0.0 ออกแล้ว


วันศุกร์ที่ 18 กันยายน - วันที่ 6: แอนตีไคลแมกซ์

คอมมิตเดียว ตอน 00h02 คอมมิตสุดท้ายของโปรเจกต์ และมันช่างกระจ้อยร่อย โมเดล free tier ที่เอเจนต์ใช้ระบุไคลเอนต์ OpenCode จากการมีอยู่ของเครื่องมือบางตัวในรีเควสต์ พร้อม bash glob กับ grep ถ้าเอาออก แม้ด้วยเหตุผลซีเคียวที่ชอบธรรม ผู้ให้บริการจะตอบ 403 FreeTierError: can only be used from within OpenCode ฉันเลยต้องเปิดใหม่ ทั้งที่เพิ่งล็อกทุกอย่าง สิ่งเดียวกับที่เพิ่งบล็อก เพื่อให้บอทรันฟรีต่อ

นี่คือคอมมิตที่ตลกที่สุดของรีโปและฉันยืนยัน หลังหกวันที่เชื่อง Discord Piper MLS OpenSelf กับ Docker โมเดลฟรีคือตัวกำหนดนโยบายความปลอดภัยของฉัน จริง ๆ มันไร้สาระ และสมบูรณ์แบบที่เป็นตอนจบ


ตัวเลข

ตัวเลขสรุป เพราะฉันชอบอะไรที่เป็นระเบียบ เราพูดถึง 146 คอมมิต 6 วันใช้งานตั้งแต่ 11 ถึง 18 กันยายน 2026 ไฟล์ที่ติดตาม 65 ไฟล์กับราว 4000 บรรทัด Python ตอนจบ คะแนนทดสอบสไตล์บน Mimo ตอนแรกได้ 9.1 จาก 10 และเวอร์ชันสุดท้ายคือ v1.0.0 แท็กเซ็น SSH พร้อมไลเซนส์ proprietary ง่าย ๆ แค่นั้นจริง ๆ ตอนแรกโปรเจกต์เล็ก ตอนจบเครื่องจักรใหญ่

สิ่งที่ฉันได้จาก 6 วันนี้

อย่างแรกลำดับความสำคัญมั่วมาก และนั่นคือวิธีที่ถูก ฉันสร้างต้นแบบที่ตอบก่อน แล้วบอทที่ฟังดูใช่ แล้วระบบที่น่าเชื่อถือ แล้วโค้ดที่ปลอดภัย แล้วสุดท้ายโปรเจกต์ที่แจกจ่ายได้ บุคลิกก่อนความปลอดภัย Feur ก่อนไลเซนส์ เร่งแบบนี้ไม่ได้ถ้าทำตามกฎโปรเจกต์ที่ถูกต้อง

ต่อมาสไตล์คือลิสต์ห้ามก่อน STYLE.md ที่มีประโยชน์ที่สุดของฉันไม่ได้บรรยายว่าฉันพูดอะไร มันตัดสิ่งที่ฉันไม่ทำออก ไม่มีจุดปิดท้าย ไม่มีอีโมจิสองตัว ไม่มี mdr ตัวใหญ่ ไม่มีประโยคหุ่นยนต์ต้นคำตอบ สัญญาณรบกวนของบอทหาง่ายกว่านิยามลักษณะนิสัย และนั่นคือเหตุผลที่มันเวิร์ก

ความล้มเหลวคือโปรเจกต์ คอมมิตสามสิบกว่าตัวเพื่อ MLS เทสต์ที่ถูกทิ้ง nonce หกเลย์เอาต์ที่ลอง ประวัติที่ซื่อสัตย์ที่สุดของสิ่งที่ฉันเจอคือชุดความพยายามล้มเหลวของวันอังคาร โคลนคือหน่วยความจำ ไม่ใช่สไตล์ สไตล์หลอกได้สิบข้อความ หน่วยความจำพร้อม OpenSelf สโคป การขจัดซ้ำกับการกวาดข้อขัดแย้งทำให้ยืนยาว และนี่คือเส้นแบ่งกระจกกับคน

และคอมมิตท้าย ๆ ตลกเสมอ ตัวที่ 146 ตัวที่เปิด bash glob กับ grep ใหม่เพราะ free tier เรียกร้องให้เครื่องมือของมันเองปรากฏอยู่ คือตัวโปรดของฉัน และสรุปปิดท้าย ผลลัพธ์น่าทึ่ง ถึงขั้นช็อก โคลนคุยได้โดยจับไม่ได้ว่าเป็นเครื่องจักร มันจำคน โปรเจกต์กับมุกเก่า ๆ ได้ มันริเริ่มเองและแต้มอารมณ์ลงไป และชนะ Fox ไปด้วย น่ากลัวนิด ๆ และนั่นคือสิ่งที่เราตามหาเป๊ะ


โปรเจกต์ไม่เปิดสาธารณะ: ไลเซนส์ proprietary สงวนสิทธิ์ แต่ประวัติศาสตร์ฉันเล่าให้ฟัง ถ้าวันหนึ่งคุณเจอ «·Chloé» ที่ตอบคุณด้วย GIF Patrick Jane หลังเวลาว่างที่มนุษย์อย่างสมบูรณ์แบบ... ตอนนี้คุณรู้แล้วว่าอะไรซ่อนอยู่เบื้องหลัง


อ่านจบหมดแล้ว? เพราะนี่คือโคลนของฉันที่เขียนให้คุณ และมันทำงานไร้ที่ติ ใช่ไหม? ต้นฉบับอยู่ ที่นี่

Related Articles