aCelery
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 |
|
Run and observe |
|
Data |
|
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-remotebridge 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 browserOriginare 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 |
| Preact, Bootstrap-based widgets, forms with validation, and |
| SQLite with bound parameters |
| files in the app's sandbox, including binary |
| files and photos from the camera or gallery, with cropping and shrinking |
| the network |
| sharing files and leaving the app |
| Chart.js charts (opt-in) |
| 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 toolsEverything 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 |
| the Dart host: server, |
| the web bundle — source of truth, packed into |
| the shell: Home, Apps, Code, Data, Settings, and the launcher |
| the sample app, and the reference for writing one |
| JS/CSS sources built into |
| the user's guide, the MCP server notes, and design records |
| 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.zipAfter 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 bundleHot 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.
This server cannot be deployed
Maintenance
Related MCP Connectors
- MaketaOAuthpro.maketa
Build and edit app screen mockups and clickable prototypes from your AI assistant.
Build, validate, deploy — HTTP APIs, cron jobs, webhooks and MCP tools — from your AI client.
Deploy and host the apps your AI assistant builds — a real server, database, and shareable URL.
AppDeploy turns app ideas described in AI chat into live full-stack web applications
Related MCP Servers
AlicenseAqualityAmaintenanceEnables 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.319,307 npm484Apache 2.0
Argentofficial
AlicenseAqualityAmaintenanceEnables AI assistants to interact with iOS Simulators and Android Emulators, allowing autonomous app development, UI interaction, profiling, and debugging through natural language.772,958Apache 2.0- FlicenseNot gradedqualityCmaintenanceEnable AI agents to autonomously build and deploy full-stack mobile applications.1-
- AlicenseAqualityCmaintenanceEnables 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.3384 npmMIT