Automate tasks on Android with Pocket Code Workflows: event triggers, cron scheduling on your phone, retries and a visual editor β no server, all on-device.
Every developer accumulates the same little chores: run the tests after a push, back up the database once a deploy lands, format on save, ping yourself when a build fails. On a laptop you glue these together with CI runners, cron jobs and a couple of shell scripts on a server somewhere. On a phone, the usual answer is "you can't." Pocket Code changes that with Workflows β an event-driven automation engine that lets you automate tasks on Android entirely on the device, with no server to rent and nothing to keep alive in the cloud.
A workflow is simple to describe: a trigger (an event inside the IDE, or a schedule) plus a sequence of steps that run against a shared context. That's enough to build real dev workflows β the kind you'd normally stand up a CI pipeline for β right next to your editor, terminal and database manager.
You never have to start from a blank canvas. The module gives you three on-ramps:
| Mode | How you create it | Example |
|---|---|---|
| Template | Tap Activate on one of the 8 built-in templates | "CI/CD Pipeline", "Auto-Deploy on Push", "DB Backup on Deploy" |
| AI Generate | Type a prompt, get an editable scaffold | "when push to main, deploy and notify" becomes a 2-step workflow |
| Editor | Tap the "+" FAB for the full form | Build from scratch with bindings and retry policies |
Activating a template clones it into an editable copy with a fresh ID, so you can tweak it without touching the original.
Workflows listen to events flowing through the IDE. The engine subscribes to the app's internal event bus and maps each event to a trigger type. There are ten trigger types:
| Trigger | Fires on | Typical filter |
|---|---|---|
GIT_PUSH | A completed push | branch ("main", "develop") |
GIT_COMMIT | A new commit | branch |
FILE_SAVED | A file save in the editor | extension (".kt", ".ts") |
APP_FOREGROUNDED | The app coming to foreground | β |
TERMINAL_COMMAND_FINISHED | A terminal command completing | command pattern |
DATABASE_QUERY_EXECUTED | A query result landing | table name |
DEPLOYMENT_COMPLETED | A successful deploy | provider ("vercel", "railway") |
DEPLOYMENT_FAILED | A failed deploy | provider |
ERROR_DETECTED | Another workflow failing | workflow name / error pattern |
MANUAL | Nothing β run by schedule or by hand | β |
Only enabled workflows whose trigger type matches enter evaluation, and an
optional filter narrows it further with a case-insensitive substring match β
so a GIT_PUSH workflow filtered to main ignores every other branch.
This is where "no-server automation" gets concrete. A workflow with a MANUAL
trigger and an attached schedule becomes a scheduled job. Under the hood the
scheduler wraps Android's WorkManager, and it offers two modes.
Interval schedules use a periodic work request. WorkManager's floor is 15
minutes, so shorter values are clamped up. The presets:
| Preset | Interval |
|---|---|
EVERY_15_MIN | 15 min |
HOURLY | 60 min |
EVERY_6_HOURS | 360 min |
Cron schedules are the interesting part. Pocket Code ships its own 5-field
cron parser (minute, hour, day-of-month, month, day-of-week) β no external
library β supporting * wildcards, single values, N,M lists, N-M ranges and
*/N steps. Two cron presets are built in:
DAILY_9AM β 0 9 * * *WEEKLY_MON_9AM β 0 9 * * 1Because WorkManager's periodic API can't express real cron, each cron run is
scheduled as a one-time job that re-arms the next fire when it finishes,
keeping the cron alive indefinitely. The schedule editor shows a live
"Next fire" preview computed from your expression, and turns red with
"Invalid cron expression" the moment the parse fails β immediate feedback before
you save. The parser deliberately keeps things simple in this version: month and
day names, ?, L, #, seconds and year are not supported.
Schedules are persisted, and are re-queued on app startup so a process death doesn't quietly empty your automation.
The editor is a full form: name, description, an enabled switch, a trigger
dropdown with an optional filter, and a vertical list of step cards you can
reorder, edit or delete. Adding a step opens a picker split into Control flow
(Wait, If / Else) and Actions β the eight action types, each with a
readable label and a dynamic config form:
| ActionType | Form fields |
|---|---|
RUN_COMMAND | command |
NOTIFICATION | title, message |
AI_ANALYZE | prompt, language (optional) |
AI_GENERATE | prompt, language (optional) |
GIT_OPERATION | operation (commit/push/pull), branch, message |
DEPLOY | branch (optional) |
DATABASE_BACKUP | command (optional) |
OPEN_FILE | file (path), line (optional) |
Each action step also has collapsible Reliability and Conditional sections (more on those below). Nothing hits the database until you press Save in the top bar β apply and cancel work on local editor state so you can experiment freely. Save is enabled only once the workflow has a name and at least one step.
The editor exposes Wait and one level of If / Else today. The engine itself
also executes Loop, Parallel and TryCatch steps, but a visual editor for
those is a known follow-up rather than a shipping surface β so treat them as
engine-level building blocks, not something you can drag in from the picker yet.
Steps don't run in isolation β they share a context, and any value field can
reference an earlier step with a {{binding}}. The syntax:
| Expression | Resolves to |
|---|---|
{{var.<name>}} | A context variable |
{{step.<id>.status}} | A step's status |
{{step.<id>.output.<field>}} | A field from a step's output |
{{step.<id>.error}} | A step's error message |
{{item.<alias>}} | The current item inside a loop |
{{trigger.eventName}} | The event that started the run |
An expression that doesn't resolve returns an empty string on purpose, so a
binding to a step that never ran (say, in a skipped conditional branch) doesn't
blow up the whole run. Conditions build on the same idea, with Equals,
NotEquals, GreaterThan, LessThan, Contains, IsNull and boolean
And / Or / Not operators comparing resolved values.
Automation you can't trust isn't automation. Every action step supports a retry policy and a timeout, surfaced in that collapsible Reliability section:
| Setting | Default |
|---|---|
| Max attempts | 1 (no retry) |
| Backoff strategy | EXPONENTIAL |
| Initial delay | 500 ms |
| Max delay | initial Γ 30 |
| Timeout | none |
Backoff comes in fixed, linear and exponential flavours (exponential
doubling: 500, 1000, 2000, 4000β¦), each capped at the max delay. Timeouts are
real coroutine timeouts β when one fires, the step is marked TIMED_OUT. There's
also a lightweight _when condition on individual actions: bind it to a
value and the step is skipped when that value is empty, false, 0 or null,
so you can gate a single step without wrapping it in a full conditional.
Every run is persisted with a full snapshot of its step results, which means the
history survives crashes. The Runs timeline lists runs newest-first with a
status icon, timestamp, step count, duration and a one-line error preview if
something failed. Tapping a run opens a step-by-step drill-down: per-step
status colour (success, failure, skipped, timed-out, running), the step's
duration, its output rendered as key=value pairs, and any error string.
Retention is automatic β the repository keeps the latest 100 runs per workflow and drops anything older than 30 days, so history stays useful without growing unbounded.
Eight immutable templates cover the common cases, so you can have working automation in one tap:
| Template | Trigger | Actions |
|---|---|---|
tpl_ci_cd | GIT_PUSH | npm test β deploy β notify |
tpl_auto_deploy | GIT_PUSH (main) | deploy β notify |
tpl_db_backup | DEPLOYMENT_COMPLETED | database backup β notify |
tpl_error_ai | ERROR_DETECTED | notify β AI "suggest a fix" |
tpl_auto_format | FILE_SAVED | prettier --write . |
tpl_auto_commit | FILE_SAVED | git add -A && git commit |
tpl_branch_protect | GIT_PUSH (main) | npm test β notify |
tpl_test_commit | GIT_COMMIT | npm test β notify |
If you'd rather not assemble steps by hand, the AI Generator turns a prompt
into an editable workflow. It reads keywords to infer a trigger ("push", "deploy
failed", "error", "save"β¦) and a sequence of actions ("deploy", "backup", "test",
"format", "notify"β¦), then shows a preview you can Save & enable or discard.
A prompt like "when push to main, deploy and notify" produces a two-step
workflow wired to GIT_PUSH on main. The generator also has an LLM-backed path
that uses your configured AI provider and falls back silently to the heuristic
parser if anything goes wrong β so you always get a preview or a clear
"couldn't infer" message.
Workflow definitions, run history and schedules live in a local database on
your phone. Definitions can be backed up to the cloud for restore, but nothing
in the cloud is ever read to run your automation β the engine executes locally,
period. Run history and schedules aren't synced at all: history is device-local,
and schedules are WorkManager state that's specific to each device. Your
automation is yours, and it runs where you are.
Pocket Code is heading to Google Play, bringing a full automation engine β triggers, cron-on-phone scheduling, retries and a visual editor β into the same app where you write and ship the code. Join the pre-registration to be among the first to try it on your own device.