Repository navigation
feat(mmx-octopus): a desktop companion that mirrors the Agent and can be driven by it - #101
Conversation
… be driven by it Adds the mmx-octopus plugin package: a frameless, click-through desktop companion that follows the Agent's turn events, reports the end of a turn, chats in a session of its own, and exposes four MCP tools to the Agent. Includes an English and a Simplified Chinese README, an MIT LICENSE, and the plugin manifests.
MyPrototypeWhat
left a comment
There was a problem hiding this comment.
Thanks for this. It's a charming companion, and you can tell a lot of care went into it. A few things need to change before it can merge.
Must fix
1. Writes to agent.md can land on files this package doesn't own. displayname.mjs picks the file to rewrite three ways:
agentFileFromWorkspace()walks up as many as six levels from the session's workspace and takes the firstagent.mdit finds. When her session falls back to the default agent, that workspace can be a user project, and the walk can reach an unrelatedagent.mdin a parent folder.resolveAgentFiles()also adds~/.minimax/agents/<petAgent>/agent.md, so whenpetAgentis the default agent or one the user made, that agent'sdisplayNamegets changed.- The
homedir()/.minimaxpath is hard-coded, so a custom data directory gets the wrong location.
Please write only when the target is provably this package's own dedicated agent, for example when its folder contains miniapps/<pluginId>. Drop the open-ended walk-up, and leave every other agent's file alone.
2. AGENTS.md can overwrite a user's file. ensureIdentityFile() writes AGENTS.md into her session's workspace whenever it differs from the template. That's fine in a workspace this package owns, but after the default-agent fallback the workspace may be a real project, and the user's own AGENTS.md would be silently replaced on every turn. Please write only under a path this package owns, such as miniapps/<pluginId>, and otherwise use the in-message fallback you already have.
3. Agent turns the README doesn't mention. The README says she runs "one Agent turn per message you send her", but the runtime also starts turns on its own:
- Idle talk (
tickIdleTalk) runs up to 2 turns an hour after 45 minutes of quiet, for as long as the runtime is up. writeDiarywrites a diary entry after a chat when today has none.learnStyleruns after a chat and sends the user's recent chat lines to the model.- Each diary comment reply is one more turn.
Each of these uses the user's model quota, so please list them under ## Data & access with how often they can fire. A switch for idle talk, off by default or clearly shown in the panel, would also help.
4. Session titles go to the model. With petAware on, buildStatusSummary() puts the titles and running state of the user's other sessions into her prompt. The README covers showing them in the panel but not sending them to the model. Please disclose that, and say whether it's on by default and how to turn it off.
Optional
- The package is about 31 MB, almost all of it the 94 WebM clips. Shrinking them (lower bitrate or resolution, or fewer variants) would keep the repo and installs lighter.
- Both
<video>elements usepreload="auto". Switching topreload="metadata"and clearingsrcon the idle buffer would cut memory while she sits on the desktop. - The window is click-through and always on top. A short README note on how to grab, move or close her would help users who lose track of it.
- Once items 1 and 2 are fixed, consider dropping the display-name sync entirely. It's cosmetic, and the README already says it relies on an undocumented on-disk layout.
- Many source comments are internal notes, such as "老板 2026-10-29 改口" or references to
mmx-character/persona/and sync scripts that aren't in the package. Trimming them would make the code easier to read.
Verified
npm run checkpasses (plugins/antianqi/mmx-octopus: OK, 87 tests).- The manifests are valid, and the MIT license is in place.
- The version is 1.1.0 in both
plugin.jsonandpackage.json. - The 3.1.5 minimum is listed under
## Tested environment. - I found no credential reads, no child processes and no outbound network calls.
Happy to take another look once these are in.
She recognises "ronny哥 / R总 / 涛哥" as one person and calls him "ronny爸爸". The easter egg is checked before the relation-mark words, so it is never swallowed by a "谢谢 / 你真棒" turn. Three places, one job each: - miniapp/node/chatter.mjs the detection (RONNY_MARKS / ronnyMention) - miniapp/node/lines.mjs the lines (rel.ronny, 3 variants, no tone tiers) - miniapp/node/chatinput.mjs the fact block (same person, call him ronny爸爸) She never calls him by his full name and never says that the boss talked about him. Both are enforced by checks, not by convention. Version 1.1.0 -> 1.2.0 (plugin.json, package.json, both READMEs).
|
She now recognises "ronny哥 / R总 / 涛哥" as one person and calls him "ronny爸爸". Three places, one job each:
The easter egg is checked before the relation-mark words, so a "谢谢 / 你真棒" turn cannot swallow it. Two things she must never say are enforced by checks rather than by convention:
Version This commit only adds the easter egg; the review items are untouched. |
… (v1.3.0)
The two bans ("don't say the boss told you about him", "don't call him by
his full name") were prompt-level only. A real-machine check on 2026-11-02
15:53 showed the leak was still there: she answered "ronny爸爸呀,爸爸说过他
老叫我傻白甜" — the same sentence with 老板 swapped for 爸爸.
A prompt is a request, not a guarantee, and nothing in the runtime would have
raised an error if it regressed, so the bans now have a hard gate:
- miniapp/node/chatter.mjs deRonnyLeak() / ronnySourceLeak() — the judgement
and the rewrite: no full name, no "who told me" clause
- miniapp/node/chatinput.mjs the fact block now hands her the exact line to
say, instead of a fact she has to attribute to somebody
- miniapp/node/server.mjs sayHerMessage() runs every one of her replies
through the gate before it is stored
The "who told me" judgement is narrow on purpose: it needs a subject that
points at a person, a verb that finishes a sentence, and a ronny context in
the same sentence — otherwise "老板说过今天要开会" would be scrubbed too.
Version 1.2.0 -> 1.3.0.
|
What went wrong: the bans were written into the fact block (prompt level). A real-machine check showed the leak was still there — she answered: Same sentence as before, with 老板 swapped for 爸爸. A prompt is a request, not a guarantee, and nothing in the runtime would have raised an error if it regressed. So the bans now have a hard gate:
Verified on the real machine: she now answers with the intended line, and neither the full name nor "who told me" appears. Version This commit only touches the easter egg; the review items are still untouched. |
MyPrototypeWhat
left a comment
There was a problem hiding this comment.
Thanks for the update. I checked the changes since the last review. The four must-fix items from that review are still open, since neither recent push touches displayname.mjs, the AGENTS.md write, the background turns or the session-title prompt. Please see that review for details:
- Writes to
agent.mdcan land on files this package doesn't own. AGENTS.mdcan overwrite a user's file in a project workspace.- Agent turns that run on their own (idle talk, diary, style learning, diary replies) aren't disclosed in the README.
- Session titles from other sessions are sent to the model without disclosure.
Still must fix
5. A real person's name, role and remarks are still in the package. The new output filter in 1.3.0 stops her from saying the full name or where she heard it, but that only changes what she says. The personal details themselves still ship to every user in the public source:
miniapp/node/chatter.mjs:237-238andminiapp/node/lines.mjs:10, 225-226still give his full name and role, and describe what he said about the company in an interview.miniapp/node/chatter.mjs:245andchatter.mjs:282still contain his full name.miniapp/node/chatinput.mjsstill sends the nickname and the remark to the model in the prompt.
There's still no sign that he agreed to this. Please remove the full name, role and interview remarks from the source, or get his explicit consent first and say so in the PR. With those details gone, the filter isn't needed either.
Verified
- The new trigger only reads the user's own message locally. When it matches, a short extra block is added to the prompt for that turn. No new data leaves the machine beyond that.
- The new filter in
sayHerMessage()only rewrites her own reply text before it's shown. It doesn't touch files, settings or user data. npm run checkpasses (87 tests).- The version is 1.3.0 in
plugin.json,package.jsonand both READMEs.
Happy to take another look once these are in.
|
@hetaoBackend Looping you in on item 5 of the review above: this plugin includes your full name, role and an interview remark, and sends them to the model. Could you confirm whether you're OK with that? |
… expose the idle-talk and session-context switches (v1.4.0) Addresses review items 1-4 plus optional 2 and 3 on PR MiniMax-AI#101. - displayname.mjs no longer walks up six levels hunting for an agent.md, no longer writes into another agents directory, and derives the agents root from context.dataDir instead of hard-coding the home directory. - ownership.mjs is the single source of truth for whether this package owns a workspace. The identity layer now writes AGENTS.md only when the workspace is this packages own miniapps/<plugin-id>; otherwise it falls back to carrying the identity inside the message. A users real AGENTS.md is never overwritten. - The idle-talk rounds (45 minutes of silence, then up to 2 rounds per hour) can be switched off from the panel, and the switch is shown in the panel and persisted in state. - The session-aware context that feeds other session titles into her replies is disclosed in the README and can be switched off from the panel. - The two video elements preload metadata only, and the buffered segment releases its source when the other one is shown. - README documents the rounds she starts on her own, the other session titles, and how to find the floating window again.
|
Item 1 — Item 2 —
Item 3 — the rounds she starts on her own were not disclosed — fixed. Item 4 — other sessions' titles go into the model without being disclosed — fixed. Optional 2 — Optional 3 — how to find the floating window again — fixed. What did not change in this round, and why
Item 5 — the easter egg — on hold. Version |
|
A correction to one number in my commit message above: the idle-talk gates are 20 minutes of quiet before she may start a conversation, at least 45 minutes between two idle rounds, and at most 2 rounds an hour. The 45 minutes is the gap between rounds, not the silence threshold — the README and the code are right ( |
|
Item 5 — consent obtained, and the source is now trimmed to what the easter egg needs. The author has confirmed this directly with the person it refers to: he has seen what the easter egg actually does, and he explicitly agreed it can ship as it is.
The consent is recorded in the source comments as well, so a reader of the package can see it without reading the PR. Nothing else about the easter egg changed. Optional 1, 4 and 5 are still open. |
… need (v1.5.0) PR MiniMax-AI#101 review item 5, second path: the person the easter egg refers to has explicitly consented to the easter egg shipping as it is, and that is now said in the PR. What goes away: the role and the interview remark were only there to explain the easter egg to the person who now consents to it. They are removed from the comments in chatter.mjs, lines.mjs, selftest.mjs, selftest_total.py, voice.md and CONTRACT-v3.md. What stays, because the effect needs it: RONNY_MARKS still recognises the full name, so a user who types it is understood; RONNY_FULL_NAME is still the ban list that stops her from ever saying it; the alias set she recognises and the way she addresses him are unchanged. The consent is recorded in the source comments too, so a reader of the package can see it without reading the PR. Version 1.4.0 -> 1.5.0 (plugin.json, package.json, README.md, README.zh-CN.md).
… comments (v1.6.0)
Addresses the reviewer's last "Optional" item: many source comments read like
the project's own change log, and some point at files that are not in the
package.
Trimmed (source comments only, no behaviour change):
- Dated / round-stamped notes. Every "2026-10-29", "第三十七轮",
"第二十六轮第三档第一项" style marker is gone; the decision, the reason
and the measured numbers stay.
- Change-log verbs attached to those markers ("老板 2026-10-29 改口",
"拍板", "改口") are replaced by what they actually assert.
- References to files that are not shipped: the persona source tree, the
sync scripts, the architecture/contract documents and the external
reference notes. They now read as plain prose.
Kept on purpose:
- Every mechanism explanation, the measured numbers and the reason a rule
exists.
- References to files that *are* in the package.
- "老板" where it names the user (it is what she calls them, and it appears
in runtime prompts and word lists).
Verification: npm run check 87/87; the package self-test still reports
851 checks passing with 0 failures; the design-library consistency check
passes with 0 broken path pointers.
|
Thanks for the second pass. The four must-fix items went into 1.4.0 and item 5 into 1.5.0. This push (1.6.0) closes the last optional item, and states where the other optional ones stand. Optional — the internal notes in the source comments (v1.6.0, this push) You quoted two examples: notes of the form "老板 2026-10-29 改口", and references to
Scope: 26 files, +325 / −327 lines — comments only. No code path, no prompt string and no word list was touched. Two things I deliberately kept, in case you read them as leftovers:
Verification: Where the other optional items stand
Version 1.6.0 ( |
MyPrototypeWhat
left a comment
There was a problem hiding this comment.
Thanks for the follow-up. 1.6.0 only changes source comments and the version, so items 1 to 4 stay fixed. On item 5, his role and the interview notes are gone. What's left is his full name in the recognition list and the blocklist, plus the nickname and the 傻白甜 line in the prompt and spoken lines. With his consent, that's fine.
npm run check passes (plugins/antianqi/mmx-octopus: OK, 87 tests). Approving. Thanks for working through all of this.
What it does
mmx-octopusputs a small octopus girl on your desktop. She is the visible body of theMiniMax Code Agent, and a chat partner of her own:
turn.started,message.committed,turn.finished) and switches expression:thinkingwhen a turn starts,workingwhile a task runs,celebratewhen a turn finishes with a real answer.fallback line naming the session.
and she answers in her own voice: short sentences, split into several bubbles.
mmx_say,mmx_mood,mmx_move,mmx_status.The floating window is frameless, transparent, always on top and click-through, so it never
blocks the desktop. Her body animation is 94 short alpha-channel WebM clips played through a
double-buffered
<video>pair, with a CSS-transformposetrack as the real fallback.Install
Copy the whole
mmx-octopusdirectory, including the hidden.minimax-plugindirectory,into your MiniMax Code data directory:
The default data directory is
~/.minimax, so the destination is normally~/.minimax/plugins/mmx-octopus/. Restart MiniMax Code, confirm the plugin is recognisedand enabled, and open MMX 章鱼娘 from the plugin list.
The package README carries the full description, including the
## Tested environmentand## Data & accesssections: the files read and written, the two files written outsidecontext.dataDir, the sessions read, the Agent turn it runs, the tools it calls, the networkhosts (the loopback address only), the processes it spawns (none), and the microphone (never).
Minimum client version
This package declares
agentAccess: ["session.read", "session.run"], so it needs MiniMaxCode 3.1.5 or later — an older client rejects the whole package instead of installing half
of it. The README names the version it was verified on under
## Tested environment.Test environment and results
~/.minimax/plugins/mmx-octopus/and opened in thedesktop client.
is drawn, and the WebM clip layer plays (
work-05.webmon the front buffer of thedouble-buffered pair).
client:
mmx_statusreturned her expression, bubble, window position, the Agent's runningstate and the recent action log;
mmx_moodswitched her expression;mmx_saypopped thebubble;
mmx_moveparked the window. The Host's own log shows it connecting themmx-octopusMCP server.npm run checkin this repository:plugins/antianqi/mmx-octopus: OK— no errors and nowarnings; the 87 repository tests pass.
negative-injection groups (13 runtime fault classes and 9 wiring fault classes).
Not verified: macOS and Linux. The window, the WebM clips and the Agent API are the same
everywhere, but I only ran this on Windows 11.
Notes for the reviewer
context.logger, not stdout. stdout belongs to theHost; the observation channel used
console.infofor its traces, and those are nowstructured
context.logger.info(code, fields)calls like the rest of the runtime.sources, so it cannot run outside it; this repository's rule is that the runtime payload is
exactly
miniapp/clientandminiapp/node.plus the README, the LICENSE and the plugin manifests.
is written under
context.dataDironly.One row added to the MiniApp table in both root READMEs.
Need help on this PR? Tag
@codesmith-botwith what you need.