Skip to main content
Glama

aCelery

Build and run your own JavaScript mini-apps on your phone — or have an AI assistant build them for you.

aCelery is a pocket app-maker for Android and iOS. An app is a folder of plain files — a manifest, an entry module, whatever CSS and assets you want. You can write one in the built-in editor, or point an AI assistant at the phone and describe what you want: it creates the app, runs it on the device, reads the console and the rendered page, and fixes what is broken. Apps talk to SQLite, the filesystem, the camera and gallery, and the network through a small capability API. No build step, no bundler, no account.

Originally an Android app (2014, GPLv3, Xavier Llamas Rolland), now one Flutter codebase for Android and iOS.


Build apps by describing them

aCelery runs an MCP server inside the app, at http://<phone>:8123/mcp. Any MCP client on the same network can connect to the phone directly — nothing is installed on the computer and nothing is exposed to the internet.

Using the aCelery MCP create an aCelery app that will manage my cooking recipes. Each recipe should show as a tabbed view with tabs for ingredients, procedure, photos, notes and source…

Given that prompt, Claude Desktop (Pro plan) created, ran and tested a working recipes app on the phone in about four minutes. A second test asked DeepSeek V4.1 Flash, through the Jan harness, for a books-read tracker that fills in bibliographic data and the cover photo from the Open Library API by ISBN. It delivered a working app for about US$ 0.13 of tokens (doc/app_creation_test.md; the two apps are in doc/AI_Created_Apps/, as project zips).

What the assistant can do, as MCP tools:

Tools

Author

list_apps, read_app, read_file, create_app, write_file, delete_file, delete_app

Run and observe

run_app, read_console, read_dom, take_screenshot (Android), eval_js, close_app

Data

list_databases, query_db (read-only, bound parameters), exec_db

It also gets the material it needs to write correct code the first time: a written guide to the aCelery API (acelery://guide), the live project files (acelery://apps/…), a create_acelery_app prompt, and the Example app as a worked template. run_app reports whether the app started or failed — with the file, line and column of a syntax error — together with what the console said. The assistant sees the same evidence you would, on the real device WebView, and iterates until it works.

Connecting. Settings → Network access → Connect an assistant mints a key and shows a ready-made command for Claude Code and a configuration block for Claude Desktop:

claude mcp add --transport http aCelery http://<phone>:8123/mcp \
  --header "Authorization: Bearer <key>"
  • Works with clients that connect from your network: Claude Code, Claude Desktop (through the small mcp-remote bridge the app generates the configuration for) and harnesses such as Jan. Other clients that dial out from your machine should work too.

  • Claude on the web and mobile cannot reach a phone on a home network; those connectors originate in Anthropic's cloud.

  • Keys are per client, shown once, listed in the app and revocable. A key is always required on /mcp, requests carrying a browser Origin are refused, and writes are confined to your apps and databases.

  • Sharing must be switched on. On Android it keeps working with the screen off. On iOS the connection lasts while aCelery is on screen.

Details: doc/mcp-server.md.

Related MCP server: Argent

What you get on the phone

  • Home, Apps, Code, Data, Settings — a Continue card that picks up where you left off; every app as a card you can run, export or pin to the home screen (Android).

  • A real code editor — CodeMirror 6, with highlighting, folding, search, autocomplete and undo, designed for touch. Run saves first and launches the app on the device; a debug run adds an error log.

  • App management — App details sets an app's icon (picked and cropped on the device), name and description; Add files copies pictures, data or scripts from the device into a project.

  • A database manager — browse and edit tables built from their real columns, see their structure, or run SQL.

  • Share on your network — the same server answers a browser on your computer, so you can use the full IDE and your apps from a desktop. New devices must be approved on the phone, and each gets its own revocable key.

  • Back up and restore — databases, app files and the apps themselves in one zip; export and import single projects.

  • Themes — 18, with light and dark, applied to your apps as well as the shell.

Writing an app by hand

Two bare-name imports, resolved by an import map. htm compiles its templates at runtime, so the file you write is the file that runs.

import { openDB } from "acelery/sql.js";
import { html, render, Panel, Input, Form, notEmpty } from "acelery/ui.js";

export default async function main() {
  const db = await openDB("notes.db");
  await db.exec("create table if not exists note (body text)");

  render(html`
    <${Panel} title="Notes">
      <${Form} onSubmit=${(v) => db.insert("insert into note (body) values (?)",
                                           [v.body])}>
        <${Input} label="Note" name="body" validate=${[notEmpty()]} />
      <//>
    <//>`, document.body);
}

acelery_app.json names the entry module (main.js if it does not say). The capability modules an app can import:

Module

For

acelery/ui.js

Preact, Bootstrap-based widgets, forms with validation, and TableMaint — declare fields and get a working list / record / edit / search screen over a SQLite table, with linked child tables

acelery/sql.js

SQLite with bound parameters

acelery/file.js

files in the app's sandbox, including binary

acelery/picker.js

files and photos from the camera or gallery, with cropping and shrinking

acelery/http.js

the network

acelery/export.js

sharing files and leaving the app

acelery/chart.js

Chart.js charts (opt-in)

acelery/datatable.js

sortable, searchable, paged tables, answered from SQLite (opt-in)

The full guide is doc/user-guide.md, printed into the app as a PDF under Settings → About; the Example app is the reference implementation.

How it fits together

The Flutter side is a thin host. The product is the web bundle.

Flutter shell  ──►  WebView  ──►  http://127.0.0.1:8123
  (lib/)                             │
                                     ├─ static:  bundle/www/…
                                     ├─ /android.itf:  the capability bridge
                                     │    sqflite · dart:io · http · archive
                                     └─ /mcp:  the assistant's tools

Everything a user app can do goes through that one HTTP origin, local and remote alike. That is why a browser on another machine gets the same IDE and the same apps, and why an assistant sees exactly what the app sees.

Directory

What it is

lib/

the Dart host: server, /android.itf bridge, /mcp server, WebView shell

bundle/

the web bundle — source of truth, packed into assets/aCelery.zip

bundle/www/system/

the shell: Home, Apps, Code, Data, Settings, and the launcher

bundle/www/user/Example/

the sample app, and the reference for writing one

web/

JS/CSS sources built into bundle/www/tools/

doc/

the user's guide, the MCP server notes, and design records

tool/

the build scripts

Built on Preact 10 + htm, react-bootstrap, Bootstrap 5.3, CodeMirror 6, Chart.js and DataTables, as ES modules with an import map.

Running it

flutter pub get
flutter run                      # Flutter 3.41+ / Dart 3.11+

After editing anything under web/ or bundle/:

(cd web && npm install)          # once
sh tool/build_js.sh              # web/src → bundle/www/tools/
sh tool/build_bundle.sh          # bundle/ → assets/aCelery.zip

After editing doc/user-guide.md, reprint the PDF that Settings → About links to. It needs Chrome, Chromium or Edge on the machine; the output is committed, so a checkout without one still packs a working bundle.

node tool/build_guide.mjs        # doc/user-guide.md → bundle/www/system/doc/

Then bump ACeleryRuntime.bundleVersion so installed devices pick the change up. A test fails if the zip goes stale, another if the built JS does, and another if the guide PDF was never reprinted.

flutter test                     # the host, the bridge, and the bundle's shape
(cd web && npm test)             # the widget layer, against the built bundle

Hot reload will not do it. The bundle is unzipped on launch and the JS is vendored, so a full rebuild and reinstall is the only way to see a bundle change on a device.

In a desktop browser

Two ways, and they test different things.

adb forward tcp:8123 tcp:8123     # then open http://localhost:8123/

Reaches the app on a device or emulator, with DevTools. adbd connects from 127.0.0.1 inside the device, so the request counts as loopback and skips pairing. That makes it the quick way to drive the UI — and it exercises the remote JavaScript path, because a browser has no ACeleryHost, so Run opens the launcher in a tab rather than pushing a Flutter route.

dart run tool/serve.dart --share  # then open http://<this machine>:8123/

Runs the real server here, against a throwaway copy of the bundle in a temp directory. Reaching it by this machine's own LAN address means the request arrives from a non-loopback address, which is the only way to exercise pairing from one machine. The approval prompt that would appear on the device is printed to the terminal and answered there.

Do not leave the adb forward in place while tool/serve.dart runs: both can bind at once — adb takes 127.0.0.1:8123, the script takes *:8123 — and macOS prefers the more specific one, so localhost quietly reaches the emulator while the LAN address reaches the script.

Status

Verified on Android (emulator and device). Not yet verified on iOS — in particular the native date pickers. The design records behind the port and the web bundle are in doc/ (web-bundle-port-plan.md, js-ui-framework-evaluation.md, shell-redesign.md).

A note on original/

The 2014 Android app, its aCelery_content/ tree and the source aCelery.zip live in original/, which is not in this repository — it is listed in .gitignore. The documents in doc/ cite it throughout (aCeleryAndroidInterface.java, aCeleryUnzip.java, original/assets/), so those references will not resolve from a fresh clone.

Licence

GNU General Public License v3.0 — see LICENSE. This is the licence the 2014 sources were released under, and the headers in xscript5/ and the original Android app carry it; the file makes it explicit rather than implied.

The LICENSE file is the verbatim FSF text. Its closing section is the standard "How to Apply These Terms" appendix, so the <year> and <name of author> placeholders in it are instructions, not blanks to fill in.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Enables AI assistants to automate mobile app testing and development for iOS and Android through natural language interactions. Supports intelligent element identification, session management, automated test generation, and comprehensive device interactions including clicks, swipes, screenshots, and app management.
    31
    9,307 npm
    484
    Apache 2.0
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI assistants to interact with iOS Simulators and Android Emulators, allowing autonomous app development, UI interaction, profiling, and debugging through natural language.
    77
    2,958
    Apache 2.0
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to build, drive, and observe Android/KMM apps end-to-end through ADB and Gradle, with tools for UI automation, error capture, and testing.
    33
    84 npm
    MIT