Improve AI guidelines

This commit is contained in:
franzap
2026-03-07 20:46:02 -03:00
parent f2db9a7b70
commit e7d4bb109a
17 changed files with 205 additions and 52 deletions
+1
View File
@@ -0,0 +1 @@
../../spec/guidelines/ARCHITECTURE.md
+65
View File
@@ -0,0 +1,65 @@
---
description: Flutter/Dart conventions for Zapstore projects
globs: ["**/*.dart", "**/pubspec.yaml"]
---
# Flutter/Dart Conventions
## State Management
- Use Flutter Hooks (`HookWidget`, `HookConsumerWidget`) for local widget state — not `StatefulWidget`.
- Use `useState`, `useAnimationController`, `useEffect` over manual `State` classes.
- Use Riverpod providers for shared/global state. Keep providers focused and composable.
- Prefer `ref.watch` for reactive UI, `ref.read` in callbacks only.
## Data & Async
- All async work must be cancellable. Pass `CancellationToken` or use `ref.onDispose`.
- Never `await` inside `build()`. Move async work to providers or `useEffect`.
- Use `switch` on sealed classes / union types for exhaustive state handling:
```dart
return switch (state) {
StorageLoading() => const CircularProgressIndicator(),
StorageError(:final exception) => Text('Error: $exception'),
StorageData(:final models) => MyWidget(models),
};
```
- All async operations must have explicit loading, success, and error states in the UI.
## Widget Structure
- One widget per file. File name matches widget name in snake_case.
- Keep `build()` methods short — extract sub-widgets or use helper methods.
- Widgets must not manage relay connections, storage, or background jobs.
- Use `const` constructors wherever possible.
## Naming
- Files: `snake_case.dart`. Classes: `PascalCase`. Variables/methods: `camelCase`.
- Providers: `<noun>Provider` or `<noun>NotifierProvider`.
- Services: `<Noun>Service`. Notifiers: `<Noun>Notifier`.
## Error Handling
- Never swallow exceptions silently. Surface errors to the UI or log them.
- Use typed exceptions where the caller needs to distinguish error types.
- `try/catch` at the boundary (provider/service), not deep in domain logic.
## Testing
- Test providers and services, not widget internals.
- Use `ProviderContainer` for unit-testing Riverpod providers.
- Mock external dependencies (storage, network) — no real I/O in unit tests.
- Widget tests for critical UI states: loading, error, empty, success.
## Dependencies
- Run `fvm flutter pub get` after any `pubspec.yaml` change.
- Pin Flutter SDK version via FVM (`fvm use <version>`).
- Prefer packages already in use over adding new ones.
## Build
- Assume Android as default target unless instructed otherwise.
- Release builds must be reproducible (see INVARIANTS.md).
- Run `flutter analyze` — fix all issues before committing.
+1
View File
@@ -0,0 +1 @@
../../spec/guidelines/INVARIANTS.md
+1
View File
@@ -0,0 +1 @@
../../spec/guidelines/QUALITY_BAR.md
+1
View File
@@ -0,0 +1 @@
../../spec/guidelines/VISION.md
-1
View File
@@ -1 +0,0 @@
CONTEXT.md
+19 -50
View File
@@ -1,17 +1,8 @@
# AI Agents # Zapstore — Agent Instructions
This document is the entry point for AI assistants. Local-first, Nostr-native app store for Android.
All behavioral authority lives in the project spec, not here.
If anything in this file conflicts with files under `spec/guidelines/`, All behavioral authority lives in `spec/guidelines/`. If this file conflicts, guidelines win.
this file is wrong.
## What This Repository Is
Zapstore is a local-first, Nostr-native app store for Android.
It discovers, downloads, verifies, and installs APKs signed by developers the user trusts.
Users can support developers directly via Lightning zaps.
## Quick Reference ## Quick Reference
@@ -22,51 +13,29 @@ Users can support developers directly via Lightning zaps.
| Quality standards | `spec/guidelines/QUALITY_BAR.md` | | Quality standards | `spec/guidelines/QUALITY_BAR.md` |
| Product vision | `spec/guidelines/VISION.md` | | Product vision | `spec/guidelines/VISION.md` |
| Feature specs | `spec/features/` | | Feature specs | `spec/features/` |
| Active work | `work/` | | Active work | `spec/work/` |
| Decisions & learnings | `spec/knowledge/` |
## Project Spec Structure Guidelines are symlinked into `.cursor/rules/` and auto-load.
spec/
guidelines/ # Permanent rules (human-owned, never AI-modified)
ARCHITECTURE.md # Package boundaries, dependencies, key patterns
INVARIANTS.md # Non-negotiable behavioral guarantees
QUALITY_BAR.md # Standards, when to create specs
VISION.md # Product goals and non-goals
features/ # Feature specs (behavioral contracts)
_TEMPLATE.md # Template with example
FEAT-001-*.md # Actual feature specs
work/ # Active work packets (temporary, delete after merge)
_TEMPLATE.md # Template with example
WORK-001-*.md # Actual work packets
## How to Work
1. Before implementing, check `spec/features/` for a relevant feature spec
2. For non-trivial work, create a work packet in `work/`
3. Every code change must trace to a task in the work packet
4. If a spec is unclear or incorrect, report a Spec Issue—do not guess
See `spec/guidelines/QUALITY_BAR.md` for what qualifies as "non-trivial."
## File Ownership ## File Ownership
**Never modify** files in `spec/guidelines/`.
If a guideline seems wrong or incomplete, report it as a Spec Issue.
| Path | Owner | AI May Modify | | Path | Owner | AI May Modify |
|------|-------|---------------| |------|-------|---------------|
| `spec/guidelines/*` | Human | No | | `spec/guidelines/*` | Human | No |
| `spec/features/*` | Human | No (unless explicitly asked) | | `spec/features/*` | Human | No (unless asked) |
| `work/*.md` | AI | Yes | | `spec/work/*.md` | AI | Yes |
| `lib/**` | Shared | Yes | | `spec/knowledge/*.md` | AI | Yes |
| `test/**` | Shared | Yes | | `lib/**`, `test/**` | Shared | Yes |
| `AGENTS.md` | Human | No |
## Working Rules ## Key Commands
```bash
fvm flutter pub get # Dependencies
fvm flutter analyze # Lint
fvm flutter test # Tests
```
## Project Rules
- Prefer small, localized changes. Avoid unrelated refactors.
- After dependency changes, run: `fvm flutter pub get`
- Fix any analyze/lint errors introduced by your changes.
- Assume Android as default target unless instructed otherwise. - Assume Android as default target unless instructed otherwise.
+5
View File
@@ -1,3 +1,8 @@
---
description: Architecture — layers, dependency rules, ownership, common Dart/Flutter patterns
alwaysApply: true
---
# Zapstore — Architecture # Zapstore — Architecture
## Core Principle ## Core Principle
+5
View File
@@ -1,3 +1,8 @@
---
description: Non-negotiable invariants — UI safety, async discipline, local-first, security, lifecycle
alwaysApply: true
---
# Zapstore — Invariants # Zapstore — Invariants
The following guarantees are non-negotiable. The following guarantees are non-negotiable.
+24 -1
View File
@@ -1,3 +1,8 @@
---
description: Quality expectations — when to spec, layer standards, testing, anti-patterns, AI workflow
alwaysApply: true
---
# Zapstore — Quality Bar # Zapstore — Quality Bar
## General Expectations ## General Expectations
@@ -66,6 +71,20 @@ If multiple phases: `WORK-005-a.md`, `WORK-005-b.md` (same feature number).
- Failure, cancellation, and degraded-network paths must be covered. - Failure, cancellation, and degraded-network paths must be covered.
- Tests that only assert the happy path are insufficient. - Tests that only assert the happy path are insufficient.
### Test layers
- **Widget tests** (`flutter test`): preferred for UI state machines, all states
(loading, empty, error, retry). Fully headless, no device needed.
- **Integration tests** (`flutter test integration_test/`): used for flows that
cross platform boundaries — downloads, installs, storage, notifications.
Run against a connected Android emulator or device via ADB.
- **Patrol** is the integration test framework. Use `patrolTest` and `$.native`
for interacting with Android system UI (e.g. PackageInstaller dialogs).
Do not use `testWidgets` for integration tests.
- Pre-grant `REQUEST_INSTALL_PACKAGES` via
`adb shell appops set <package> REQUEST_INSTALL_PACKAGES allow`
before running install tests, to avoid a permissions setup screen.
## Anti-Patterns ## Anti-Patterns
- Silent failures - Silent failures
@@ -91,7 +110,7 @@ This project uses a spec-first workflow to collaborate safely with AI.
### What AI Owns ### What AI Owns
- Work packets under `work/` - Work packets under `spec/work/`
- Refinement of task plans during implementation - Refinement of task plans during implementation
### Spec-First Rule ### Spec-First Rule
@@ -109,3 +128,7 @@ For non-trivial work, changes are not complete unless:
- Edge cases and failure modes are addressed - Edge cases and failure modes are addressed
This workflow exists to prevent AI drift, accidental refactors, and UX regressions. This workflow exists to prevent AI drift, accidental refactors, and UX regressions.
## Knowledge Entries
After a work packet merges, promote non-obvious decisions to `spec/knowledge/DEC-XXX-*.md`. See `spec/knowledge/_TEMPLATE.md` for format and criteria.
+5
View File
@@ -1,3 +1,8 @@
---
description: Product vision — what Zapstore is, who it serves, what success means
alwaysApply: true
---
# Zapstore — Vision # Zapstore — Vision
## What Zapstore Is ## What Zapstore Is
+74
View File
@@ -0,0 +1,74 @@
---
date: YYYY-MM-DD
tags: [tag1, tag2, tag3]
problem: One-line description of the problem encountered
---
# DEC-XXX — Short Title
## Problem
What went wrong, or what was unclear. Concrete and specific.
## Context
Why this came up. What was being built. What made it non-obvious.
## Decision
What was chosen. One clear statement.
## Options Considered
- **Option A** — description, why rejected
- **Option B** — description, why rejected
- **Option C (chosen)** — description, why selected
## Rationale
Why this option fits this codebase, this team, this context.
## How to Avoid This Problem Next Time
Concrete rule or pattern an agent can follow automatically:
- Do X instead of Y
- When you see Z, always do W
- Reference: `path/to/example.go` shows the correct pattern
---
# Example: DEC-001 — Separate polling from local watching
---
date: 2026-02-04
tags: [state-management, providers, riverpod, skeleton]
problem: Mixed local/remote data in one provider caused skeleton showing during refreshes
---
## Problem
The updates screen showed a skeleton loading state during every pull-to-refresh, even when data was already loaded locally.
## Context
Building the updates screen. A single `CategorizedUpdatesNotifier` was both watching local DB and performing remote fetches. Timer-based invalidation triggered network requests on every rebuild.
## Decision
Split into two providers: one owns remote polling, one watches local data only.
## Options Considered
- **Single provider** — simpler, but mixing concerns caused skeleton/loading state confusion
- **Split providers (chosen)** — `UpdatePollerNotifier` (remote) + `CategorizedUpdatesNotifier` (local only)
## Rationale
Local provider is purely reactive — it never triggers network. Remote provider handles network + throttling. Clear separation means skeleton logic is simple: show only when no local data matches.
## How to Avoid This Problem Next Time
- Never mix `RemoteSource` and `LocalSource` queries in the same provider
- If a provider needs both local reactivity and remote fetching, split it
- Skeleton rule: `showSkeleton = installedIds.isNotEmpty && !hasAnyMatch` — once any match exists, never show skeleton again
- See `lib/services/updates_service.dart` for the correct pattern
@@ -40,6 +40,10 @@ Report blockers here instead of guessing. Format:
Brief updates as work proceeds. Brief updates as work proceeds.
## On Merge
Delete this work packet. If any decision here is non-obvious and worth remembering, promote it to `spec/knowledge/DEC-XXX-short-title.md` first.
--- ---
# Example: WORK-002 — NWC Zaps # Example: WORK-002 — NWC Zaps