No description
  • Kotlin 99.5%
  • Python 0.2%
  • Shell 0.2%
  • Java 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Morten Olsen d713b8bda1
All checks were successful
ci/woodpecker/push/compliance Pipeline was successful
ci/woodpecker/push/quality Pipeline was successful
ci/woodpecker/push/draft-release Pipeline was successful
ci/woodpecker/tag/release Pipeline was successful
ci/woodpecker/cron/renovate Pipeline was successful
docs(agents): write one close trailer per issue
Forgejo parses only the first issue reference in a commit trailer, so a
comma-separated list closes the first and silently leaves the rest open.
2026-09-17 14:29:44 +02:00
.woodpecker fix(release): sign Android APKs 2026-09-15 23:39:36 +02:00
app feat(editor): reorder, extend and copy steps on a route projection 2026-09-17 14:14:08 +02:00
authoring refactor(build): extract :authoring for the LAN and ADB transport 2026-09-17 12:20:17 +02:00
catalog feat(editor): reorder, extend and copy steps on a route projection 2026-09-17 14:14:08 +02:00
contract refactor(contract): move the workflow codec into :engine 2026-09-17 12:48:23 +02:00
design-system feat(editor): reorder, extend and copy steps on a route projection 2026-09-17 14:14:08 +02:00
docs docs(architecture): record the first improve pass 2026-09-17 13:04:58 +02:00
engine feat(editor): reorder, extend and copy steps on a route projection 2026-09-17 14:14:08 +02:00
gradle/wrapper update 2026-09-15 20:15:25 +02:00
persistence test(persistence): hold both port adapters to one conformance suite 2026-09-17 12:58:31 +02:00
platform refactor(platform): declare each device reading once 2026-09-17 13:03:51 +02:00
scripts build(scripts): measure cross-module imports by declaring module 2026-09-17 12:20:18 +02:00
.gitignore fix(release): sign Android APKs 2026-09-15 23:39:36 +02:00
.taskrc.yml ci: add Android release pipeline 2026-09-15 22:53:33 +02:00
AGENTS.md docs(agents): write one close trailer per issue 2026-09-17 14:29:44 +02:00
build.gradle.kts refactor(build): extract :contract and :engine as pure-JVM modules 2026-09-17 11:09:05 +02:00
CLAUDE.md docs: move roadmap to Forgejo issues 2026-09-16 01:11:24 +02:00
DESIGN.md feat(editor): reorder, extend and copy steps on a route projection 2026-09-17 14:14:08 +02:00
ENGINE.md feat(editor): reorder, extend and copy steps on a route projection 2026-09-17 14:14:08 +02:00
gradle.properties support android studio 2026-09-15 21:51:57 +02:00
gradlew support android studio 2026-09-15 21:51:57 +02:00
gradlew.bat init 2026-09-15 14:58:34 +02:00
mise.toml ci: add Android release pipeline 2026-09-15 22:53:33 +02:00
PRODUCT.md init 2026-09-15 14:58:34 +02:00
README.md docs: refresh repository readme 2026-09-16 10:13:24 +02:00
renovate.json ci: add Android release pipeline 2026-09-15 22:53:33 +02:00
settings.gradle.kts refactor(build): extract :platform as a module declaring only :contract 2026-09-17 12:20:18 +02:00
Taskfile.yml refactor(build): extract :platform as a module declaring only :contract 2026-09-17 12:20:18 +02:00

Macros

Android automation you can read from top to bottom.

Macros is a native Android app for building personal automations as clear, inspectable routes. A route starts with one or more triggers, passes records through actions and control flow, and keeps enough history to explain what happened afterward.

It is under active development. The editor and execution engine are already useful, but the project is not presenting itself as a finished consumer product yet. “Macros” is also still a working name.

Macros automation library showing three example workflows    A battery workflow with a Switch node and visible branch route

What can it automate?

A workflow can begin from the app, a Quick Settings tile, a cron-style schedule, an external app, or Android events such as:

  • an SMS arriving;
  • the screen turning on or off;
  • the device being unlocked;
  • Wi-Fi, power, battery, audio-route, or Do Not Disturb changes.

From there, it can transform text, inspect device state, make an HTTPS request, run JavaScript, show a notification, vibrate the device, open a URL, send an SMS, wait, or branch with a Switch.

For example, the route above reads the current battery state and sends each record through Running low, Charging, or Otherwise. Branches remain visible in the editor instead of disappearing into a configuration screen.

The shape of a workflow

Trigger              Action                 Control flow            Outcome
Run manually  ───▶  Get battery status ───▶ Switch ── Running low ─▶ Show notification
                                                   ├─ Charging ────▶ Show notification
                                                   └─ Otherwise ───▶ Show notification

Macros uses a typed dataflow graph underneath this phone-friendly route view. Nodes have versioned contracts, named ports, and JSON Schema inputs and outputs. Values can be fixed, taken from the starting event, selected from an earlier action, interpolated, or written as an expression.

That gives the editor enough information to offer real output fields and reject obvious type mismatches without reducing advanced workflows to a form builder.

Useful parts already in place

Authoring

  • Multiple saved workflows with search, duplication, deletion, and direct test runs
  • Shared searchable catalogs for actions, triggers, and named event sources
  • Schema-generated input controls and an earlier-output picker
  • Visible Switch branches with first-match or all-match routing and a fallback
  • Per-node evaluation using manual input or data retained from an earlier run
  • A Compose-native JavaScript editor with schema-aware completions

Android integration

  • One honest, manifest-backed Quick Settings tile slot with a user-defined name
  • Named schedules using Android alarms rather than a permanently running process
  • Durable Android event delivery through a SQLite inbox
  • Explicit-broadcast contracts for events published by other apps
  • Reconciliation after app launch, package replacement, and device boot
  • A background-resources screen showing what the app has registered and why

Execution and recovery

  • Durable runs, history, cancellation, and failure context
  • Wait until and Wait for event checkpoints that survive process death
  • Deduplicated event delivery and leased continuation claims
  • Default-on runaway-loop protection, configurable per workflow
  • Optional, bounded run-data capture for debugging

JavaScript without handing scripts your phone

Run JavaScript receives a list of JSON values and returns a list of JSON objects:

return inputs
  .filter(input => input.enabled)
  .map(input => ({ result: input.text.toUpperCase() }));

Returning [] filters records; returning more records fans out. Declared output fields become selectable by later nodes.

Rhino runs interpreted in a dedicated Android isolated process. Scripts receive only their explicit JSON input: no Android/Java bridge, app files, package imports, network access, or app permissions. Input and output cross the process boundary through bounded anonymous file descriptors, and the worker has cancellation, size, and time limits.

Safety and privacy

Automation apps sit close to personal data and device capabilities, so the project treats those boundaries as part of the workflow rather than incidental plumbing.

  • External intents and broadcasts are validated before entering the event gateway.
  • Package allowlists fail closed where Android cannot verify the sender.
  • HTTP is HTTPS-only, with redirects, retries, cookies, and implicit authentication disabled.
  • Full run-data capture is off by default and warns that retained inputs may contain credentials or personal data.
  • JavaScript is isolated from the app UID and Android permissions.
  • The app has no persistent idle service; active background resources are derived from saved workflows.

Macros is intended to remain F-Droid compatible. It uses Android platform facilities and open-source dependencies rather than proprietary push or analytics services.

Try it

The app supports Android 8.0 (API 26) and newer. Check the Forgejo releases for available APKs. Release artifacts are currently unsigned, so Android will not treat them like a store-installed build.

To build locally, install the pinned tools and use the same quality entry points as CI:

mise install
task build
task test
task lint

The app APK is written to app/build/outputs/apk/debug/app-debug.apk.

task ci:quality runs the complete build, JVM test, and Android lint gate. Device-only isolated-worker lifecycle tests require a connected emulator or phone:

./gradlew :app:connectedDebugAndroidTest

Building in Termux

The local SDK is expected at $HOME/android-sdk, with Android 36 and Termux-native build tools installed. When $PREFIX/bin/aapt2 exists, the Gradle wrapper selects it automatically; desktop Android Studio continues to use the normal Maven-provided toolchain.

For contributors

The repository is split by responsibility rather than by Android screen:

  • app/ — product UI, workflow engine, persistence, and Android adapters
  • design-system/ — reusable Compose tokens and model-free components
  • catalog/ — internal component catalog; never shipped as a release artifact
  • ENGINE.md — execution model, durability, events, and extension boundaries
  • DESIGN.md — the “Pocket Routebook” interaction and visual system
  • PRODUCT.md — product intent, constraints, and principles

Android callbacks are adapters over the shared event gateway; they do not invoke workflows directly. Built-in and future contributed actions use the same registry seam. Third-party implementations are intended to run out of process rather than loading arbitrary code into the app.

Planned work and design decisions live in Forgejo issues. If you are considering a change, that is the best place to see current constraints and avoid building a second mechanism beside an existing one.