OpenTasker is a fully open-source, on-device, FOSS alternative to Tasker for Android.
- Profiles, contexts, tasks, actions — a complete Room-backed automation pipeline with a Compose UI
- 7 context families — Application, Time, Day, Location, State, Event, and Plugin (Locale/Tasker condition)
- 58 built-in actions plus engine-handled flow control (
task.run,if/else/end if,for each/end for,stop) - Template expressions — bounded
{{ ... }}expansion with scoped variables, arrays, JSON paths, string/math/date functions, traces, and strict regex policy - First-class secret variables — AES-256-GCM Android Keystore storage, deliberate reveal/re-entry UX, and provenance-based redaction for derived action arguments, logs, traces, and failures
- Automation modes — per-profile single, restart, queued, and parallel re-trigger behavior
- Profile groups — organize profiles into named groups with filter chips
- Time/day schedules with presets, aliases, and ranges
- Device state (battery, charging, headphones, screen, airplane, power save, Wi-Fi SSID)
- App foreground detection via UsageStats
- Wi-Fi and data/internet connectivity via NetworkCallback
- Notification listener with package/title/body filters
- NFC tag scans with normalized ID matching and a one-time NDEF write helper
- Calendar windows with redacted event metadata
- Sunrise/sunset filters with coordinate, offset, and window support
- Shake, Bluetooth connect/disconnect, package install/remove/replace
- Quick Settings tile tap, home-screen widget/shortcut, boot
- FOSS platform location/geofence — GPS/network fixes, balanced provider cadence, radius/accuracy/dwell evaluation, persisted dwell state, and API 36 background delivery evidence
- Locale/Tasker condition plugins — polled as first-class context predicates with last-known-state caching
| Category | Count | Examples |
|---|---|---|
| Settings | 11 | Wi-Fi, Bluetooth, brightness, volume, airplane, mobile data, screen timeout, DND, ringer mode, torch, tile state |
| App | 7 | launch intent, launch app, kill, go home, open URL, SMS, screenshot |
| File | 5 | read, write, append, delete, list |
| Network | 6 | HTTP Request, legacy GET/POST aliases, ping, download, Wake-on-LAN |
| Media | 6 | play, stop, pause, next, previous, mute |
| System | 6 | vibrate, reboot, lock, screen off, wake, log |
| Notification | 3 | notify/toast, cancel, TTS speak |
| Variable | 10 | set variable, read data (JSON/CSV/XML), date-time (format/parse/add), text (match/replace/split/join/substring) |
| Flow | 1+7 | wait; engine: task.run, if/else/end if, for each/end for, stop |
| Plugin | 2 | Locale setting dispatch, Locale condition query |
| Script | 1 | SHA-256-pinned Termux RUN_COMMAND with bounded result capture |
| Import | 1 | unsupported Tasker action placeholder |
Privileged actions (airplane, mobile data, screenshot, reboot, screen off) are gated to fail honestly. SMS is available in standard/F-Droid builds; Play builds omit SMS/phone-state permissions.
New automations use HTTP Request for GET, HEAD, POST, PUT, PATCH, DELETE, and OPTIONS. It accepts structured query/header lines, inline or OpenTasker-file request bodies, per-stage timeouts, status/header/body variables, and atomic file output. Redirects default off and can be enabled only for the same origin; TLS verification cannot be disabled, cleartext remains private-LAN-only, and response/request sizes are bounded. Stored http.get and http.post actions continue to execute through compatibility aliases. Put credentials in Keystore-backed secret variables and reference them from Authorization or header fields so traces remain redacted.
Variable names follow Tasker's scope rule: an all-lowercase name is local to the current task, while any name containing an uppercase letter is global and durable. var.persist promotes an all-lowercase target to a global name, and the Variable vault applies the same normalization. Concurrent runs merge changes to different globals; if two stale snapshots change the same global, the first committed value is kept and the later conflict is recorded in the run log.
- OEM battery-killer detection with per-vendor remediation (Samsung, Xiaomi, OnePlus, Oppo, Realme, Vivo, Huawei, etc.)
- Alarm-backed time/day reevaluation through Doze, with a persisted engine heartbeat and periodic WorkManager watchdog that re-arms dropped ticks and foreground-service timeout recovery
- Setup checklist covering notifications, exact alarms, battery optimization, usage access, overlays, location, Bluetooth, SMS, DND, Shizuku, and Termux
- Context inspector with live source health, latest values, and per-profile match explanations
- Step-level run logs with action traces, template diagnostics, warning counts, and configurable retention
- In-app diagnostics for service/foreground-type/standby/exact-alarm/matcher/watchdog health, a bounded process log, and captured crash previews; shared reports include the same evidence with credential redaction
- Crash log capture and local diagnostic export
- Locale/Tasker plugin host — setting dispatch, condition queries, configuration parsing, request-query events, bundle validation, and last-known-state fallback
- Locale/Tasker condition context — condition plugins as first-class profile predicates polled every 30 seconds
- External automation target — signature-scoped intents to run tasks, toggle profiles, query status, and pass variables
- OpenTasker JSON bundles — schema-versioned export/import with computed action-power manifests, data-to-external-chain warnings, disabled-by-default installation, explicit first-enable acknowledgement, and secret values omitted by design
- Tasker XML import — preview with migration/capability warnings, mapped and unsupported action reporting
- Profile sharing — offline share manifests with safety findings and GitHub Discussions submission text
Untrusted imports are preflighted before object/DOM allocation. OpenTasker JSON is capped at 16 Mi characters, 250,000 lexical tokens, and depth 64; Tasker XML is capped at 4 Mi characters, 100,000 nodes, and depth 64. Both formats share decoded limits of 5,000 top-level entities, 20,000 actions, 10,000 contexts, 10,000 scene elements, and 8 MiB of aggregate UTF-8 string data. A named budget violation aborts before the Room transaction.
- AMOLED-first Catppuccin Mocha (dark) and Latte (light) palettes, high contrast mode
- Refined mobile shell with clearer primary navigation, bottom-bar contrast, and edge-to-edge system bar theming
- Accessible Setup theme selector with explicit selected state plus denser, confidence-building backup controls
- Compact-safe profile, task, and run-log cards with horizontally safe status chips and filtered empty states
- Variable vault, Flow, Scenes, and Inspector surfaces with summary metrics, clear status language, and polished empty states
- Guided profile templates with variable slots and safety notes
- Scene element editor with drag-to-move, resize handles, multi-select, alignment guides, scaled canvas previews, overlay launch, and tap/long-press task bindings
- Flow graphs with zoom/pan canvas previews, edge routing, branch/subflow markers, node deep links, and picker-backed add commands
- Profile and task search bars
- Saveable editor/dialog state across rotation and resize
- F-Droid readiness profile with dependency-policy and metadata verification
- Play distribution profile with SMS/phone-state manifest policy gate
- Local release verification scripts for F-Droid metadata, readiness, and APK payload comparison
- Environment-driven release signing
- SQLite database backup/restore with WAL-safe validation and atomic staged restore; encrypted
.otbackupv2 exports use bounded-memory, independently authenticated 64 KiB frames while legacy v1 files remain restorable. Secret rows stay ciphertext and the device-bound Keystore key is never copied, so a restore on another device requires secret re-entry - APK payload comparison harness for reproducibility checks
- Shizuku manager/service/permission status, a persisted default-on kill switch, and a fail-closed command allowlist; elevated actions remain unsupported until a privileged user-service transport ships
- Termux 0.109+
RUN_COMMANDintegration with a user-managed SHA-256 allowlist, pre-run hash verification, timeouts, and bounded output variables
To run a Termux script, place it below ~/.termux/tasker/, enable Termux's external-app access, and grant OpenTasker RUN_COMMAND permission from Setup. Add the script path and the expected 64-character SHA-256 under Approved Termux scripts; OpenTasker performs a hash preflight and rechecks inside the fixed execution wrapper before the script can run. A capture prefix such as %script writes bounded %script_stdout, %script_stderr, %script_exit_code, and original-length variables; captured content is never written to the run log.
AutomationService (foreground)
↓
ProfileMatcher (monitors context streams)
↓
ContextSources (app, time, state, event, location, plugin)
↓
TaskRunner (executes action list with flow control)
↓
ActionRegistry (built-ins + capability gates + Locale plugin dispatch)
↓
Room DB (persistent storage + StateFlow live queries)
No Hilt — manual dependency wiring via OpenTaskerApp_NoHilt. MVVM with Compose, Room, coroutines, DataStore, and WorkManager.
git clone https://github.com/SysAdminDoc/OpenTasker
cd OpenTasker
./gradlew :app:testDebugUnitTest :app:assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apkRelease build (unsigned without keystore env vars):
./gradlew :app:assembleReleaseF-Droid profile:
./gradlew -PopenTaskerDistribution=fdroid :app:assembleRelease :app:verifyFdroidReadiness :app:verifyFdroidMetadataPlay manifest policy check:
./gradlew -PopenTaskerDistribution=play :app:verifyPlayManifestPolicyFull local release gate (blocking lint, JVM tests, Room schemas, Android-test compilation, resolved dependency/SBOM and OSV policy, configuration-cache reuse, plus Play and F-Droid release builds):
.\tools\verify-local-release.ps1The gate writes machine-readable reports under build/reports/opentasker/. To prove failure propagation without running the full build, run .\tools\verify-local-release.ps1 -SeedFailure; success is a nonzero exit with Seeded local quality-gate failure.
| Property | Value |
|---|---|
| Kotlin | 2.3.21 |
| Gradle | 9.4.1 |
| AGP | 9.2.1 |
| KSP | 2.3.7 |
| Build Tools | 36.0.0 |
| JDK | 17 or 21 |
| Min SDK | 26 (Android 8.0) |
| Compile SDK | 37 |
| Target SDK | 37 |
| Room | 2.8.4 |
| Compose BOM | 2026.05.00 |
| WorkManager | 2.11.2 |
All dependency versions are centralized in gradle/libs.versions.toml.
See ROADMAP.md for the full backlog. Key remaining work:
- Broad device-verified background geofence reliability evidence
- API 37 platform readiness pass (FGS, predictive back, large-screen QA)
- Macrobenchmark and Baseline Profile for cold-start performance
MIT — see LICENSE.
Issues and pull requests welcome. See ROADMAP.md for planned features.
OpenTasker supports localization. English source copy lives in app/src/main/res/values/strings.xml, action_catalog_strings.xml, and dynamic_surface_strings.xml; locale targets under app/src/main/res/values-* are ready for Weblate-style translation workflows. Debug builds enable Android's en-XA and ar-XB pseudolocales for expansion and right-to-left checks. To contribute a translation:
- Copy the three translatable XML files from
app/src/main/res/values/toapp/src/main/res/values-<locale>/ - Translate only the string values (not the
nameattributes) - Omit strings that are identical to English — Android falls back automatically
- Submit a PR with your locale directory
Skeleton directories exist for: ar, de, es, fr, hi, it, ja, ko, pl, pt-rBR, ru, tr, zh-rCN.