⚠️ Retired (2026-08-10). This Rails prototype has been retired and consolidated into its successor — a more polished implementation of the same idea. It is preserved read-only as a reference (its auth, token API, notes/brain sync, subtasks, agent-delegation loop, and PWA work are the source for porting). No further development happens here.
A minimalist task manager with hidden decision-intelligence. Moves helps you capture tasks quickly, score them with expected-value logic, and surface the best actions to take right now.
Moves treats every task as a "move" — something with a probability of success, an effort cost, and a payoff. Behind a clean, calm UI, an EV (expected value) engine continuously scores and ranks your work so you always know what deserves attention.
Key concepts:
- Moves — individual tasks scored by probability, effort, and payoff
- Campaigns — groups of related moves toward a shared objective
- Projects — color-coded filter lenses with cadence-based health tracking
- Signals — lightweight check-ins that update a move's probability over time
- Focus page — auto-curated view of your best moves, strategic bets, and stale items
- Smart capture — type a short phrase for instant capture, paste a long block for AI-powered field extraction
- 4-step move wizard — guided creation: title, probability/effort, payoff, confirm
- EV scoring engine —
(payoff x probability) / effortwith staleness decay and signal adjustments - Recommendation labels — Move now, Strong position, Gone quiet, Low priority, Let it go, Re-examine
- Monday brief — weekly stats card with top move, most neglected project, and pipeline overview
- Command palette —
Cmd+Kfor instant search and quick capture from anywhere - Project filtering — sidebar switcher with color dots; click to scope, click again to clear
- Signal logging — record positive/negative/neutral signals that automatically adjust probability
- AI suggestions — optional OpenAI integration for move classification, signal summaries, and probability hints
- Text-to-Move — paste unstructured text or voice transcription, AI extracts structured fields
- Backup/restore — full JSON export/import with UUID-based conflict resolution
- 10-step product tour — onboarding walkthrough with spotlight highlights, re-runnable from Settings
- Electron desktop app — macOS wrapper that bundles Rails + SQLite locally
Japanese-Swiss aesthetic — warm off-white backgrounds, sage green accents, Inter typeface. Intentionally calm. The intelligence layer stays hidden until you need it.
| Token | Value |
|---|---|
| Background | #F5F4F0 |
| Surface | #FFFFFF |
| Ink | #18181A |
| Accent (sage) | #1E5C42 |
| Amber | #8B6020 |
| Font | Inter, system-ui |
| Layer | Technology |
|---|---|
| Framework | Ruby on Rails 8.1 |
| Frontend | Hotwire (Turbo + Stimulus) |
| JS bundling | Importmap (no build step) |
| Database | SQLite |
| Asset pipeline | Propshaft |
| Background jobs | Solid Queue |
| Cache | Solid Cache |
| WebSocket | Solid Cable |
| AI (optional) | OpenAI API (gpt-4.1-mini default) |
| Desktop | Electron 36 |
- Ruby 3.2+
- Bundler
- Node.js 18+ (for Electron desktop only)
# Install dependencies
bundle install
# Set up database
bin/rails db:setup
# Start the server
bin/dev# Install Electron dependencies
npm install
# Run desktop (starts Rails internally)
npm run desktop:dev
# Build macOS DMG
npm run desktop:build:dmgMoves works fully offline. To enable AI suggestions, signal summaries, and text-to-move parsing:
- Set your API key:
export OPENAI_API_KEY=your_key_here - Or configure it in-app: Settings → enter your OpenAI API key → enable AI
The key is stored locally in your SQLite database and never transmitted anywhere except OpenAI's API.
app/
├── controllers/ # 12 controllers (Focus, Inbox, Moves, Campaigns, etc.)
├── models/ # Move, Campaign, Project, MoveSignal, AppPreference
├── services/ # EV calculator, recommendation engine, focus classifier,
│ │ # staleness detector, signal impact, weekly brief, AI provider
│ └── ai/providers/ # OpenAI integration
├── javascript/
│ └── controllers/ # Stimulus: wizard, command palette, smart capture,
│ # tour, project modal, context menu, disclosure
├── helpers/ # Display label mapping, badge classes
└── views/ # ERB templates
electron/ # Desktop wrapper (main.js, preload.js)
- Base EV =
(payoff_normalized × probability) / effort_minutes - Signals adjust probability — positive signals increase it, negative decrease it
- Staleness decays scores — 10+ days without signals triggers "Gone quiet", 21+ days triggers "Re-examine"
- Recommendation engine combines EV, probability, effort, and staleness into a human label
- Focus classifier buckets moves into: Best moves now, Strategic bets, Needs a call
| Service | Purpose |
|---|---|
EvCalculator |
Computes expected value from payoff, probability, effort |
RecommendationEngine |
Maps EV + signals into action labels |
FocusClassifier |
Waterfall sort into focus buckets |
SignalImpactEngine |
Adjusts probability based on signal direction/magnitude |
StalenessDetector |
Flags moves that have gone quiet |
WeeklyBriefService |
Monday morning stats and insights |
AiSuggestionProvider |
Facades OpenAI for suggestions, summaries, parsing |
BackupExporter/Importer |
Full JSON backup with UUID conflict resolution |
bin/rails testFrom the Settings page:
- Export — downloads a JSON file with all moves, campaigns, projects, and signals
- Import — uploads a JSON backup; uses UUID matching to avoid duplicates
| Route | Page | Purpose |
|---|---|---|
/focus |
Focus | Default landing — best moves, weekly brief |
/inbox |
Inbox | Uncategorized moves awaiting triage |
/moves |
All Moves | Full list with search and filters |
/moves/:id |
Move Detail | Signals, AI tools, state transitions |
/campaigns |
Campaigns | Campaign cards with progress stats |
/archive |
Archive | Completed and archived moves |
/settings |
Settings | AI config, tour restart, backup/restore |
MIT