This post is meant to document a project I’ve almost finished working on recently:weixin-household-gateway。
Project Address:
github.com/thekfjie/weixin-household-gateway
Simply put, it’s a home gateway that integrates the Codex/AI backend into WeChat.
It’s not a web-based agent, nor is it simply a chatbot; rather, it’s a WeChat gateway deployed on my own server: I can use it within WeChat to manage servers, code, files, and attachments, and I can also let my family members use it to have casual AI conversations in a relatively secure way.
This is so complicated...
1. Why are we doing this?
My initial idea was actually quite simple: I usually run a lot of things on my server—blogs, APIs, music analysis, and all sorts of other random services. If I’m out and about and want the AI to take a look at some logs, tweak a configuration, or analyze a file, the most natural way to do that isn’t through a web page, but through WeChat.
In addition, I had another idea: I wanted to share my model with my family so they could use certain large models in the most convenient way possible, without having to worry about internet connectivity, the learning curve, or other factors... Naturally, WeChat became the best solution for this.
Because WeChat is always online.
At the same time, WeChat released an official API earlier this year: WeChat OpenClaw (🙏)
But I don’t want to use a token-heavy service like OpenClaw—my weekly quota definitely wouldn’t be enough for it (🙏)—and just throwing an agent directly into WeChat definitely won’t work. The chat experience on WeChat is completely different from that of a web console:
- WeChat does not allow you to refresh a single message in place.
- WeChat does not support streaming output.
- If there are too many short updates, they’ll flood the feed.
- Family members should not have the same permissions as the admin when using the system.
- You must clearly define the boundaries for server operations, file access, `sudo`, and Docker.
Therefore, the ultimate goal of this project is not to “move the web agent into WeChat,” but to build an AI gateway that is better suited to the WeChat environment.
2. What does it look like now?
Overall, it is a single TypeScript/Node.js service deployed on a Linux server. The core architecture looks something like this:
flowchart TB
USER["微信用户"] --> ILINK["iLink 轮询"]
ILINK --> WORKER["WechatWorker"]
WORKER --> ROUTE{"角色与任务路由"}
ROUTE -->|admin| ADMIN["Admin ACP 持久会话"]
ROUTE -->|family 普通聊天| API["Family API 直连"]
ROUTE -->|family 复杂任务| FACP["Family ACP 非持久任务"]
ADMIN --> CODEX["Codex / ACP / CLI"]
API --> MODEL["OpenAI-compatible API"]
FACP --> CODEX
CODEX --> FILTER["输出过滤与分段"]
MODEL --> FILTER
FILTER --> SEND["iLink 回复微信"]
WORKER --> DB["SQLite 会话与消息"]
WORKER --> FILES["inbox / office / outbox 工作区"]
It does things like this:
- Poll for iLink WeChat messages.
- Identify Account Roles:
admin/family。 - Select either the API or ACP based on the task type.
- Download the WeChat attachment and place it in the controlled workspace.
- Call Codex to process the task.
- Send the results back in a format that WeChat can handle.
- Use SQLite to store account information, sessions, messages, and attachment records.
The deployment directory is now fairly fixed:
/opt/weixin-household-gateway
/var/lib/weixin-household-gateway
inbox/
office/
outbox/
~/.codex
Among them inbox It is an incoming attachment,office It is the intermediate processing area,outbox These are the final files that can be sent back via WeChat.
3. Why are “admin” and “family” separated?
This is the point I consider most important in this project.
admin It’s for my personal use. By default, it uses ACP persistent sessions, making it suitable for server maintenance, code modifications, long-running tasks, and multi-step tool invocations. It can access more context and perform more advanced operations once I’ve explicitly configured it.
family It’s for family use. By default, it prioritizes the direct API connection, which handles regular chats, image recognition, and simple Q&A. Only when dealing with compressed files, Office documents, complex attachments, or tasks that require tool-based processing does it escalate to ACP—and even then, it uses non-persistent ACP.
The reason for doing this is quite practical:
- Family members do not need access to server administration privileges.
- Casual chat shouldn’t involve going through a whole toolchain just to “sound like an agent.”
- API routes are faster and make it easier to maintain context caching.
- ACP is suitable for tool-based tasks, but it should not become the default session mode for the family.
In the end, it turned into a fairly reasonable rule:
| Scene | Default Path | Note |
|---|---|---|
| admin Operations/Code/Long-running Tasks | ACP Persistent Session | For my own use |
| family General Chat | Direct API Connection | Faster, Safer |
| family files/attachments—complex tasks | ACP Non-persistent | When you’re done, return to the API main track |
This design underwent numerous revisions along the way. In particular, regarding the “family” context, initially only the most recent messages were retrieved, which resulted in a very poor user experience and made caching ineffective. Later, we switched to a separate API context track with a budget of approximately 100,000 characters, aiming to keep the prompt cache key as stable as possible so it wouldn’t feel like starting from scratch every time.
4. There is no true streaming output in WeChat
This is another really frustrating part.
On a web page, you can refresh on a token-by-token basis and scroll line by line in the terminal. But WeChat doesn’t work that way. In WeChat, you can only send messages; you can’t elegantly edit the same message. If you force it to send token by token, it will just flood the screen.
So, in the end, we went with a “quasi-streaming” approach that’s better suited for WeChat:
- The admin ACP has process output enabled by default.
- The ACP family does not enable process output by default.
- The family API does not enable early segmentation by default.
- Ultimately, the answers will still be grouped into segments based on their length.
The general strategy at this point is:
| Mode | Default procedure output | Note |
|---|---|---|
| admin-acp | Open | You can see what it’s doing, making it suitable for long tasks |
| family-acp | Close | By default, only the final result is shown. |
| family-api | Close | Prioritize general chat until a complete answer is provided |
At first, I also wondered if this platform could truly be “stream-like,” but later realized that what matters most in WeChat chats isn’t whether it technically resembles a stream, but whether it feels natural to users.
For example, in the admin long-running task, I can accept it sending a message every so often:
我看完主链路了,现在项目是一个 TypeScript/Node 单服务。
This is much more pleasant than just sitting around for 30 seconds while it says “Thinking.”
But if the “family” group posted like that too, it would look really strange—like a robot dumping out all its internal construction logs.
So, in the end, we categorized them by role.
5. The ACP line is the hardest to deal with.
The really tough parts of this project are mostly in ACP.
ACP isn’t simply a matter of “calling the model once and getting a string.” It continuously outputs events:
- status
- thinking
- responding
- tool progress
- visible message run
- usage update
- prompt result
The most frustrating part is:visible_message_run It isn’t necessarily the final answer. It could be a step-by-step guide, or it could be text that ultimately proves useful to the user.
Therefore, a dedicated collector was implemented in the project to filter out ACP events and then determine which ones should be sent to WeChat, which ones should be used only for internal state tracking, and which ones should be treated as final answers.
Later, we encountered another very common issue: the final step of the ACP doesn’t always return results in a timely manner. If the project throws an exception as soon as it times out, the front end won’t wait for this round, and subsequent results won’t be received. In the end, we had to rework the handling of timeouts, cancellations, and completion results so that the system would at least provide a clear status, rather than making it seem to the user as if the process had “suddenly disappeared.”
This kind of problem is annoying, but it’s also very real.
Because once you integrate AI into WeChat, it’s no longer just a function call—it’s something that’s actually chatting with people. If it freezes, goes silent, repeats itself, or breaks the conversation into random segments, users will notice.
6. I’ve run into quite a few pitfalls with permissions and sandboxes as well
This project really does involve working with servers!!!
Therefore, permissions are divided into several levels:
- The project’s own role strategy.
- Permission review for the “family” small model.
- Permission request for Codex ACP.
- Linux Users and sudoers.
- Codex’s own sandbox.
When these layers are stacked on top of each other, a classic scenario emerges:
Even though the project has already granted the admin sudo privileges, the Codex sandbox is still blocking it.
I later discovered that, under Linux, Codex’s default sandbox uses `bubblewrap` (`bwrap`), and it may include NoNewPrivs=1. Even if the sudoers file for the user is set to allow access, sudo may still fail.
So now the installer handles a few things:
- Testing
bubblewrap/bwrap。 - Create compatible soft links as needed.
- admin Configuration in Maintenance Mode
danger-full-access。 - family: Do not omit this parameter.
- The Codex trusted project only trusts the project directory and the admin runtime; it does not trust
/。
The principle here is also quite simple:
“admin” is my operations portal—it needs to be robust; “family” is my home portal—it needs to be stable and streamlined.
7. Document Tasks: You can do them, but don’t just do them haphazardly
Another very common use case on WeChat is sending files.
For example, if you send a compressed file, a Word document, an Excel file, or an image and want the AI to take a look at what’s inside, this project will download the attachments to inbox, and then decide whether to upgrade to ACP based on the type.
But there are pitfalls here, too.
For example, there was a file that looked like a ZIP file but actually contained data more similar to RAR5, and I didn’t have a suitable RAR reader on my computer. After the model went through a few iterations, it tried to... apt-get update I installed the tool, but of course, the “family” policy wouldn’t allow it.
So now, the design of “family” leans more toward:
- If it can be handled with existing tools, do so.
- When you need to perform system-level operations—such as sudo, Docker, or systemctl—don’t try to take a roundabout approach.
- Content displayed to users must be filtered to remove paths, command fragments, and suspected internal reasoning.
Otherwise, if a family member just wants to look at a document but ends up receiving a bunch of photos from a server construction site, that would be way too abstract.
8. What did this project ultimately accomplish?
To sum it up in one sentence:
It transforms Codex into a role-based, deployable home AI gateway that can be used via WeChat and is capable of handling files and long-running tasks.
Its most important capabilities at this time include:
- Support for multiple WeChat accounts.
- admin / family permissions.
- family: Priority for general chat API.
- family: Automatically escalate complex tasks to ACP.
- admin ACP persistent session.
- WeChat-friendly formatted output.
- Configurable process output.
- File downloads and file uploads.
- SQLite session storage.
- Codex Configuration Generation.
- Linux installation scripts, systemd services, and doctor self-checks.
- The prompt template is external, making it easy to modify later.
There are also some things that may seem insignificant but actually have a big impact on the user experience:
/newNew conversation./outputControl the process output.- API context quota and cache hits.
- ACP Final Answer Extraction.
- Cancellation and Wrap-Up After a Timeout.
- “family” output filtering.
Taken individually, these features aren’t particularly impressive, but when combined, they transform the WeChat experience from “just functional” to “something I can tolerate—and am even willing to keep using.”
9. Areas That Still Need Improvement
Of course, it’s not a perfect product yet.
The outstanding issues I’m currently aware of are:
- WeChat messages don’t have a true delivery confirmation. (The ACP workflow is still a bit odd.)
- The ability to recall or edit messages hasn’t been implemented yet. (When will WeChat give us that feature?!)
- ACP events may continue to change in the future, so we’ll need to adapt accordingly.
- The security policy for “family” still needs to be monitored in real-world usage scenarios. (There are always strange issues.)
- The prompt still needs some fine-tuning; it’s impossible to write it all in one go. (I’m not a pro at prompts, by the way.)
But at least it has evolved from “a rather obvious idea” into something that can be deployed, updated, explained, and maintained.
This journey really is like climbing a mountain.
There are a lot of small but annoying pitfalls along the way: segmented monsters, lost context, ACP not wrapping up, sudo being blocked by the sandbox, inconsistent names in bubblewrap, switching back and forth between the API and ACP, and being unable to hit the family cache…
The good news is that most of them have already been pressed one by one.
10. Finally
In short,weixin-household-gateway We’re now nearing the point where we can wrap things up.
If I keep tinkering with this in the future, I’ll probably continue making gradual improvements focused on message recall, file handling capabilities, ACP event adaptation, and a more user-friendly output experience. I think the foundation is solid enough now, right? I hope so...
I handled a lot of boundary conditions:
Boundaries regarding permissions, context, output, and usage among family members—as well as the limit of whether I can continue to maintain this myself.
I’ll stop here for now.
Finally, I can put up a little sign for this unfinished project.

