Imported from involvex/nova-assistant (
.claude/skills/nova-dev/SKILL.md). Install upstream withnpx skills add involvex/nova-assistant --skill nova-dev. Copyright stays with the author.
Nova Assistant development skill
You are helping a developer work on Nova Assistant — a Flutter app that runs Gemma / LiteRT models entirely on-device.
Repo root should contain pubspec.yaml with name: nova_assistant and AGENTS.md.
Canonical path: .cursor/skills/nova-dev/
Other agents: .agents/skills/nova-dev/ (synced copy) · .claude/skills/nova-dev/ (junction → .agents)
Edit the Cursor copy, then run ./scripts/link-nova-dev-skill.ps1 (or .sh) to sync. Use -LiveLink / --live to junction .agents → .cursor for single-edit local work.
When invoked
Follow the matching workflow below. Prefer running commands yourself. Do not invent API keys; HF token is optional in Settings.
Workflow A — Setup and build the app
Say this when the user asks to setup and build Nova.
1. Preconditions
- Flutter matching
pubspec.yaml(flutter: '>=3.17.0-0.1.pre', Dart SDK constraint). - Android SDK, API 26+, prefer physical arm64 device.
- One ADB device only (
adb devices). If duplicates:adb disconnectthen reconnect once.
2. Bootstrap
flutter pub get
dart format --set-exit-if-changed . || dart format .
flutter analyze --no-pub
3. Run / build
flutter devices
flutter run -d android
# or
flutter build apk --debug --target-platform android-arm64
4. First model
Do not force-download Gemma 4 on low-RAM phones during soak tests. Guide the user to:
- Open the app → onboarding or Settings → AI Models
- Download SmolLM or Gemma 3 1B, or Import from storage
- For vision/thinking demos, use Gemma 4 E2B only with enough free RAM
5. Verify
flutter test
Report device serial, Flutter version, and whether a model is installed.
Workflow B — Configure my own model
Say this when the user wants a custom / local model.
Supported formats
| Format | Supported |
|---|---|
.litertlm |
Yes (preferred) |
.task |
Yes (MediaPipe) |
.gguf |
No on-device — use Remote LAN instead |
Diffusion .tflite graphs |
Yes — Settings → Models → Image generation |
Steps
- Confirm file format and approximate size.
- Warn if ≥2 GB on ≤6 GB RAM devices.
- In-app path: Settings → AI Models → Import from storage (or onboarding import).
- Code path for agents debugging installs:
- Registration:
ModelManager.registerDiskModel/ disk sync - Canonical name must match catalog (e.g.
gemma-4-E2B-it.litertlm) - Avoid leaving
nova_download_<timestamp>_…as the prefs name
- Registration:
- After import, set preferred model in the model selector (or Auto).
- Cold-start the app if the engine was already loaded without vision and the new model needs vision.
HuggingFace download
- Optional token in Settings for gated models.
- Use Model Browser or built-in install URLs from
ModelHuggingFaceURLs. - On 401/403, ask user to set HF token — do not scrape private URLs.
Diffusion (image generation)
- Catalog: Z-Image-Turbo (
Z-Image-Turbo-LiteRT), FLUX.2-klein (FLUX.2-klein-4B-LiteRT). - Files land under Flutter documents:
app_flutter/diffusion_models/<folder>/*.tflite. - Native channel IDs must use folder names, not Dart enum names (
zImageTurbo). - Uninstall via trash icon on Settings model cards (
uninstallDiffusionModel/uninstallModel).
Workflow C — Day-to-day development
Read first
AGENTS.md— architecture, lint rules, tools, modelsdocs/— human docs (GitHub Pages); assistant capture:docs/assistant-mode.mdlib/services/model_orchestrator.dart— inference + tools + idle unloadandroid/app/src/main/kotlin/dev/nova/assistant/— native tools / capture / diffusion
Stability invariants (do not regress)
- Never close / clear LiteRT while streaming (
isStreaming) — causes SIGABRT (Callback invoked after it has been deleted). - Vision-capable models load with
supportImage: truealways (not only when an image is present). - Screenshot pixels via
ScreenshotService/dev.nova.assistant/screenshot, not huge tool MethodChannel maps. - Idle unload only after stream ends; lifecycle pause skips unload while streaming.
- Remote LAN (
InferenceBackend.remote): do not call_getOrCreateModel/ pre-warm; re-read prefs eachprocessMessage.
Common commands
flutter pub get
flutter run -d android
flutter test
flutter analyze --no-pub
dart format .
dart run build_runner build --delete-conflicting-outputs # if codegen needed
Assistant mode / screen capture
adb shell appops set dev.nova.assistant PROJECT_MEDIA allow
adb shell appops get dev.nova.assistant PROJECT_MEDIA
See docs/assistant-mode.md.
Commit style
Conventional Commits (feat:, fix:, docs:, …). Commit only when the user asks. Push only when the user asks.
Project map (short)
lib/
main.dart
models/ # NovaModel, ChatMessage, roles, identity, palettes
theme/ # NovaPalette (Hacker, Monokai, Dracula, …)
screens/ # Assistant, settings, onboarding, MCP, tasks, notes
services/ # Orchestrator, ModelManager, Memory, MCP, RemoteInference, …
platform/ # ToolExecutorService, ScreenshotService
tools/ # Tool JSON schemas
widgets/
android/ # Kotlin: tools, MediaProjection, diffusion pipeline
docs/ # GitHub Pages site
.cursor/skills/nova-dev/ # canonical skill (edit here)
.agents/skills/nova-dev/ # synced for Codex / Agents SDK
.claude/skills/nova-dev/ # junction → .agents (Claude Code)
scripts/link-nova-dev-skill.ps1 # sync / live-link helper
scripts/link-nova-dev-skill.sh
Out of scope for this skill
- Implementing Streamable HTTP + OAuth MCP (HIBP) unless explicitly requested
- Committing secrets, HF tokens, or
local.properties - Force-pushing
main