taskflare
A Dart CLI tool that runs your dev commands, parses their output to determine a single unambiguous result, and notifies you when they're done — via the terminal and Windows toast notifications.
Supports dart test / flutter test with structured per-test output, and any arbitrary shell command through taskflare run.
Outcomes
Every run ends with exactly one of three outcomes:
| Outcome | Meaning |
|---|---|
[SUCCESS] |
All tests passed — or the command exited with code 0 |
[FAILURE] |
At least one test failed — or the command exited with a non-zero code |
[CRASH] |
The process could not start or crashed before producing a result |
Usage
Interactive menu
dart run taskflare
Opens the main menu with options for Help, Config, Run command, and Quit. Good for exploring taskflare for the first time.
Run tests
dart run taskflare test
dart run taskflare test --name "my test"
dart run taskflare test test/parser/
Auto-detects Flutter vs. Dart and runs flutter test or dart test accordingly. All extra arguments are forwarded to the underlying runner.
Example terminal output:
FAIL ▶ parses failure when done reports failure test/parser/json_event_parser_test.dart:42
THROW ▶ throws when input is malformed test/parser/json_event_parser_test.dart:91
SKIP ▶ skipped scenario
[FAILURE] passed: 108 failed: 2 skipped: 1 (14.3s)
FAIL— assertion error (expectfailed), including Flutter widget test failuresTHROW— uncaught exception thrown during the test; shown with file path but no line numberSKIP— test was skipped- File references are
path/to/file.dart:line— Ctrl+click in most terminals and IDEs to jump directly to the source. For Flutter widget tests the reference resolves to the user's test file, not the flutter_test framework internals
The progress line updates in-place while tests run and is erased when the run completes, leaving only the permanent failure/skip lines and the final summary.
Run a shell command
dart run taskflare run # Prompts for a command interactively
dart run taskflare run flutter build apk
dart run taskflare run dart run build_runner build
Streams the command output directly to the terminal, fires a Windows notification when it finishes, and optionally writes a markdown report. Outcome is determined by exit code. Taskflare will not execute taskflare run inside itself.
Help
dart run taskflare help # Interactive command list
dart run taskflare help test # Print test command help directly
Config
dart run taskflare config # Interactive configuration menu
Settings are split into two sections:
- Tests — filter toggles (show only failures, etc.) and report on/off
- Run — report on/off for
taskflare run
Configuration is persisted to .taskflare.json in the working directory.
Markdown reports
When the report toggle is enabled, taskflare writes a .md file to taskflare-reports/ after each run. The document structure is:
# Taskflare Run
## Summary — outcome, counts, duration
## Failed tests — each failed/thrown test with file ref and duration
## Skipped tests — each skipped test with file ref and duration
## All tests — every test grouped by group name
Windows notifications
On Windows, taskflare sends a native desktop toast notification at the end of every run. For taskflare test, an additional immediate toast fires when each individual test fails.
On first run, taskflare automatically:
- Writes the bundled app icon to
%LOCALAPPDATA%\Taskflare\taskflare.ico - Registers
Taskflare.AppinHKCU\Software\Classes\AppUserModelId\ - Creates a Start Menu shortcut (
Taskflare.lnk) with the AppUserModelID set
This is what makes the Taskflare icon appear next to the app name in the notification header. No manual setup required. Re-registration happens automatically if any of the three components is missing (e.g. after a clean install or manual deletion).
To replace the icon, overwrite %LOCALAPPDATA%\Taskflare\taskflare.ico with any ICO file, then delete the Start Menu shortcut so it is recreated on the next run:
Remove-Item "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Taskflare.lnk" -Force
Requirements
- Dart SDK
>=3.0.0 <4.0.0 - Windows toast notifications require Windows 10 or later
Architecture
taskflare follows a clean, layered architecture. Each layer has a single responsibility and depends only on the layers below it.
bin/
└── taskflare.dart Entry point — dispatches menu / help / config / test / run
lib/src/
├── cli/ CLI entry points (menu-driven and direct)
│ ├── profile/ CommandProfile base + concrete profiles (TestProfile, RunProfile)
│ ├── command_registry.dart Central list of commands (drives menu, help, run submenu)
│ ├── menu_command.dart Main menu shown by bare `taskflare`
│ ├── help_command.dart Interactive help + `help <name>` shortcut
│ ├── config_command.dart Interactive configuration menu (Tests / Run sections)
│ ├── test_command.dart Wires Taskflare for the `test` command
│ ├── custom_command.dart Handles `taskflare run` — prompts, streams, notifies
│ └── terminal.dart TerminalSession — owns the alt screen buffer, injected into all TUI screens
├── config/
│ └── taskflare_config.dart Persisted user preferences (per-command filter + report toggles)
├── utils/ Shared utilities
│ ├── enums.dart TestResultKind and TestOutcome enums
│ └── project_detector.dart Detects Flutter vs. Dart project from pubspec.yaml
├── entities/ Domain objects accumulated across a test run (Test, ErrorEvent, …)
├── parser/
│ └── json_event_parser.dart Reads test JSON lines → produces a RunSummary
├── runner/ Abstract CommandRunner + process-based runners (dart / flutter test / shell)
├── reporter/ Markdown report writers for test runs and shell commands
├── notifier/ Console + Windows toast notifiers, progress line, composite
└── taskflare.dart Orchestrator: runner → parser → notifier + reporter
lib/assets/
└── icon.png Bundled app icon (written to LocalAppData on first run)
Layer rules
utils ← no dependencies
entities ← utils
config ← no dependencies (pure persisted preferences)
parser ← entities, utils
runner ← utils
reporter ← entities, utils
notifier ← entities, utils
taskflare ← runner, parser, notifier, reporter, entities, utils (orchestrator only)
cli ← all layers (entry points that wire everything)
The orchestrator depends only on abstractions (CommandRunner, Notifier, ReportWriter) — never on concrete implementations. Swapping them requires no changes to taskflare.dart.
Extending taskflare
Add a new structured command (e.g. taskflare lint):
- Create
lib/src/cli/profile/lint_profile.dartextendingCommandProfile— implementname,description,helpText,commandLabel, andbuildRunner - Create
lib/src/cli/lint_command.dartwiringTaskflarefor the new profile (notifier, reporter, progress options) - Add an entry to
commandRegistryinlib/src/cli/command_registry.dart— menu, help, and run submenu pick it up automatically
Add a new notifier (e.g. webhook, Slack):
- Create
lib/src/notifier/slack_notifier.dartimplementingNotifier - Implement
notify(RunSummary summary) - Add tests in
test/notifier/slack_notifier_test.dart - Pass it to
Taskflare(notifier: SlackNotifier(), ...)
Running tests
dart test
The integration tests in test/runner/ spin up real subprocesses using the fixture projects under test/fixtures/. They take a few seconds — all other tests are pure unit tests and run instantly.
Project conventions
| Document | Contents |
|---|---|
doc/conventions_testing.md |
Test structure, group/test naming rules, what must be covered |
doc/conventions_architecture.md |
Folder layout, layer dependency rules, naming patterns |
doc/learnings.md |
Problems encountered and what we learned from them |
Libraries
- taskflare
- A Dart CLI tool that wraps
dart test(orflutter test), parses the JSON event stream, reports live progress in the terminal, and fires desktop notifications on test failure and completion.