- Viewing your daily agenda with scheduled items and deadlines
- Capturing new tasks using org-mode capture templates
- Searching across all your TODO items
- Running custom agenda views
- Receiving notifications for upcoming tasks
The phone and Wear OS APKs are also attached to each GitHub release:
The F-Droid repository serves the same signed phone APKs as the releases page, so installs from either source upgrade in place. See docs/fdroid.md for publication and repository setup details.
Mova is the mobile frontend for org-agenda-api, a JSON HTTP API that exposes org-mode data from GNU Emacs. The architecture:flowchart TB
subgraph Docker["Docker Container"]
nginx["nginx<br/>(HTTP Basic Auth)"]
subgraph Emacs
httpd["simple-httpd<br/>(HTTP server)"]
api["org-agenda-api<br/>(elisp)"]
org["org-mode"]
httpd --> api --> org
end
repo["Git Repository<br/>(.org files on disk)"]
sync["git-sync-rs"]
nginx --> httpd
org <--> repo
sync <--> repo
end
remote["Remote Git"]
mova["Mova<br/>(this app)"]
sync <--> remote
mova <-->|HTTP/JSON| nginx
- nginx handles HTTP Basic Auth and proxies requests to Emacs
- simple-httpd provides the HTTP server functionality within Emacs
- org-agenda-api is an elisp package that runs inside Emacs, translating org-mode data into JSON HTTP responses
- org-mode reads and writes
.orgfiles from the git repository on disk - git-sync-rs keeps the local git repository synchronized with a remote
- Mova connects to nginx via HTTP Basic Auth to provide a native mobile experience
You need a running org-agenda-api instance for Mova to connect to. See the org-agenda-api README for setup instructions.
- Daily agenda with date navigation
- Shows scheduled items, deadlines, and overdue tasks
- Pull-to-refresh synchronization
- Inline task completion and editing
- Template-based task capture using your org-mode capture templates
- Dynamic form fields (text, dates, tags) defined by templates
- Priority and TODO state selection
- Scheduled/deadline date pickers
- Remembers your last-used template
- Full-text search across all TODO items
- Searches title, tags, and TODO state
- Real-time filtering
- Access your custom org-agenda commands
- Dynamic view rendering from server-defined views
- Quick Capture widget for home screen
- Capture tasks without opening the app
- Configurable template per widget instance
- Agenda widget listing today’s items (overdue first), each with a tap-to-complete circle that finishes the item without opening the app, plus task/habit tabs and typed and voice quick-capture actions in the header; scheduled/deadline timestamps appear on cards, with two cards per row at wider sizes
- Background sync for upcoming tasks
- Configurable notification intervals
- Scheduled and deadline reminders
- Node.js 18+
- Yarn or npm
- A running org-agenda-api server
- For development: Android Studio (Android) or Xcode (iOS)
# Clone the repository
git clone https://github.com/colonelpanic8/mova
cd mova
# Install dependencies
yarn install
# Start the development server
yarn start# Android
yarn android
# iOS
yarn ios
# Or use Expo Go for quick testing
npx expo start- Launch Mova
- Enter your org-agenda-api server URL (e.g.,
https://your-server.com) - Enter your username and password
- Tap Login
mova/ ├── app/ # Expo Router screens │ ├── (tabs)/ # Main tab navigation │ │ ├── index.tsx # Agenda screen │ │ ├── capture.tsx # Capture screen │ │ ├── search.tsx # Search screen │ │ ├── habits.tsx # Habits screen │ │ ├── views.tsx # Custom views │ │ └── settings/ # Settings screens │ ├── edit.tsx # Todo editor │ └── login.tsx # Login screen ├── services/ # API client, query cache, background tasks │ ├── api.ts # org-agenda-api client │ ├── queryClient.ts # TanStack Query client + offline persistence │ ├── captureOutbox.ts # Durable offline capture queue │ ├── backgroundSync.ts # Background task registration │ └── notifications.ts # Local notifications ├── hooks/ # Query hooks (useAgendaData, queryKeys), mutations ├── components/ # Reusable UI (agenda/, capture/, todoForm/, todoEditing/) ├── context/ # React context providers (auth, settings, filters) ├── widgets/ # Android home-screen widget (JS side) ├── android/wear/ # Wear OS companion app (Kotlin) └── tests/ # Jest unit/integration/component tests
yarn start # Start Expo dev server
yarn android # Run on Android
yarn ios # Run on iOS
yarn test # Run Jest tests
yarn typecheck # TypeScript validation
yarn lint # ESLint check
yarn e2e:android # Run Detox E2E tests# Unit tests
yarn test
# E2E tests (requires Android emulator)
yarn e2e:build:android
yarn e2e:android- React Native + Expo - Cross-platform mobile framework
- Expo Router - File-based navigation
- React Native Paper - Material Design 3 components
- TanStack Query - Server-state caching, invalidation, and offline persistence (queries are keyed per server identity and persisted to AsyncStorage for offline launches)
- TypeScript - Type safety
- Jest + Detox - Testing
Note: the home-screen widget, quick-capture activity, and Wear OS companion app are Android-only; iOS currently has no counterpart for these capture surfaces.
The Wear OS companion also provides a Mova Quick Capture Tile. Add it
from the watch’s tile picker to launch voice capture directly by swiping
from the watch face and tapping Capture. A second assistant button uses
system dictation to send a text instruction to OpenAI, then lets the model
read or change org data through an allowlisted set of org-agenda-api tools.
Raw microphone audio is handled by the Wear OS speech recognizer and is not
sent to OpenAI by Mova.
To enable natural-language requests from Wear OS:
- Open Mova’s Settings screen on the phone.
- Under
Watch Assistant, enter an OpenAI API key and model. - Tap
Savewhile the watch is paired.
The default model is gpt-5.6-luna for a latency/cost-sensitive watch
workflow. The OpenAI key is kept in secure storage on the phone and in
encrypted preferences on the watch. Assistant requests go directly from the
watch to OpenAI’s Responses API; tool calls then go directly from the watch to
the configured org-agenda-api server.
The assistant can search and count todos, inspect agendas and habits, capture, update, complete, or explicitly delete tasks, and use other allowlisted API operations. It resolves mutation targets to an org ID or exact file position before acting and asks for clarification rather than guessing when a target is ambiguous.
Capture templates are defined in your Emacs org-mode configuration and exposed via the org-agenda-api/capture-templates endpoint. Mova automatically fetches and renders forms based on your template definitions.
Example template structure from org-agenda-api:
{
"todo": {
"name": "Todo",
"prompts": [
{ "name": "title", "type": "string", "required": true },
{ "name": "scheduled", "type": "date", "required": false },
{ "name": "tags", "type": "tags", "required": false }
]
}
}- Enable/disable notifications
- Set reminder intervals (e.g., 15 minutes before)
- Background sync frequency (default: 15 minutes)