<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Neo</title>
    <description>The latest articles on DEV Community by Neo (@neooriginal).</description>
    <link>https://dev.to/neooriginal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3931835%2Fe8c3372d-d2f2-48dd-b66a-7af4e3f699dd.png</url>
      <title>DEV Community: Neo</title>
      <link>https://dev.to/neooriginal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/neooriginal"/>
    <language>en</language>
    <item>
      <title>I built a self-hosted AI agent that runs as a system service and controls Android over ADB — here's the architecture</title>
      <dc:creator>Neo</dc:creator>
      <pubDate>Fri, 15 May 2026 11:00:00 +0000</pubDate>
      <link>https://dev.to/neooriginal/i-built-a-self-hosted-ai-agent-that-runs-as-a-system-service-and-controls-android-over-adb-heres-1hgi</link>
      <guid>https://dev.to/neooriginal/i-built-a-self-hosted-ai-agent-that-runs-as-a-system-service-and-controls-android-over-adb-heres-1hgi</guid>
      <description>&lt;p&gt;About a year ago I wanted an AI assistant that could actually automate my life — not just answer questions. I wanted it to send Telegram/Whatsapp messages, check my calendar, control my phone, run shell commands on my server, and schedule things&lt;/p&gt;

&lt;p&gt;I couldn't find something that did all of that and was actually self-hostable (openclaw is lacking features and wasn't popular at that time), so I built NeoAgent. This is a breakdown of how it works.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it is
&lt;/h3&gt;

&lt;p&gt;NeoAgent is a Node.js server you install with just two commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; neoagent
neoagent &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client is a Flutter app that works in the browser and on Android. Both connect to your own server — nothing routes through a third-party cloud.&lt;/p&gt;

&lt;h3&gt;
  
  
  The agent loop
&lt;/h3&gt;

&lt;p&gt;The core is a tool-calling loop. When you send a message, the server:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Loads context: relevant memories, recent run history, integration state&lt;/li&gt;
&lt;li&gt;Calls the configured AI provider (Anthropic, OpenAI, Gemini, Grok, or local Ollama)&lt;/li&gt;
&lt;li&gt;Executes any tool calls the model returns&lt;/li&gt;
&lt;li&gt;Feeds results back and repeats until the model stops requesting tools or a step limit is hit&lt;/li&gt;
&lt;li&gt;Writes the run steps to SQLite and streams them to the client&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The tools
&lt;/h3&gt;

&lt;p&gt;Here's what the agent can actually invoke:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shell and files:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;execute_command&lt;/code&gt; — a PTY-capable shell executor with stdin, timeout, stdout, stderr, exit code, and duration. Not &lt;code&gt;exec&lt;/code&gt;, a real PTY.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;read_file&lt;/code&gt;, &lt;code&gt;write_file&lt;/code&gt;, &lt;code&gt;edit_file&lt;/code&gt;, &lt;code&gt;list_files&lt;/code&gt;, &lt;code&gt;search_files&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Browser:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate, click, type, extract content, screenshot, and evaluate JavaScript in a server-side Chromium instance&lt;/li&gt;
&lt;li&gt;The browser runs inside a QEMU-backed Ubuntu VM, isolated from the host, or via a paired Chrome extension on a remote machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Android control:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the part that took the most work. NeoAgent can control a server-attached Android emulator or physical ADB device:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;android_screenshot&lt;/code&gt; — returns the current screen as an image the model can see&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;android_ui_dump&lt;/code&gt; — returns the UIAutomator XML for the current screen&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;android_observe_nodes&lt;/code&gt; — extracts clickable/typeable nodes so the model doesn't have to parse raw XML&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;android_tap&lt;/code&gt;, &lt;code&gt;android_long_press&lt;/code&gt;, &lt;code&gt;android_type&lt;/code&gt;, &lt;code&gt;android_swipe&lt;/code&gt;, &lt;code&gt;android_key&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;android_open_app&lt;/code&gt;, &lt;code&gt;android_open_intent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;android_wait_for&lt;/code&gt; — waits for a text, resource ID, or class to appear, up to a timeout&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;android_install_apk&lt;/code&gt;, &lt;code&gt;android_shell&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The emulator runs as part of the QEMU VM. When NeoAgent is deployed on a remote server, the AI controls the Android runtime attached to that server.&lt;/p&gt;

&lt;p&gt;A practical example: &lt;em&gt;"Open WhatsApp on the phone, find the conversation with [name], and read the last 10 messages"&lt;/em&gt; — the agent takes a screenshot, reads the UI tree, taps into WhatsApp, scrolls the conversation, and returns the messages as text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Messaging:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NeoAgent has a unified messaging layer that abstracts over 15 platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Telegram, WhatsApp, Discord, Slack, Google Chat, Teams, Matrix, Signal, iMessage/BlueBubbles, IRC, LINE, Mattermost, Twitch, Telnyx Voice&lt;/li&gt;
&lt;li&gt;Plus configurable webhook bridges for Feishu, Nextcloud Talk, Nostr, Synapse, WeChat, and others&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent tool is &lt;code&gt;send_message(platform, recipient, content)&lt;/code&gt;. Platform-specific details (credentials, API tokens) are configured server-side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integrations:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These are richer structured tools beyond basic messaging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google Workspace: Gmail, Calendar, Drive, Docs, Sheets&lt;/li&gt;
&lt;li&gt;Microsoft 365: Outlook, Calendar, OneDrive, Teams&lt;/li&gt;
&lt;li&gt;Notion: search, pages, blocks, databases&lt;/li&gt;
&lt;li&gt;Home Assistant: entity reads, service calls, config&lt;/li&gt;
&lt;li&gt;Trello, Spotify, Figma, Weather&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These connect via OAuth. Secrets are stored in &lt;code&gt;~/.neoagent/.env&lt;/code&gt; and never sent to the client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scheduled tasks:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tasks run on a cron schedule or in response to triggers. Each task has a prompt, a model override option, and optionally a Telnyx voice delivery for the result. You can schedule things like "every morning at 8, summarize my calendar for today and send it to Telegram."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP client:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NeoAgent registers as an MCP client. You can add remote MCP servers through the UI, and their tools become available in the agent loop alongside the built-in tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data and credentials
&lt;/h3&gt;

&lt;p&gt;Everything persists in SQLite under &lt;code&gt;~/.neoagent/data/&lt;/code&gt;. WAL mode is enabled for concurrent reads. The schema includes runs, messages, run steps, tasks, memory entries, recordings, health samples, and artifact storage.&lt;/p&gt;

&lt;p&gt;All AI provider keys and OAuth client secrets live in &lt;code&gt;~/.neoagent/.env&lt;/code&gt; on the server. The Flutter client authenticates to your backend with a session token — it never sees raw API keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's missing / known rough edges
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Android emulator boot is slow (it's a full QEMU VM). First boot also downloads a base Ubuntu image.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Trying it
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; neoagent
neoagent &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:3333&lt;/code&gt; in your browser. Set up an AI provider in Settings (or point it at Ollama for fully local). MIT license.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/NeoLabs-Systems/NeoAgent" rel="noopener noreferrer"&gt;https://github.com/NeoLabs-Systems/NeoAgent&lt;/a&gt;&lt;br&gt;
Docs: &lt;a href="https://neolabs-systems.github.io/NeoAgent/docs/" rel="noopener noreferrer"&gt;https://neolabs-systems.github.io/NeoAgent/docs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you build something interesting with it or hit a rough edge, I'd like to hear about it. &lt;br&gt;
&lt;strong&gt;Also its still a WIP, so please share any issues you encounter&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>agents</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
