jev-chat-JARVIS Reads Your Screen by Pretending to Be a System Service, and Says So in the README
An MIT-licensed Android app on today's trending board uses a malware evasion technique to read WeChat, discloses it plainly, and in doing so shows you exactly what is wrong with how agents get access to anything.
Somewhere in the adapter table of a 3.6k-star Android repository sits a sentence that stops you cold if you know what you are reading. It describes how the app handles WeChat:
服务类名伪装成系统的
SelectToSpeakService
The service class name is disguised as the system's SelectToSpeakService.
That is the app renaming its own accessibility service to impersonate an Android platform component, because WeChat obfuscates its UI nodes against ordinary accessibility services and does not obfuscate them against that one. It is the same shape as the trick a piece of Android spyware uses to survive a user glancing at their accessibility settings.
The project is Finderchangchang/jev-chat-JARVIS, MIT licensed, copyright 2026 Finderchangchang and the jev-chat contributors, v1.3 tagged September 22. It is not spyware. It puts the masquerade in a table in its own README and repeats it in the known-limitations section, noting that a WeChat version update could break the technique at any time. Its "why use it" list opens by promising it does not hook anything, does not modify packages, does not touch any app's API or account system, and does not read any database.
Both things are true at once. That is the problem worth writing about.
What the app actually does
The pitch is narrow and, I think, genuinely well judged. You are chatting in WeChat, QQ, X, or Feishu. A translucent overlay reads the conversation currently on screen, sends it to a typed decision model for judgment, and shows you a panel with the other person's real intent, a danger rating from 1 to 9, what they want, whether you should reply right now, and three ranked reply candidates.
The ordering matters more than it sounds. From the README: "它先判断,再写字", which translates as "it judges first, then writes." Most tools point a generative model at a conversation and ask it to produce a reply. This one runs a typed decision pass first, seven questions in a single request, roughly one second, with a confidence figure attached, and only then drafts candidates conditioned on that judgment. The decision model then re-ranks the three drafts.
It never sends. That is stated three separate times in the README, with the mechanism named: the selected reply is written into the input box with ACTION_SET_TEXT, falling back to clipboard plus ACTION_PASTE if that fails, and "任何情况下都不发送", meaning under no circumstances does it send. It explicitly refuses to touch transfers, red packets, or payment requests.
The capture layer is one adapter per app, dispatched by foreground package name, and the adapter table is a small education in how differently four chat apps expose themselves:
- QQ leaves nodes open with stable IDs. Read
id/mjnfor body text,id/371for the title, decide who spoke by which side the avatar sits on. - WeChat obfuscates nodes against normal accessibility services. Hence the masquerade, then read
id/bklbubbles and judge by left versus right. - X uses Compose, so there are no IDs and the text field is empty. The adapter parses
content-descstrings shaped like "sender: body. time. Read." - Feishu draws its message bodies itself, so the accessibility tree holds bubble rectangles and no text at all. Since v1.3 the app screenshots each rectangle and runs ML Kit's offline Chinese OCR on it.
That Feishu case is the one I keep thinking about. When an app custom-draws its UI, the accessibility tree becomes useless and the only remaining way in is to photograph the screen and read the pixels. The app's answer to a platform closing the structured door is to go through the window with an OCR model. Adding OCR grew the APK from roughly 12 MB to roughly 27 MB, arm64-v8a only.
The thing this repo demonstrates
Screen reading is becoming the universal integration layer for on-device agents, and the accessibility API is the only door.
Think about why. An agent that wants to help you inside an app you already use has three options. It can use the app's API, which for WeChat means it cannot. It can hook or patch the app, which gets you banned and requires root. Or it can read what is rendered, which requires no cooperation from anyone and works on every app ever written.
The third option wins on capability every single time. So that is where the agents go.
But the accessibility API was designed in a different era for a different purpose: to let screen readers help blind users. It was never built as a trust boundary. It has no notion of an app consenting to be read, no concept of scope, no way to grant "read this one conversation" instead of "read every pixel of every app forever." It is one switch, and it is all or nothing.
And here is the part that should bother you. Android cannot distinguish jev-chat-JARVIS from actual spyware. Both request the same permission. Both use a plausible-looking service name. Both read the screen continuously in the background. The only difference is disclosure, and disclosure lives in a README that the operating system never reads and most users never open.
WeChat's obfuscation is a reasonable defense that fails for the same reason. It cannot tell a hostile reader from a helpful one either, so it blocks both, and the helpful one routes around it by impersonating a system service. That escalation has no obvious next move that is not worse.
I want to be fair to the author here, because the disclosure is not a technicality. Putting your evasion technique in a table in your own README, in a project you are soliciting sponsorship for, is a choice with a cost. The app also does several things right that a careless version would not: keys live in app-private storage, there is no first-party server anywhere in the design, chat content goes only to the API endpoint you configured at the moment you trigger analysis, history logging is off by default, and the knowledge base and history live in an app-private directory with a one-tap wipe. If you are going to build this, this is roughly how to build it.
The problem is not this author. The problem is that the platform gives an honest author and a dishonest one the exact same tools and the exact same appearance.
Put this into practice
You probably do not want to install this app, and I am not suggesting you do. There are three things worth taking from it.
Read the adapter table before you build any screen-reading agent. It is a four-case taxonomy of how UIs expose themselves: open nodes with IDs, obfuscated nodes, Compose with descriptions only, and custom-drawn with nothing. Your integration strategy is determined entirely by which case you land in, and the fourth case means you are building an OCR pipeline whether you planned to or not. The README's "adapting a new chat app" section is about thirty lines and tells you to start with adb shell uiautomator dump to see what a target actually exposes. Do that first, before you design anything.
Steal the judge-then-draft ordering. This is the transferable architectural idea and it has nothing to do with Android. A typed decision pass that answers a fixed set of questions in one request, returning intent, risk, and a should-I-act-now verdict, then a generative pass conditioned on that judgment, then the decision model re-ranking its outputs. The judgment is cheap, fast, and structured enough to log and audit. The generation is expensive and unstructured. Putting the cheap structured thing first and letting it gate the expensive one is a pattern that works anywhere you have an agent choosing whether and how to act.
Audit your own accessibility settings tonight. Open Android's accessibility settings and look at what is enabled. If you see something named like a system service that you do not remember turning on, you now know that a service name proves nothing. That is the practical lesson and it took a well-intentioned open-source project to make it concrete.
If you do want to run it: Android 11+, one OpenRouter API key in the judgment slot is the minimum viable setup because the reply and vision slots inherit it when left blank, and on Xiaomi or HyperOS you must enable autostart and unrestricted battery or the background service gets frozen and reads nothing.
Honest limitations
I did not install this app or run it. Everything above is a reading of the repository's own documentation, in Chinese, plus a cache-busted check of its license, star count and release tag. The README describes what the code is meant to do; I did not verify that the code does it. In particular I did not confirm that the app never sends a message, never touches a payment flow, or never writes chat content to disk. Those are claims, made by the author, in a document the author controls.
The README's own limitations section is unusually frank and you should read it rather than my summary. The highlights: Chinese ROMs freeze the background process despite foreground-service keepalive, so the bubble vanishes and you have to poke the chat to revive it. Feishu's speaker attribution is inferred from read status and gets it backwards sometimes. The X adapter was only tested against a Chinese-language interface; English is a fallback path that has not been verified. Group chats are analyzed as if they were one-to-one, so the whole "the other person" framing is wrong there. Knowledge base retrieval is tag and title substring matching with no semantic search, capped at five notes. OCR only reads what is visible on screen, misses truncated long messages, makes character errors, and cannot capture FLAG_SECURE windows at all.
And the one the author states plainly about the model underneath: "Jev 主训练语言是英文", meaning Jev's main training language is English. The app sends its questions in English and keeps the chat content in Chinese, and the README recommends you calibrate against a batch of your own real conversations using the Python scaffolding in tools/jev/. That is an honest disclosure of a real gap, and it means the danger ratings on Chinese conversations are an open question that the project is asking you to close yourself.
Two things I could not resolve. Every badge and link in the README points at a jev-chat/jev-chat-jarvis organization repo rather than the Finderchangchang path I read, so the two may be mirrors, a rename in progress, or something else, and I did not establish which is canonical. And the README carries a sponsors table with two paid placements plus a donation QR code, which does not make anything in it false but is worth knowing when you weigh a project's self-description.
I also want to be explicit that I take no position on whether the WeChat masquerade is acceptable. The author frames the app as only reading chats on your own device that you already have the right to see, and includes a disclaimer pointing at each platform's terms of service and local law. That is a real argument. Whether it survives contact with WeChat's terms is a question for someone with a different job than mine.
Where that leaves you
The interesting thing on today's board is not a model. It is a 27-megabyte Android app that had to impersonate a system service to do something reasonable, told you it did, and is now indistinguishable from something unreasonable that would not have told you.
Every on-device agent is heading through that same door, because it is the only door. Go look at what you have already let through it.
Sources: Finderchangchang/jev-chat-JARVIS README · Trendshift daily board
Medium metadata
- Title: jev-chat-JARVIS Reads Your Screen by Pretending to Be a System Service, and Says So in the README
- Subtitle: An MIT-licensed Android app on today's trending board uses a malware evasion technique to read WeChat, discloses it plainly, and in doing so shows you exactly what is wrong with how agents get access to anything.
- Tags: Android, AI Agents, Security, Accessibility, Open Source
- Canonical: import from the fervorai.dev URL