Compare commits

...

2 Commits

Author SHA1 Message Date
mansi.kansara da64f769da feat(flutter-cursor-templates): introduce MCP integration and conventions in project brief
- Added optional MCP integration settings in project-brief.yaml, allowing for environment-based server configurations.
- Introduced conventions for strict package imports to enhance code organization and maintainability.
- Updated brief schema to validate new MCP properties and ensure correct usage.
- Implemented MCP JSON builder to generate .cursor/mcp.json based on project brief settings.
- Enhanced resolver to include MCP configuration in generated files when enabled.

This update improves integration capabilities and enforces coding standards across the project.
2026-05-14 13:33:13 +05:30
mansi.kansara 2ee257c630 feat(flutter-cursor-templates): add /debug, /verify, /explain skills and goldens.
Wire debug-issue, verify-change, and explain-code into the universal resolver with reasons, extend AGENTS.md slash list, cross-link build Phase 3 and Phase 6, refresh generator goldens for three stacks, and note cross-skill links in the build skill design spec.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 12:38:13 +05:30
130 changed files with 3350 additions and 182 deletions
@@ -205,6 +205,14 @@ The `/build` skill orchestrates existing skills internally:
- Invokes `/generate-api-client` if `api_docs.format != none` and feature needs API (Phase 2)
- References `/deploy` checklist for flavor-scoped secret handling (Phase 7)
Generated alongside `/build` (same `cursor_gen` bundle) for lifecycle support:
- **`/debug`** (`debug-issue` skill) — structured BugReport + evidence before fixes; use when Phase 6 checks fail with unclear errors or weak reproduction.
- **`/verify`** (`verify-change` skill) — pasted-evidence gate for tests/analyze/hooks without walking the full seven-phase build doc; use for small PRs or post-fix sanity checks.
- **`/explain`** (`explain-code` skill) — read-only walkthrough of code paths; use when research needs human answers about runtime or native behavior before implementation.
The generated `build` skill template also cross-links **Phase 3** (TDD loop) and **Phase 6** (verification failures) to **`/debug`** and **`/verify`** so agents escalate without re-reading the full seven-phase doc.
---
## 9. Rules Applied Every Phase
+11
View File
@@ -116,6 +116,17 @@ localization:
enabled: true
locales: ["en", "es", "fr"]
# -----------------------------------------------------------------------------
# Integrations & conventions (optional)
# -----------------------------------------------------------------------------
integrations:
mcp:
enabled: false # true → .cursor/mcp.json (secrets only via env vars)
preset: auto # auto | minimal
conventions:
strict_package_imports: false
# -----------------------------------------------------------------------------
# Telemetry (Pillar 6) — local-only generation / usage log under .cursor/
# -----------------------------------------------------------------------------
@@ -162,6 +162,38 @@
"type": "boolean",
"description": "Pillar 6: Opt-in local telemetry for rule trigger analytics",
"default": false
},
"integrations": {
"type": "object",
"description": "Optional third-party integrations for generated Cursor config",
"properties": {
"mcp": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": false,
"description": "When true, emit .cursor/mcp.json with env-placeholder server stubs only"
},
"preset": {
"type": "string",
"enum": ["auto", "minimal"],
"default": "auto",
"description": "minimal = empty mcpServers; auto = brief-derived stubs (still no committed secrets)"
}
}
}
}
},
"conventions": {
"type": "object",
"properties": {
"strict_package_imports": {
"type": "boolean",
"default": false,
"description": "When true, flutter-core rule enforces package: imports across feature boundaries"
}
}
}
}
}
@@ -22,6 +22,9 @@ class BriefLoader {
final appCtx = yaml['app_context'] as YamlMap? ?? YamlMap();
final features = yaml['features'] as YamlMap? ?? YamlMap();
final l10n = yaml['localization'] as YamlMap? ?? YamlMap();
final integrations = yaml['integrations'] as YamlMap? ?? YamlMap();
final mcp = integrations['mcp'] as YamlMap? ?? YamlMap();
final conventions = yaml['conventions'] as YamlMap? ?? YamlMap();
// Parse backends (can be "firebase+rest" shorthand or list)
final backendRaw = stack['backend']?.toString() ?? 'rest';
@@ -75,6 +78,11 @@ class BriefLoader {
}(),
rolesEnabled: appCtx['roles_enabled'] as bool? ?? false,
roleNames: _toStringList(appCtx['role_names']) ?? [],
mcpConfigEnabled: mcp['enabled'] as bool? ?? false,
mcpPreset: mcp['preset']?.toString() ?? 'auto',
strictPackageImports:
conventions['strict_package_imports'] as bool? ?? false,
);
}
@@ -0,0 +1,88 @@
// mcp_json.dart — Builds .cursor/mcp.json from project brief (env placeholders only).
import 'dart:convert';
import 'models.dart';
class McpJsonBuilder {
/// JSON string for Cursor MCP config. Never embed secrets — use `\${VAR}` in strings.
static String build(ProjectBrief brief) {
if (brief.mcpPreset == 'minimal') {
return const JsonEncoder.withIndent(' ')
.convert(<String, dynamic>{'mcpServers': <String, dynamic>{}});
}
final servers = <String, Map<String, dynamic>>{
'filesystem': {
'command': 'npx',
'args': ['-y', '@modelcontextprotocol/server-filesystem', '.'],
'description': 'Read/write project files under the workspace root',
},
'flutter-docs': {
'command': 'npx',
'args': ['-y', '@modelcontextprotocol/server-fetch'],
'env': {'BASE_URL': 'https://api.flutter.dev/flutter'},
'description': 'Flutter API documentation lookup',
},
'dart-pub': {
'command': 'npx',
'args': ['-y', '@modelcontextprotocol/server-fetch'],
'env': {'BASE_URL': 'https://pub.dev/api'},
'description': 'Pub.dev package metadata and versions',
},
'github': {
'command': 'npx',
'args': ['-y', '@modelcontextprotocol/server-github'],
'env': {'GITHUB_TOKEN': r'${GITHUB_TOKEN}'},
'description': 'GitHub issues and PR context (requires GITHUB_TOKEN)',
},
};
if (brief.backends.contains('firebase')) {
servers['firebase'] = {
'command': 'npx',
'args': ['-y', '@modelcontextprotocol/server-firebase'],
'env': {'FIREBASE_PROJECT': r'${FIREBASE_PROJECT_ID}'},
'description':
'Firebase project context (configure FIREBASE_PROJECT_ID)',
};
}
if (brief.designSource == 'figma_mcp') {
servers['figma'] = {
'url': 'https://mcp.figma.com/mcp',
'type': 'http',
'headers': {
'Authorization': r'Bearer ${FIGMA_ACCESS_TOKEN}',
},
'description':
'Figma MCP — set FIGMA_ACCESS_TOKEN (never commit the value)',
};
}
if (brief.backends.contains('supabase')) {
servers['supabase'] = {
'command': 'npx',
'args': ['-y', '@supabase/mcp-server-supabase@latest'],
'env': {
'SUPABASE_ACCESS_TOKEN': r'${SUPABASE_ACCESS_TOKEN}',
},
'description': 'Supabase MCP — token from env only',
};
}
if (brief.apiDocsFormat == 'openapi' && brief.apiDocsPath.isNotEmpty) {
servers['openapi-ref'] = {
'command': 'npx',
'args': ['-y', '@modelcontextprotocol/server-fetch'],
'env': {
'OPENAPI_SPEC_URL': r'${OPENAPI_SPEC_URL}',
},
'description':
'Optional fetch MCP — point OPENAPI_SPEC_URL at a hosted spec or file:// URL you expose locally',
};
}
return const JsonEncoder.withIndent(' ').convert({'mcpServers': servers});
}
}
@@ -59,6 +59,15 @@ class ProjectBrief {
final bool rolesEnabled;
final List<String> roleNames;
/// When true, emit `.cursor/mcp.json` with safe env-placeholder servers.
final bool mcpConfigEnabled;
/// When [mcpConfigEnabled]: `minimal` (empty `mcpServers`) or `auto` (stubs from brief).
final String mcpPreset;
/// When true, generated flutter-core rule enforces package imports (no cross-feature relatives).
final bool strictPackageImports;
const ProjectBrief({
required this.projectName,
required this.packageId,
@@ -90,6 +99,9 @@ class ProjectBrief {
this.themeVariants = const ['light', 'dark'],
this.rolesEnabled = false,
this.roleNames = const [],
this.mcpConfigEnabled = false,
this.mcpPreset = 'auto',
this.strictPackageImports = false,
});
/// Local snapshot for tooling (written as `cursor-gen-metadata.json` under the output dir).
@@ -2,6 +2,7 @@
import 'dart:io';
import 'package:path/path.dart' as p;
import 'mcp_json.dart';
import 'models.dart';
class Renderer {
@@ -10,22 +11,32 @@ class Renderer {
required List<String> templateFiles,
required String templateSrc,
}) async {
final context = _buildContext(brief);
final baseContext = _buildContext(brief);
final output = <String, String>{};
for (final key in templateFiles) {
if (key == 'config/mcp-json') {
output['mcp.json'] = McpJsonBuilder.build(brief);
continue;
}
final outPath = _outputPath(key);
final tmplPath = _templatePath(templateSrc, key);
final file = File(tmplPath);
if (!file.existsSync()) {
// Gracefully skip missing optional templates with a placeholder
output[_outputPath(key)] = _missingTemplatePlaceholder(key);
output[outPath] = _missingTemplatePlaceholder(key);
continue;
}
var content = await file.readAsString();
content = _substituteAll(content, context);
_checkUnreplacedPlaceholders(
content, key); // Pillar 3: validate no broken {{VAR}}
output[_outputPath(key)] = content;
final ctx = Map<String, String>.from(baseContext);
if (key.startsWith('rules/features/')) {
final slug = p.basename(key);
ctx['FEATURE_MODULE'] = slug;
ctx['FEATURE_MODULE_TITLE'] = _titleCase(slug);
}
content = _substituteAll(content, ctx);
_checkUnreplacedPlaceholders(content, key);
output[outPath] = content;
}
return output;
}
@@ -71,9 +82,35 @@ class Renderer {
'TEST_PATTERN': _testPattern(brief.stateManagement),
'LOCALES_LIST': brief.locales.join(', '),
'TEMPLATE_VERSION': '1.0.4',
'IMPORT_POLICY_BLOCK': _importPolicyBlock(brief.strictPackageImports),
};
}
static String _titleCase(String slug) {
if (slug.isEmpty) return slug;
return slug
.split('_')
.where((w) => w.isNotEmpty)
.map((w) => '${w[0].toUpperCase()}${w.substring(1)}')
.join(' ');
}
static String _importPolicyBlock(bool strictPackage) {
if (strictPackage) {
return '''
### Imports (strict — `conventions.strict_package_imports: true`)
- Use `package:<your_pubspec_name>/...` imports everywhere in `lib/` and `test/` — **no** relative `../` across feature boundaries (the brief `project.package` id is often the app bundle id; prefer the **pubspec.yaml `name`** for Dart imports)
- Barrel files (`index.dart`) at feature roots; do not wildcard re-export third-party packages
''';
}
return '''
### Imports (default)
- Order: `dart:` → `package:` → relative
- Relative imports are allowed **within** the same feature directory; use `package:` imports for cross-feature code
- Never import another feature's internals from outside that feature
''';
}
static String _substituteAll(String content, Map<String, String> ctx) {
for (final entry in ctx.entries) {
content = content.replaceAll('{{${entry.key}}}', entry.value);
@@ -107,6 +144,25 @@ class Renderer {
}
return p.join(templateSrc, 'hooks', '${p.basename(key)}.ts.tmpl');
}
if (key.startsWith('commands/')) {
final name = p.basename(key);
return p.join(templateSrc, 'commands', '$name.md.tmpl');
}
if (key == 'onboarding/ONBOARDING') {
return p.join(templateSrc, 'onboarding', 'ONBOARDING.md.tmpl');
}
if (key.startsWith('telemetry/')) {
final leaf = p.basename(key);
if (leaf == 'gitignore') {
return p.join(templateSrc, 'telemetry', 'gitignore.tmpl');
}
if (leaf == 'log-sh') {
return p.join(templateSrc, 'telemetry', 'log.sh.tmpl');
}
}
if (key.startsWith('rules/features/')) {
return p.join(templateSrc, 'rules', 'features', '_stub.mdc.tmpl');
}
return p.join(templateSrc, '$key.mdc.tmpl');
}
@@ -122,6 +178,22 @@ class Renderer {
if (key.endsWith('hooks-json')) return 'hooks/hooks.json';
return 'hooks/${p.basename(key)}.ts';
}
if (key.startsWith('commands/')) {
final name = p.basename(key);
return 'commands/$name.md';
}
if (key == 'onboarding/ONBOARDING') {
return 'ONBOARDING.md';
}
if (key == 'telemetry/gitignore') {
return 'telemetry/.gitignore';
}
if (key == 'telemetry/log-sh') {
return 'telemetry/log.sh';
}
if (key == 'config/mcp-json') {
return 'mcp.json';
}
return '${key.replaceAll('rules/', 'rules/')}.mdc';
}
@@ -8,6 +8,9 @@ class Resolver {
static List<String> resolve(ProjectBrief brief) {
final files = <String>[];
// ── Meta: rule authoring (first — governs other .mdc files) ─────────
files.add('rules/universal/rule-authoring');
// ── Universal (every project) ──────────────────────────────────────
files.addAll([
'rules/universal/flutter-core',
@@ -15,6 +18,11 @@ class Resolver {
'rules/universal/project-context',
]);
// ── Theming tokens (when high contrast or extra variants) ───────────
if (_emitThemingRule(brief)) {
files.add('rules/theming/theming');
}
// ── Security (Pillar 5: always-on, not just for large/auth projects) ──
files.add('rules/security/security-standards');
@@ -28,11 +36,19 @@ class Resolver {
files.add('rules/architecture/${brief.architecture}');
// ── Backend — one or more ─────────────────────────────────────────
for (final b in brief.backends) files.add('rules/backend/$b');
for (final b in brief.backends) {
files.add('rules/backend/$b');
}
if (brief.specialFeatures.contains('realtime')) {
files.add('rules/backend/realtime');
}
// ── Push / deep linking ───────────────────────────────────────────
if (brief.specialFeatures.contains('push_notifications') ||
brief.specialFeatures.contains('deep_linking')) {
files.add('rules/integrations/push-deeplink');
}
// ── Routing — exactly one ─────────────────────────────────────────
files.add('rules/routing/${brief.routing}');
@@ -67,16 +83,32 @@ class Resolver {
files.add('rules/i18n/localization');
}
// ── CI/CD + flavours ─────────────────────────────────────────────
if (brief.cicd != 'none' || brief.flavors.length > 1) {
files.add('rules/cicd/cicd');
}
// ── Feature-scoped rule stubs ─────────────────────────────────────
final featureKeys = <String>{};
for (final m in brief.featureModules) {
final k = featureRuleKey(m);
if (k != null) featureKeys.add(k);
}
files.addAll(featureKeys);
// ── Skills ────────────────────────────────────────────────────────
files.addAll([
'skills/scaffold-feature',
'skills/scaffold-screen',
'skills/generate-tests',
'skills/build',
'skills/debug-issue',
'skills/verify-change',
'skills/explain-code',
]);
if (brief.apiDocsFormat != 'none') files.add('skills/generate-api-client');
if (brief.flavors.length > 1) files.add('skills/create-flavor');
if (brief.cicd.isNotEmpty) files.add('skills/deploy');
if (brief.cicd != 'none') files.add('skills/deploy');
// ── Agents ────────────────────────────────────────────────────────
files.addAll([
@@ -94,11 +126,51 @@ class Resolver {
files.add('agents/migration-agent');
}
// ── Cursor workspace extras (reference architecture) ────────────────
files.addAll([
'root/.cursorignore',
'root/tool/cursor_audit.sh',
'onboarding/ONBOARDING',
'commands/build',
'commands/debug-issue',
'commands/verify-change',
'commands/explain-code',
]);
if (brief.mcpConfigEnabled) {
files.add('config/mcp-json');
}
if (brief.telemetryOptIn) {
files.addAll([
'telemetry/gitignore',
'telemetry/log-sh',
'rules/telemetry/usage-logging',
]);
}
files.addAll(['root/AGENTS.md', 'root/lefthook.yaml']);
return files;
}
/// `lib/features/<slug>/` ↔ `rules/features/<slug>.mdc`
static String? featureRuleKey(String module) {
var s = module
.trim()
.toLowerCase()
.replaceAll(RegExp(r'[^a-z0-9]+'), '_');
s = s.replaceAll(RegExp(r'_+'), '_');
s = s.replaceAll(RegExp(r'(^_+|_+$)'), '');
if (s.isEmpty) return null;
return 'rules/features/$s';
}
static bool _emitThemingRule(ProjectBrief brief) {
return brief.themeVariants.contains('high_contrast') ||
brief.themeVariants.length > 2;
}
/// Returns human-readable description of why each file was included
static Map<String, String> resolveWithReasons(ProjectBrief brief) {
final resolved = resolve(brief);
@@ -110,26 +182,100 @@ class Resolver {
}
static String _reason(String key, ProjectBrief brief) {
if (key == 'rules/universal/rule-authoring') {
return 'Always included — meta rules for authoring .cursor/rules';
}
if (key.contains('universal')) return 'Always included';
if (key.contains('security')) return 'Always included — Pillar 5';
if (key == 'rules/theming/theming') {
return 'Theme variants include high contrast or extended set';
}
if (key.contains('security')) {
return 'Always included — Pillar 5';
}
if (key.contains('error-handling')) return 'Always included';
if (key.contains('state-management')) return 'Matches stack.state_management: ${brief.stateManagement}';
if (key.contains('architecture')) return 'Matches stack.architecture: ${brief.architecture}';
if (key.contains('routing')) return 'Matches stack.routing: ${brief.routing}';
if (key.contains('testing-e2e')) return 'testing.depth includes e2e';
if (key.contains('testing')) return 'Matches state_management testing patterns';
if (key.contains('platform')) return 'Matches stack.platforms';
if (key.contains('state-management')) {
return 'Matches stack.state_management: ${brief.stateManagement}';
}
if (key.contains('architecture')) {
return 'Matches stack.architecture: ${brief.architecture}';
}
if (key == 'rules/integrations/push-deeplink') {
return 'features.special includes push_notifications or deep_linking';
}
if (key.contains('routing')) {
return 'Matches stack.routing: ${brief.routing}';
}
if (key.contains('testing-e2e')) {
return 'testing.depth includes e2e';
}
if (key.contains('testing')) {
return 'Matches state_management testing patterns';
}
if (key.contains('platform')) {
return 'Matches stack.platforms';
}
if (key.startsWith('hooks/')) {
return 'stack.codegen non-empty — Cursor hooks for analyze, boundaries, and tests';
}
if (key.contains('codegen')) return 'Matches stack.codegen';
if (key.contains('i18n')) return 'localization.enabled: true';
if (key.contains('migration')) return 'state_management is GetX — migration guidance included';
if (key.contains('security-agent')) return 'scale: ${brief.scale} or auth is configured';
if (key == 'skills/build') return 'Always included — universal TDD-first feature implementation command';
if (key.contains('api-client')) return 'api_docs.format is set';
if (key.contains('realtime')) return 'features.special contains realtime';
if (key.startsWith('root/')) return 'Repo-level companion files';
if (key.contains('codegen')) {
return 'Matches stack.codegen';
}
if (key.contains('i18n')) {
return 'localization.enabled: true';
}
if (key == 'rules/cicd/cicd') {
return 'environments.cicd is set or multiple flavors';
}
if (key.startsWith('rules/features/')) {
return 'Listed under features.modules in project-brief.yaml';
}
if (key.contains('migration')) {
return 'state_management is GetX — migration guidance included';
}
if (key.contains('security-agent')) {
return 'scale: ${brief.scale} or auth is configured';
}
if (key == 'skills/build') {
return 'Always included — universal TDD-first feature implementation command';
}
if (key == 'skills/debug-issue') {
return 'Always included — structured bug triage and evidence-first debugging';
}
if (key == 'skills/verify-change') {
return 'Always included — pre-PR verification checklist without full /build lifecycle';
}
if (key == 'skills/explain-code') {
return 'Always included — explain-only walkthrough of code paths and stack behavior';
}
if (key.contains('api-client')) {
return 'api_docs.format is set';
}
if (key.contains('realtime')) {
return 'features.special contains realtime';
}
if (key == 'root/.cursorignore') {
return 'Root ignore patterns for Cursor indexing';
}
if (key == 'root/tool/cursor_audit.sh') {
return 'Maintenance script for rule drift checks';
}
if (key == 'onboarding/ONBOARDING') {
return 'Team onboarding for Cursor layout and slash skills';
}
if (key.startsWith('commands/')) {
return 'Project slash command → skill mapping';
}
if (key == 'config/mcp-json') {
return 'integrations.mcp.enabled: true in project-brief.yaml';
}
if (key == 'telemetry/gitignore' ||
key == 'telemetry/log-sh' ||
key == 'rules/telemetry/usage-logging') {
return 'telemetry_opt_in: true — local usage logging helpers';
}
if (key.startsWith('root/')) {
return 'Repo-level companion files';
}
return 'Included';
}
}
@@ -52,6 +52,7 @@ class Validator {
};
static const _validApiFormats = {'openapi', 'postman', 'markdown', 'none'};
static const _validThemeVariants = {'light', 'dark', 'high_contrast'};
static const _validMcpPresets = {'auto', 'minimal'};
static Future<ValidationResult> validateFile(String path) async {
final file = File(path);
@@ -178,6 +179,18 @@ class Validator {
}
}
final integrations = yaml['integrations'] as YamlMap?;
if (integrations != null) {
final mcp = integrations['mcp'] as YamlMap?;
if (mcp != null) {
final preset = mcp['preset']?.toString();
if (preset != null && !_validMcpPresets.contains(preset)) {
warnings.add(
'integrations.mcp.preset "$preset" is not valid. Use: ${_validMcpPresets.join(", ")}');
}
}
}
return ValidationResult(
isValid: errors.isEmpty,
errors: errors,
@@ -214,6 +227,10 @@ class Validator {
if (brief.rolesEnabled && brief.roleNames.isEmpty) {
warnings.add('roles_enabled is true but role_names is empty');
}
if (!_validMcpPresets.contains(brief.mcpPreset)) {
warnings.add(
'integrations.mcp.preset "${brief.mcpPreset}" is not valid. Use: ${_validMcpPresets.join(", ")}');
}
return ValidationResult(
isValid: errors.isEmpty, errors: errors, warnings: warnings);
@@ -0,0 +1 @@
End-to-end feature implementation (research, TDD, integration tests, verification). Follow the workflow and constraints in `@file:.cursor/skills/build/SKILL.md`. Use `project-brief.yaml` as the source of truth for stack and platforms.
@@ -0,0 +1 @@
Structured bug triage and evidence-first debugging. Follow `@file:.cursor/skills/debug-issue/SKILL.md`. Gather reproduction steps, logs, and failing commands before proposing fixes.
@@ -0,0 +1 @@
Explain-only walkthrough of code paths and stack behavior (no edits). Follow `@file:.cursor/skills/explain-code/SKILL.md`. Do not modify source files unless the user explicitly asks.
@@ -0,0 +1 @@
Pre-PR verification checklist (analyze, tests, hooks) without full /build lifecycle. Follow `@file:.cursor/skills/verify-change/SKILL.md` for the change in scope.
@@ -0,0 +1,20 @@
# Cursor — {{PROJECT_NAME}}
## Quick start
1. Open this repo in **Cursor** so `.cursor/rules/` and `.cursor/skills/` load automatically.
2. Read **`rules/universal/rule-authoring.mdc`** — how we maintain AI rules.
3. Stack and product context live in **`project-brief.yaml`** at the repo root; regenerate `.cursor/` with `cursor_gen` after changing it.
4. **Slash skills** (primary workflows): open the Command Palette and use the project commands, or reference:
- `.cursor/skills/build/SKILL.md` — end-to-end feature implementation
- `.cursor/skills/debug-issue/SKILL.md` — structured debugging
- `.cursor/skills/verify-change/SKILL.md` — pre-PR verification
- `.cursor/skills/explain-code/SKILL.md` — explain-only walkthroughs
5. **Agents** (`.cursor/agents/*.mdc`) are reusable reviewer personas — attach when asking for code review or focused passes.
6. **Custom overrides**: files under `.cursor/custom/` and `CURSOR:CUSTOM` blocks in generated files are preserved on `cursor_gen --refresh` (see generator docs).
## Optional
- **`integrations.mcp.enabled`** in `project-brief.yaml` — generates `.cursor/mcp.json` with env-based server entries (no secrets in git).
- **`telemetry_opt_in: true`** — emits local telemetry helpers under `.cursor/telemetry/` (never commit usage logs if you enable logging).
- Run **`bash tool/cursor_audit.sh`** from the project root periodically to catch stale feature rules and overly broad `alwaysApply` usage.
@@ -0,0 +1,27 @@
# Build artefacts
build/
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
*.g.dart
*.freezed.dart
*.gr.dart
*.config.dart
# Secrets
.env
.env.*
firebase_options.dart
google-services.json
GoogleService-Info.plist
# Large binary assets
assets/fonts/
assets/videos/
*.aab
*.apk
*.ipa
# IDE
.idea/
*.iml
@@ -3,3 +3,5 @@
Repo-level notes for AI assistants. Authoritative stack and conventions are in `project-brief.yaml` and `.cursor/` (regenerate with `cursor_gen` from the project root).
- **Package:** `{{PACKAGE_ID}}`
- **Onboarding:** `.cursor/ONBOARDING.md` — layout, slash commands → skills, MCP opt-in, audits
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain` (see `.cursor/commands/*.md`)
@@ -1,4 +1,5 @@
# {{PROJECT_NAME}} — generated by cursor_gen; adjust commands to your repo
# Optional: run `bash tool/cursor_audit.sh` after changing features.modules or rule files.
pre-commit:
commands:
flutter-analyze:
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# {{PROJECT_NAME}} — Cursor rule hygiene (generated by cursor_gen)
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CURSOR="${ROOT}/.cursor"
RULES="${CURSOR}/rules"
echo "== cursor_audit (${ROOT}) =="
if [[ ! -d "$CURSOR" ]]; then
echo "ERROR: missing ${CURSOR}"
exit 1
fi
if [[ -d "$RULES" ]]; then
ac="$(grep -R "alwaysApply: true" "$RULES" --include='*.mdc' 2>/dev/null | wc -l | tr -d ' ')"
echo "alwaysApply: true occurrences in .cursor/rules: ${ac}"
echo " (expect a small number — meta/safety; prefer scoped globs for domain rules)"
else
echo "WARN: no ${RULES}"
fi
if [[ -d "$RULES/features" ]]; then
shopt -s nullglob
for f in "$RULES/features"/*.mdc; do
base="$(basename "$f" .mdc)"
if [[ ! -d "${ROOT}/lib/features/${base}" ]] && [[ ! -d "${ROOT}/lib/feature_${base}" ]]; then
echo "WARN: rules/features/${base}.mdc has no obvious lib/features/${base} folder — update features.modules or lib layout"
fi
done
shopt -u nullglob
fi
echo "OK — review warnings above after brief or folder renames"
@@ -0,0 +1,29 @@
---
description: CI/CD, flavours, and quality gates for {{PROJECT_NAME}}
globs: [".github/**", "codemagic.yaml", "Makefile", "pubspec.yaml", "fastlane/**"]
alwaysApply: false
---
# CI/CD & flavours — {{PROJECT_NAME}}
## Context
Pipeline and flavour setup must stay aligned with how the app is built and released.
## Flavours
- Documented in `project-brief.yaml`: **{{FLAVORS_LIST}}**
- Use `--flavor` / `-t lib/main_<flavour>.dart` (or your projects entrypoints) consistently across local, CI, and store builds
- Configuration via `--dart-define` / `--dart-define-from-file` — **never** hardcode secrets in source
## Quality gates (recommended stages)
- **Lint:** `dart format --set-exit-if-changed .` and `flutter analyze`
- **Unit + widget:** `flutter test` (with coverage if the team tracks it)
- **Goldens:** fixed device/locale; CI fails on drift unless intentionally updated
- **Smoke build:** e.g. `flutter build apk` or `flutter build ios --no-codesign` for the primary flavour
- **E2E:** when `testing.depth` includes e2e — {{E2E_TOOL}} on CI devices or Firebase Test Lab
## Cursor integration
- After substantive edits: run analyze and relevant tests before PR
- For release-oriented tasks, use the **deploy** skill at `.cursor/skills/deploy/SKILL.md` when present
## CI/CD tool
- Selected in brief: **{{CICD_TOOL}}** (`{{CICD_RAW}}`)
@@ -0,0 +1,21 @@
---
description: "Feature module {{FEATURE_MODULE}} — contracts, boundaries, and ownership (fill after design)"
globs: ["lib/**/{{FEATURE_MODULE}}/**", "test/**/{{FEATURE_MODULE}}/**"]
alwaysApply: false
---
# Feature — {{FEATURE_MODULE_TITLE}}
## Context
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `{{FEATURE_MODULE}}` so agents do not invent cross-feature wiring.
## Constraints
- List external dependencies (other features, packages, backend endpoints) explicitly
- Document invariants (auth required, idempotency, offline behavior) when known
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
## Patterns
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
## Anti-patterns
- Empty file left forever — either fill it or delete the module entry from the brief
@@ -1,6 +1,7 @@
---
description: "Localization / i18n conventions for {{PROJECT_NAME}}"
alwaysApply: true
globs: ["lib/l10n/**", "lib/**/*.dart", "test/**/*.dart"]
alwaysApply: false
---
# Localization Standards — {{PROJECT_NAME}}
@@ -0,0 +1,21 @@
---
description: Push notifications and deep linking for {{PROJECT_NAME}}
globs: ["lib/**/*.dart", "android/**", "ios/**", "test/**/*.dart"]
alwaysApply: false
---
# Push & deep linking — {{PROJECT_NAME}}
## Context
Special capabilities from `project-brief.yaml`: **{{SPECIAL_FEATURES}}**. Native and server configuration must stay consistent.
## Constraints
- **Push:** request permissions through the platform flow; handle denial gracefully; no silent failures on token registration
- **Routing:** deep links and notification taps MUST go through **{{ROUTING}}** (no ad-hoc `Navigator` stacks for inbound links)
- **Payloads:** map FCM/APNs/Supabase payloads to domain models in the data layer — no JSON parsing scattered in widgets
- **iOS:** exercise push on a **physical device** when possible (simulator limitations)
- **Android:** declare required permissions explicitly; target API behaviour for POST_NOTIFICATIONS where applicable
## Testing
- Unit-test payload → domain mapping and routing targets
- Integration/E2E: cold start, background, and foreground tap-to-open flows when `testing.depth` allows
@@ -0,0 +1,19 @@
---
description: "Policy for optional local AI usage logs under .cursor/telemetry/"
globs: [".cursor/telemetry/**"]
alwaysApply: false
---
# Telemetry — {{PROJECT_NAME}}
## Context
When `telemetry_opt_in: true`, this repo may record **local-only** generation or usage notes under `.cursor/telemetry/`. This is **not** production analytics.
## Constraints
- **Never** commit secrets, tokens, or PII into JSONL or shell history
- Prefer redacted summaries over raw prompts
- Add `.cursor/telemetry/*.jsonl` to `.gitignore` unless your team explicitly version-controls sanitized samples
## Patterns
- Append one JSON object per line (JSONL) with ISO timestamps and event type
- Rotate or truncate files if they grow beyond a few MB
@@ -0,0 +1,20 @@
---
description: Semantic colours and theme extensions for {{PROJECT_NAME}}
globs: ["lib/**/*.dart", "test/**/*.dart"]
alwaysApply: false
---
# Theming — {{PROJECT_NAME}}
## Context
Theme variants from brief: **{{THEME_SUMMARY}}**.{{HIGH_CONTRAST_NOTE}}
## Constraints
- Prefer **`ThemeExtension`** (or design-system equivalents) for app-specific colours and radii — avoid raw `Color(0xFF...)` in feature code except in central token definitions
- Use **`Theme.of(context).colorScheme`** / `TextTheme` for Material-aligned roles where appropriate
- **High contrast:** when supported, verify WCAG contrast for text and controls; never rely on colour alone for state (pair with icon or label){{HIGH_CONTRAST_UX_LINE}}
- Touch targets: respect platform minimums (e.g. ~48 logical pixels) for interactive widgets
## Anti-patterns
- Hard-coded `Colors.*` scattered across feature widgets instead of theme tokens
- Ignoring `MediaQuery.of(context).platformBrightness` / high-contrast modes when the product claims support
@@ -1,6 +1,7 @@
---
description: "Core Flutter conventions for {{PROJECT_NAME}} — always applied"
alwaysApply: true
description: "Core Flutter conventions for {{PROJECT_NAME}}"
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
alwaysApply: false
---
# Flutter Core Standards — {{PROJECT_NAME}}
@@ -29,10 +30,7 @@ alwaysApply: true
- Private members: `_camelCase`
## Imports
- Order: dart: → package: → relative
- Use relative imports within a feature; absolute for cross-feature
- Never import a feature's internal files from outside that feature
{{IMPORT_POLICY_BLOCK}}
## Code quality
- Max function length: 40 lines. Extract widgets and helpers aggressively
- No `print()` in production code — use a logging package
@@ -1,6 +1,7 @@
---
description: "Project context for {{PROJECT_NAME}} — always applied"
alwaysApply: true
description: "Stack summary and product context for {{PROJECT_NAME}}"
globs: ["project-brief.yaml", ".cursor/**/*.md", ".cursor/**/*.mdc", "pubspec.yaml"]
alwaysApply: false
---
# Project Context — {{PROJECT_NAME}}
@@ -0,0 +1,24 @@
---
description: How Cursor rules in this repository must be written and maintained.
globs: [".cursor/rules/**/*.mdc"]
alwaysApply: true
---
# Rule authoring — {{PROJECT_NAME}}
## Context
Rules are version-controlled contracts for AI assistants. Poor rules waste context and silently steer every edit.
## Constraints
- One focused concern per file; split broad topics instead of one mega-rule
- Every rule MUST have a clear `description` in frontmatter (one sentence)
- Prefer `alwaysApply: false` with **narrow** `globs` for domain rules — reserve `alwaysApply: true` for meta and safety
- `globs` must be as specific as possible — never `["**/*"]` unless tooling requires it
- Code samples in rules MUST be valid for this project (Dart/Flutter/YAML as appropriate)
- Deprecated guidance is removed, not left commented out
- Each substantive rule includes **Context** (why), **Constraints** (must/must not), and where helpful **Patterns** / **Anti-patterns**
## Anti-patterns
- Domain rules (testing, l10n, a feature) with `alwaysApply: true` — burns context
- Rules with no concrete examples when the topic is code-facing
- Stale feature rules after modules are removed — run `tool/cursor_audit.sh` periodically
@@ -1,6 +1,7 @@
---
description: "UI/UX standards for {{PROJECT_NAME}} — always applied"
alwaysApply: true
description: "UI/UX standards for {{PROJECT_NAME}}"
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
alwaysApply: false
---
# UI / UX Standards — {{PROJECT_NAME}}
@@ -346,6 +346,7 @@ Follow Red → Green → Refactor strictly. Show actual terminal output at each
flutter test test/features/[feature]/ --no-pub
```
**Paste the actual output here before proceeding.**
If failures are unclear or non-deterministic after one iteration, use **`/debug`** with full pasted output before guessing fixes.
### Step 3b — Green: Implement
@@ -371,6 +372,8 @@ Follow Red → Green → Refactor strictly. Show actual terminal output at each
**Paste the actual output here before proceeding.**
3. Run tests once more to confirm still green.
If output stays red or errors are ambiguous after two focused attempts, stop and use **`/debug`** with the full failing command and log before changing more code.
---
## Phase 4: Integration Test Generation
@@ -503,6 +506,8 @@ VERIFICATION REQUIRED — paste real output for each:
```
If any check fails: invoke `superpowers:systematic-debugging` to diagnose before retrying.
For noisy errors or weak reproduction, run **`/debug`** and fill the BugReport skeleton with logs before retrying.
For small, isolated changes, **`/verify`** is enough to re-check tests and analyze without re-reading this whole skill.
Do not proceed to Phase 7 until all four checks are green.
---
@@ -0,0 +1,86 @@
---
name: Debug issue
description: Triage failing tests, analyze, CI, or runtime errors with an evidence-first BugReport. Use /debug and paste logs; invokes systematic-debugging before fixes. Stack {{STATE_MANAGEMENT}} / {{ARCHITECTURE}} / {{BACKEND}} / {{PLATFORMS_LIST}}.
---
# Debug — {{PROJECT_NAME}}
Triage failures (tests, CI, runtime, or build) **without** jumping to fixes. Stay in hypothesis-and-evidence mode until root cause is stated.
**Stack context:** **{{STATE_MANAGEMENT}}** / **{{ARCHITECTURE}}** / **{{BACKEND}}** / platforms: {{PLATFORMS_LIST}}. Flavors: {{FLAVORS_LIST}}. Codegen: {{CODEGEN_LIST}}.
## Usage
```
/debug <what failed — paste error output, command, or symptom>
```
**Examples:**
- `/debug flutter test fails on auth_cubit_test — paste output`
- `/debug CI analyze step — paste log excerpt`
- `/debug app crashes on cold start after last change`
---
## Phase 0 — Normalize the report (BugReport)
Emit this skeleton **before** deep analysis. If the user already pasted logs, map them into the fields instead of re-asking.
| Field | Content |
|-------|---------|
| **Summary** | One line: what broke |
| **Expected** | What should happen |
| **Actual** | What happened (symptom + error text) |
| **Repro steps** | Numbered, minimal |
| **Scope / files touched** | Paths or PR slice |
| **Environment** | OS, Flutter/Dart version if known, device vs simulator, flavor |
| **Evidence** | Pasted command output, stack trace, or screenshot notes |
---
## Phase 1 — Evidence checklist (Flutter-aware)
Gather or request **concrete** evidence. Do not guess versions or config.
1. **`flutter doctor -v`** — paste output when environment is unknown or iOS/Android toolchain errors appear.
2. **Failing command** — full invocation + **verbatim** tail of output (e.g. `flutter test …`, `dart test …`, `flutter analyze`).
3. **`flutter analyze`** — if not already in the failure log, run or ask the user to run and paste.
4. **Flavors** — this project uses: **{{FLAVORS_LIST}}**. Confirm which flavor was active if the failure is env-specific.
5. **Platforms** — **{{PLATFORMS_LIST}}**. Narrow reproduction to the platform that failed when relevant.
6. **Codegen** — tools: **{{CODEGEN_LIST}}**. When this is not `none`, remind to run `dart run build_runner build --delete-conflicting-outputs` after generated files changed, and to align with `.cursor/hooks/` / `lefthook run pre-commit` when hooks are present.
7. **Testing depth** — **{{TESTING_DEPTH}}**; E2E tool: **{{E2E_TOOL}}**. Match the failure to the right layer (unit vs widget vs integration).
---
## Phase 2 — Root cause (no code yet)
> **Invoke skill: `superpowers:systematic-debugging`**
Produce **one paragraph**: hypothesis tied to **specific lines** in the pasted evidence. Mark confidence (high / medium / low). **No code changes** in this phase.
---
## Phase 3 — Fix (only after Phase 2)
> **Invoke skill: `superpowers:systematic-debugging`** again while iterating fixes.
When proposing changes:
- Respect architecture boundaries for **{{ARCHITECTURE}}**:
{{ARCH_IMPORT_RULES}}
- Always consider: `.cursor/rules/flutter-core.mdc`, `.cursor/rules/security-standards.mdc`, `.cursor/rules/project-context.mdc`, and state-management rules for **{{STATE_MANAGEMENT}}**.
After each fix attempt, re-run the **same** failing command and paste new output.
---
## ACTION REQUIRED
If evidence is missing, **stop** and print:
1. Exact commands to run (copy-paste ready).
2. What to paste back (full error blocks, not summaries).
3. If the user cannot run commands: state assumptions explicitly and set confidence to **low**.
**Template version:** {{TEMPLATE_VERSION}}
@@ -0,0 +1,80 @@
---
name: Explain code
description: Explain what code does without editing it. Use /explain with a path or symbol; covers {{STATE_MANAGEMENT}} state, {{BACKEND}} I/O, routing {{ROUTING}}, and failure modes. Ask when facts are not in the repo.
---
# Explain — {{PROJECT_NAME}}
Explain **what the code is doing** — **do not** change production code unless the user explicitly asks for a fix.
**Stack:** **{{STATE_MANAGEMENT}}** / **{{ARCHITECTURE}}** / **{{ROUTING}}** / **{{BACKEND}}** / platforms: {{PLATFORMS_LIST}}. Package: `{{PACKAGE_ID}}`.
## Usage
```
/explain <file path, widget name, class, or symbol>
```
**Examples:**
- `/explain lib/features/cart/cart_cubit.dart`
- `/explain how checkout routes after payment`
- `/explain CartPage build method`
---
## Output format (use these headings in order)
### Purpose
One short paragraph: why this code exists in the product context (**{{PROJECT_NAME}}** — {{DESCRIPTION}}).
### Public API
Surface area: public classes/methods, constructors, and what callers are expected to pass. Note codegen involvement when **{{CODEGEN_LIST}}** is not `none`.
### Call flow
Ordered steps from entry point (e.g. widget `build`, route handler, Bloc `on<Event>`, Riverpod `build`, GetX controller lifecycle) through collaborators. Tie navigation to **{{ROUTING}}** where relevant.
### State and side effects
How state is held and updated for **{{STATE_MANAGEMENT}}** ({{STATE_MGMT_RAW}}). Mention async work, listeners, and disposal. Reference **{{ARCH_IMPORT_RULES}}** if layering is unclear.
### I/O and backends
Network, local storage, or platform channels touching **{{BACKEND}}** (and **{{AUTH}}** where auth applies: {{AUTH_RAW}}). Do **not** invent API shapes not visible in the repo.
### Failure modes
What can go wrong: null paths, error states, race conditions, missing permissions on {{PLATFORMS_LIST}}, auth edge cases.
### Suggested tests
Ideas aligned with **{{TESTING_DEPTH}}** and **{{E2E_TOOL}}**; for **{{STATE_MANAGEMENT}}**, prefer patterns like:
```
{{TEST_PATTERN}}
```
### Unknowns — questions for you
If behavior depends on runtime config, native projects, remote API contracts, or secrets not in tree: **stop** and list **specific** questions. Do not fabricate facts.
---
## References
- **Project brief:** `project-brief.yaml` — feature modules: {{FEATURES_LIST}}; special features: {{SPECIAL_FEATURES}}.
- **Scale:** {{SCALE}}; i18n locales: {{LOCALES_LIST}} (when explaining localization).
- **Design:** {{DESIGN_SOURCE}}; Figma URL: {{FIGMA_URL}}.
- **API docs format:** {{API_DOCS_FORMAT}} (path: {{API_DOCS_PATH}}).
- **Related repos (if any):**
{{GIT_REFS_BLOCK}}
- **Local paths (if any):**
{{LOCAL_PATHS_BLOCK}}
**Template version:** {{TEMPLATE_VERSION}}
@@ -0,0 +1,73 @@
---
name: Verify change
description: Post-change or pre-PR verification without the full /build lifecycle. Use /verify with optional scope; respects testing depth {{TESTING_DEPTH}} and E2E {{E2E_TOOL}}; no success claims without pasted outputs.
---
# Verify — {{PROJECT_NAME}}
Run a **focused** verification gate after a change or before a small PR — without replaying the entire `/build` document.
**Stack:** **{{STATE_MANAGEMENT}}** / **{{ARCHITECTURE}}** / **{{BACKEND}}** / {{PLATFORMS_LIST}}. **Testing depth:** {{TESTING_DEPTH}}. **E2E tool:** {{E2E_TOOL}}. **Codegen:** {{CODEGEN_LIST}}.
## Usage
```
/verify [optional scope: paths, “small PR”, or feature name]
```
**Examples:**
- `/verify lib/features/auth/`
- `/verify small PR before push`
- `/verify after dependency bump`
---
## Checklist (adapt to testing depth)
> **Invoke skill: `superpowers:verification-before-completion`**
**Do not claim success** until the user (or you, in a trusted environment) has pasted **real** output for each applicable item below.
### Always (typical Flutter repo)
- [ ] **Unit / widget tests** for touched code — e.g. `flutter test <path> --no-pub` or full suite as appropriate.
**Required in paste:** a line showing tests passed (or the exact failure to fix).
- [ ] **`flutter analyze`**
**Required in paste:** `No issues found!` or the analyzer errors to address.
### When `testing.depth` is `full` or `e2e` (this brief: **{{TESTING_DEPTH}}**)
- [ ] **Integration / E2E** — use **{{E2E_TOOL}}** patterns from `.cursor/rules/` (e.g. Patrol). Run on a device or emulator when scenarios require it; paste run output.
### When `testing.depth` is `unit_widget` only
- [ ] **Integration / device E2E** — *not* mandatory unless the change touches integration-only surfaces; if skipped, say so explicitly in the paste.
### Hooks and codegen
- [ ] **`lefthook run pre-commit`** — run when the repo has Lefthook configured (especially when **{{CODEGEN_LIST}}** is not `none`). Paste hook summary.
If hooks are not set up for this workspace, write *“skipped — hooks not configured”* instead of failing silently.
### CI alignment
- [ ] For **{{CICD_TOOL}}** ({{CICD_RAW}}): confirm the same commands the pipeline runs (analyze + tests) are green locally. Note flavor-scoped secrets for **{{FLAVORS_LIST}}**.
---
## ACTION REQUIRED — paste block
Print this table and wait for pasted output before declaring done:
```
VERIFICATION — paste real output for each line you executed:
[ ] flutter test … → (paste: pass count or failures)
[ ] flutter analyze → (paste: no issues or errors)
[ ] integration / e2e (if depth is full/e2e or change requires it) →
[ ] lefthook run pre-commit → (paste or "skipped — not configured")
```
If anything fails: switch to **`/debug`** with the failing log before guessing.
**Template version:** {{TEMPLATE_VERSION}}
@@ -0,0 +1,2 @@
*.jsonl
*.log
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Append a JSONL usage line (local only). Requires jq when passing structured payload.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
LOG="${ROOT}/telemetry/usage.jsonl"
mkdir -p "$(dirname "$LOG")"
echo "{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"event\":\"${1:-note}\",\"detail\":\"${2:-}\"}" >>"$LOG"
@@ -3,109 +3,41 @@
import 'dart:io';
import 'package:test/test.dart';
import 'golden_briefs.dart';
import '../src/resolver.dart';
import '../src/renderer.dart';
import '../src/validator.dart';
import '../src/models.dart';
// ─── Test fixtures ─────────────────────────────────────────────────────────
final _blocCleanBrief = ProjectBrief(
projectName: 'TestApp',
packageId: 'com.test.testapp',
description: 'Test app for golden tests',
scale: 'medium',
stateManagement: 'bloc',
routing: 'gorouter',
architecture: 'clean',
backends: ['firebase'],
auth: 'firebase_auth',
platforms: ['ios', 'android'],
codegenTools: ['freezed'],
flavors: ['dev', 'prod'],
cicd: 'github_actions',
testingDepth: 'unit_widget',
e2eTool: 'patrol',
designSource: 'none',
figmaUrl: '',
apiDocsFormat: 'none',
apiDocsPath: '',
referenceRepos: [],
localPaths: [],
featureModules: ['auth', 'home', 'products'],
specialFeatures: [],
i18nEnabled: false,
locales: ['en'],
);
final _riverpodFFBrief = ProjectBrief(
projectName: 'TaskFlow',
packageId: 'com.test.taskflow',
description: 'Task management app',
scale: 'small',
stateManagement: 'riverpod',
routing: 'gorouter',
architecture: 'feature_first',
backends: ['supabase'],
auth: 'supabase_auth',
platforms: ['ios', 'android', 'web'],
codegenTools: ['freezed', 'json_serializable'],
flavors: ['dev', 'prod'],
cicd: 'github_actions',
testingDepth: 'unit_widget',
e2eTool: 'patrol',
designSource: 'none',
figmaUrl: '',
apiDocsFormat: 'none',
apiDocsPath: '',
referenceRepos: [],
localPaths: [],
featureModules: ['auth', 'tasks', 'profile'],
specialFeatures: [],
i18nEnabled: true,
locales: ['en', 'fr'],
);
final _getxMvcBrief = ProjectBrief(
projectName: 'LegacyApp',
packageId: 'com.test.legacy',
description: 'Legacy GetX app',
scale: 'medium',
stateManagement: 'getx',
routing: 'getx_nav',
architecture: 'mvc',
backends: ['rest'],
auth: 'jwt_rest',
platforms: ['ios', 'android'],
codegenTools: [],
flavors: ['dev', 'prod'],
cicd: 'codemagic',
testingDepth: 'unit_widget',
e2eTool: 'patrol',
designSource: 'none',
figmaUrl: '',
apiDocsFormat: 'openapi',
apiDocsPath: 'docs/api.yaml',
referenceRepos: [],
localPaths: [],
featureModules: ['auth', 'dashboard'],
specialFeatures: [],
i18nEnabled: false,
locales: ['en'],
);
import '../src/mcp_json.dart';
void main() {
// ─── Resolver tests ─────────────────────────────────────────────────────────
group('Resolver', () {
test('BLoC + Clean resolves correct files', () {
final files = Resolver.resolve(_blocCleanBrief);
final files = Resolver.resolve(kBlocCleanFirebaseBrief);
// Universal — always present
expect(files.first, equals('rules/universal/rule-authoring'));
expect(files, contains('rules/universal/flutter-core'));
expect(files, contains('rules/universal/ui-ux-standards'));
expect(files, contains('rules/universal/project-context'));
// CI/CD rule when cicd set or multiple flavors
expect(files, contains('rules/cicd/cicd'));
// Feature stubs from brief
expect(files, contains('rules/features/auth'));
expect(files, contains('rules/features/home'));
expect(files, contains('rules/features/products'));
// Cursor workspace extras
expect(files, contains('root/.cursorignore'));
expect(files, contains('root/tool/cursor_audit.sh'));
expect(files, contains('onboarding/ONBOARDING'));
expect(files, contains('commands/build'));
expect(files, contains('commands/debug-issue'));
// Security — always present (Pillar 5)
expect(files, contains('rules/security/security-standards'));
@@ -142,12 +74,15 @@ void main() {
expect(files, containsNot('rules/architecture/feature_first'));
expect(files, containsNot('rules/routing/getx_nav'));
expect(files, contains('commands/verify-change'));
expect(files, contains('commands/explain-code'));
expect(files, containsNot('config/mcp-json'));
expect(files, contains('root/AGENTS.md'));
expect(files, contains('root/lefthook.yaml'));
});
test('Riverpod + Feature-First + Web resolves web platform template', () {
final files = Resolver.resolve(_riverpodFFBrief);
final files = Resolver.resolve(kRiverpodFfSupabaseBrief);
expect(files, contains('rules/platform/platform-web'));
expect(files, contains('rules/state-management/riverpod'));
expect(files, contains('rules/architecture/feature_first'));
@@ -157,8 +92,177 @@ void main() {
expect(files, containsNot('agents/migration-agent'));
});
test('featureRuleKey sanitizes module names', () {
expect(Resolver.featureRuleKey('My Cart'), 'rules/features/my_cart');
expect(Resolver.featureRuleKey('auth'), 'rules/features/auth');
expect(Resolver.featureRuleKey(' '), isNull);
});
test('MCP template key when integrations.mcp.enabled', () {
final brief = ProjectBrief(
projectName: 'McpApp',
packageId: 'com.test.mcp',
description: '',
scale: 'small',
stateManagement: 'bloc',
routing: 'gorouter',
architecture: 'clean',
backends: ['firebase'],
auth: 'none',
platforms: ['ios'],
codegenTools: [],
flavors: ['dev'],
cicd: 'none',
testingDepth: 'unit_widget',
e2eTool: 'patrol',
designSource: 'none',
figmaUrl: '',
apiDocsFormat: 'none',
apiDocsPath: '',
referenceRepos: [],
localPaths: [],
featureModules: [],
specialFeatures: [],
i18nEnabled: false,
locales: ['en'],
mcpConfigEnabled: true,
);
expect(Resolver.resolve(brief), contains('config/mcp-json'));
});
test('Push/deeplink rule when special features request it', () {
final brief = ProjectBrief(
projectName: 'PushApp',
packageId: 'com.test.push',
description: '',
scale: 'small',
stateManagement: 'bloc',
routing: 'gorouter',
architecture: 'clean',
backends: ['rest'],
auth: 'none',
platforms: ['ios'],
codegenTools: [],
flavors: ['dev'],
cicd: 'none',
testingDepth: 'unit_widget',
e2eTool: 'patrol',
designSource: 'none',
figmaUrl: '',
apiDocsFormat: 'none',
apiDocsPath: '',
referenceRepos: [],
localPaths: [],
featureModules: [],
specialFeatures: ['push_notifications'],
i18nEnabled: false,
locales: ['en'],
);
expect(Resolver.resolve(brief), contains('rules/integrations/push-deeplink'));
});
test('Theming rule when high contrast requested', () {
final brief = ProjectBrief(
projectName: 'A11yApp',
packageId: 'com.test.a11y',
description: '',
scale: 'small',
stateManagement: 'bloc',
routing: 'gorouter',
architecture: 'clean',
backends: ['rest'],
auth: 'none',
platforms: ['ios'],
codegenTools: [],
flavors: ['dev'],
cicd: 'none',
testingDepth: 'unit_widget',
e2eTool: 'patrol',
designSource: 'none',
figmaUrl: '',
apiDocsFormat: 'none',
apiDocsPath: '',
referenceRepos: [],
localPaths: [],
featureModules: [],
specialFeatures: [],
i18nEnabled: false,
locales: ['en'],
themeVariants: const ['light', 'dark', 'high_contrast'],
);
expect(Resolver.resolve(brief), contains('rules/theming/theming'));
});
test('Telemetry helpers when telemetry_opt_in', () {
final brief = ProjectBrief(
projectName: 'TelApp',
packageId: 'com.test.tel',
description: '',
scale: 'small',
stateManagement: 'bloc',
routing: 'gorouter',
architecture: 'clean',
backends: ['rest'],
auth: 'none',
platforms: ['ios'],
codegenTools: [],
flavors: ['dev'],
cicd: 'none',
testingDepth: 'unit_widget',
e2eTool: 'patrol',
designSource: 'none',
figmaUrl: '',
apiDocsFormat: 'none',
apiDocsPath: '',
referenceRepos: [],
localPaths: [],
featureModules: [],
specialFeatures: [],
i18nEnabled: false,
locales: ['en'],
telemetryOptIn: true,
);
final files = Resolver.resolve(brief);
expect(files, contains('telemetry/gitignore'));
expect(files, contains('telemetry/log-sh'));
expect(files, contains('rules/telemetry/usage-logging'));
});
test('McpJsonBuilder minimal preset emits empty mcpServers', () {
const brief = ProjectBrief(
projectName: 'M',
packageId: 'com.m.m',
description: '',
scale: 'small',
stateManagement: 'bloc',
routing: 'gorouter',
architecture: 'clean',
backends: ['rest'],
auth: 'none',
platforms: ['ios'],
codegenTools: [],
flavors: ['dev'],
cicd: 'none',
testingDepth: 'unit_widget',
e2eTool: 'patrol',
designSource: 'none',
figmaUrl: '',
apiDocsFormat: 'none',
apiDocsPath: '',
referenceRepos: [],
localPaths: [],
featureModules: [],
specialFeatures: [],
i18nEnabled: false,
locales: ['en'],
mcpConfigEnabled: true,
mcpPreset: 'minimal',
);
expect(McpJsonBuilder.build(brief), contains('"mcpServers": {}'));
});
test('GetX + MVC includes migration-agent', () {
final files = Resolver.resolve(_getxMvcBrief);
final files = Resolver.resolve(kGetxMvcRestBrief);
expect(files, contains('agents/migration-agent'));
expect(files, contains('rules/state-management/getx'));
expect(files, contains('rules/architecture/mvc'));
@@ -171,7 +275,7 @@ void main() {
});
test('Codegen stack includes Cursor hooks templates', () {
final files = Resolver.resolve(_blocCleanBrief);
final files = Resolver.resolve(kBlocCleanFirebaseBrief);
expect(files, contains('hooks/hooks-json'));
expect(files, contains('hooks/arch-guard'));
});
@@ -241,17 +345,26 @@ void main() {
});
test('No duplicate files in resolved list', () {
final files = Resolver.resolve(_blocCleanBrief);
final files = Resolver.resolve(kBlocCleanFirebaseBrief);
final unique = files.toSet();
expect(files.length, equals(unique.length),
reason: 'Duplicate template files detected');
});
test('build skill always included in resolved list', () {
expect(Resolver.resolve(_blocCleanBrief), contains('skills/build'));
expect(Resolver.resolve(_riverpodFFBrief), contains('skills/build'));
expect(Resolver.resolve(_getxMvcBrief), contains('skills/build'));
test('Universal slash skills always in resolved list', () {
const universalSkills = [
'skills/build',
'skills/debug-issue',
'skills/verify-change',
'skills/explain-code',
];
for (final skill in universalSkills) {
expect(Resolver.resolve(kBlocCleanFirebaseBrief), contains(skill));
expect(Resolver.resolve(kRiverpodFfSupabaseBrief), contains(skill));
expect(Resolver.resolve(kGetxMvcRestBrief), contains(skill));
}
});
});
// ─── Renderer / placeholder tests ───────────────────────────────────────────
@@ -283,8 +396,8 @@ void main() {
}
final rendered = await Renderer.render(
brief: _blocCleanBrief,
templateFiles: Resolver.resolve(_blocCleanBrief),
brief: kBlocCleanFirebaseBrief,
templateFiles: Resolver.resolve(kBlocCleanFirebaseBrief),
templateSrc: templateDir,
);
@@ -309,7 +422,7 @@ void main() {
}
final rendered = await Renderer.render(
brief: _blocCleanBrief,
brief: kBlocCleanFirebaseBrief,
templateFiles: ['hooks/arch-guard'],
templateSrc: templateDir,
);
@@ -321,13 +434,58 @@ void main() {
'Default template dir should resolve real arch-guard.ts.tmpl');
expect(content, contains('arch-guard'));
});
test('mcp.json renders from config/mcp-json key', () async {
final templateDir = _templateDir();
if (!Directory(templateDir).existsSync()) {
markTestSkipped('Template directory not found');
return;
}
final brief = ProjectBrief(
projectName: 'McpApp',
packageId: 'com.test.mcp',
description: '',
scale: 'small',
stateManagement: 'bloc',
routing: 'gorouter',
architecture: 'clean',
backends: const ['firebase'],
auth: 'none',
platforms: const ['ios'],
codegenTools: const [],
flavors: const ['dev'],
cicd: 'none',
testingDepth: 'unit_widget',
e2eTool: 'patrol',
designSource: 'none',
figmaUrl: '',
apiDocsFormat: 'none',
apiDocsPath: '',
referenceRepos: const [],
localPaths: const [],
featureModules: const [],
specialFeatures: const [],
i18nEnabled: false,
locales: const ['en'],
mcpConfigEnabled: true,
);
final rendered = await Renderer.render(
brief: brief,
templateFiles: const ['config/mcp-json'],
templateSrc: templateDir,
);
final json = rendered['mcp.json']!;
expect(json, contains('mcpServers'));
expect(json, contains('filesystem'));
expect(json, contains('firebase'));
});
});
// ─── Validator tests ─────────────────────────────────────────────────────────
group('Validator', () {
test('Valid brief passes validation', () async {
final result = await Validator.validate(_blocCleanBrief);
final result = await Validator.validate(kBlocCleanFirebaseBrief);
expect(result.isValid, isTrue);
expect(result.errors, isEmpty);
});
@@ -410,8 +568,8 @@ void main() {
}
final rendered = await Renderer.render(
brief: _blocCleanBrief,
templateFiles: Resolver.resolve(_blocCleanBrief),
brief: kBlocCleanFirebaseBrief,
templateFiles: Resolver.resolve(kBlocCleanFirebaseBrief),
templateSrc: templateDir,
);
@@ -439,8 +597,8 @@ void main() {
return;
}
final rendered = await Renderer.render(
brief: _riverpodFFBrief,
templateFiles: Resolver.resolve(_riverpodFFBrief),
brief: kRiverpodFfSupabaseBrief,
templateFiles: Resolver.resolve(kRiverpodFfSupabaseBrief),
templateSrc: templateDir,
);
await _compareGoldens('test/golden/riverpod-ff-supabase', rendered);
@@ -453,8 +611,8 @@ void main() {
return;
}
final rendered = await Renderer.render(
brief: _getxMvcBrief,
templateFiles: Resolver.resolve(_getxMvcBrief),
brief: kGetxMvcRestBrief,
templateFiles: Resolver.resolve(kGetxMvcRestBrief),
templateSrc: templateDir,
);
await _compareGoldens('test/golden/getx-mvc-rest', rendered);
@@ -0,0 +1,20 @@
# Cursor — TestApp
## Quick start
1. Open this repo in **Cursor** so `.cursor/rules/` and `.cursor/skills/` load automatically.
2. Read **`rules/universal/rule-authoring.mdc`** — how we maintain AI rules.
3. Stack and product context live in **`project-brief.yaml`** at the repo root; regenerate `.cursor/` with `cursor_gen` after changing it.
4. **Slash skills** (primary workflows): open the Command Palette and use the project commands, or reference:
- `.cursor/skills/build/SKILL.md` — end-to-end feature implementation
- `.cursor/skills/debug-issue/SKILL.md` — structured debugging
- `.cursor/skills/verify-change/SKILL.md` — pre-PR verification
- `.cursor/skills/explain-code/SKILL.md` — explain-only walkthroughs
5. **Agents** (`.cursor/agents/*.mdc`) are reusable reviewer personas — attach when asking for code review or focused passes.
6. **Custom overrides**: files under `.cursor/custom/` and `CURSOR:CUSTOM` blocks in generated files are preserved on `cursor_gen --refresh` (see generator docs).
## Optional
- **`integrations.mcp.enabled`** in `project-brief.yaml` — generates `.cursor/mcp.json` with env-based server entries (no secrets in git).
- **`telemetry_opt_in: true`** — emits local telemetry helpers under `.cursor/telemetry/` (never commit usage logs if you enable logging).
- Run **`bash tool/cursor_audit.sh`** from the project root periodically to catch stale feature rules and overly broad `alwaysApply` usage.
@@ -0,0 +1,27 @@
# Build artefacts
build/
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
*.g.dart
*.freezed.dart
*.gr.dart
*.config.dart
# Secrets
.env
.env.*
firebase_options.dart
google-services.json
GoogleService-Info.plist
# Large binary assets
assets/fonts/
assets/videos/
*.aab
*.apk
*.ipa
# IDE
.idea/
*.iml
@@ -3,3 +3,5 @@
Repo-level notes for AI assistants. Authoritative stack and conventions are in `project-brief.yaml` and `.cursor/` (regenerate with `cursor_gen` from the project root).
- **Package:** `com.test.testapp`
- **Onboarding:** `.cursor/ONBOARDING.md` — layout, slash commands → skills, MCP opt-in, audits
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain` (see `.cursor/commands/*.md`)
@@ -1,4 +1,5 @@
# TestApp — generated by cursor_gen; adjust commands to your repo
# Optional: run `bash tool/cursor_audit.sh` after changing features.modules or rule files.
pre-commit:
commands:
flutter-analyze:
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# TestApp — Cursor rule hygiene (generated by cursor_gen)
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CURSOR="${ROOT}/.cursor"
RULES="${CURSOR}/rules"
echo "== cursor_audit (${ROOT}) =="
if [[ ! -d "$CURSOR" ]]; then
echo "ERROR: missing ${CURSOR}"
exit 1
fi
if [[ -d "$RULES" ]]; then
ac="$(grep -R "alwaysApply: true" "$RULES" --include='*.mdc' 2>/dev/null | wc -l | tr -d ' ')"
echo "alwaysApply: true occurrences in .cursor/rules: ${ac}"
echo " (expect a small number — meta/safety; prefer scoped globs for domain rules)"
else
echo "WARN: no ${RULES}"
fi
if [[ -d "$RULES/features" ]]; then
shopt -s nullglob
for f in "$RULES/features"/*.mdc; do
base="$(basename "$f" .mdc)"
if [[ ! -d "${ROOT}/lib/features/${base}" ]] && [[ ! -d "${ROOT}/lib/feature_${base}" ]]; then
echo "WARN: rules/features/${base}.mdc has no obvious lib/features/${base} folder — update features.modules or lib layout"
fi
done
shopt -u nullglob
fi
echo "OK — review warnings above after brief or folder renames"
@@ -0,0 +1 @@
End-to-end feature implementation (research, TDD, integration tests, verification). Follow the workflow and constraints in `@file:.cursor/skills/build/SKILL.md`. Use `project-brief.yaml` as the source of truth for stack and platforms.
@@ -0,0 +1 @@
Structured bug triage and evidence-first debugging. Follow `@file:.cursor/skills/debug-issue/SKILL.md`. Gather reproduction steps, logs, and failing commands before proposing fixes.
@@ -0,0 +1 @@
Explain-only walkthrough of code paths and stack behavior (no edits). Follow `@file:.cursor/skills/explain-code/SKILL.md`. Do not modify source files unless the user explicitly asks.
@@ -0,0 +1 @@
Pre-PR verification checklist (analyze, tests, hooks) without full /build lifecycle. Follow `@file:.cursor/skills/verify-change/SKILL.md` for the change in scope.
@@ -0,0 +1,29 @@
---
description: CI/CD, flavours, and quality gates for TestApp
globs: [".github/**", "codemagic.yaml", "Makefile", "pubspec.yaml", "fastlane/**"]
alwaysApply: false
---
# CI/CD & flavours — TestApp
## Context
Pipeline and flavour setup must stay aligned with how the app is built and released.
## Flavours
- Documented in `project-brief.yaml`: **dev, prod**
- Use `--flavor` / `-t lib/main_<flavour>.dart` (or your projects entrypoints) consistently across local, CI, and store builds
- Configuration via `--dart-define` / `--dart-define-from-file` — **never** hardcode secrets in source
## Quality gates (recommended stages)
- **Lint:** `dart format --set-exit-if-changed .` and `flutter analyze`
- **Unit + widget:** `flutter test` (with coverage if the team tracks it)
- **Goldens:** fixed device/locale; CI fails on drift unless intentionally updated
- **Smoke build:** e.g. `flutter build apk` or `flutter build ios --no-codesign` for the primary flavour
- **E2E:** when `testing.depth` includes e2e — patrol on CI devices or Firebase Test Lab
## Cursor integration
- After substantive edits: run analyze and relevant tests before PR
- For release-oriented tasks, use the **deploy** skill at `.cursor/skills/deploy/SKILL.md` when present
## CI/CD tool
- Selected in brief: **GitHub Actions** (`github_actions`)
@@ -0,0 +1,21 @@
---
description: "Feature module auth — contracts, boundaries, and ownership (fill after design)"
globs: ["lib/**/auth/**", "test/**/auth/**"]
alwaysApply: false
---
# Feature — Auth
## Context
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `auth` so agents do not invent cross-feature wiring.
## Constraints
- List external dependencies (other features, packages, backend endpoints) explicitly
- Document invariants (auth required, idempotency, offline behavior) when known
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
## Patterns
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
## Anti-patterns
- Empty file left forever — either fill it or delete the module entry from the brief
@@ -0,0 +1,21 @@
---
description: "Feature module home — contracts, boundaries, and ownership (fill after design)"
globs: ["lib/**/home/**", "test/**/home/**"]
alwaysApply: false
---
# Feature — Home
## Context
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `home` so agents do not invent cross-feature wiring.
## Constraints
- List external dependencies (other features, packages, backend endpoints) explicitly
- Document invariants (auth required, idempotency, offline behavior) when known
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
## Patterns
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
## Anti-patterns
- Empty file left forever — either fill it or delete the module entry from the brief
@@ -0,0 +1,21 @@
---
description: "Feature module products — contracts, boundaries, and ownership (fill after design)"
globs: ["lib/**/products/**", "test/**/products/**"]
alwaysApply: false
---
# Feature — Products
## Context
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `products` so agents do not invent cross-feature wiring.
## Constraints
- List external dependencies (other features, packages, backend endpoints) explicitly
- Document invariants (auth required, idempotency, offline behavior) when known
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
## Patterns
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
## Anti-patterns
- Empty file left forever — either fill it or delete the module entry from the brief
@@ -1,6 +1,7 @@
---
description: "Core Flutter conventions for TestApp — always applied"
alwaysApply: true
description: "Core Flutter conventions for TestApp"
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
alwaysApply: false
---
# Flutter Core Standards — TestApp
@@ -29,9 +30,9 @@ alwaysApply: true
- Private members: `_camelCase`
## Imports
- Order: dart: → package: → relative
- Use relative imports within a feature; absolute for cross-feature
- Never import a feature's internal files from outside that feature
### Imports (strict — `conventions.strict_package_imports: true`)
- Use `package:<your_pubspec_name>/...` imports everywhere in `lib/` and `test/` — **no** relative `../` across feature boundaries (the brief `project.package` id is often the app bundle id; prefer the **pubspec.yaml `name`** for Dart imports)
- Barrel files (`index.dart`) at feature roots; do not wildcard re-export third-party packages
## Code quality
- Max function length: 40 lines. Extract widgets and helpers aggressively
@@ -1,6 +1,7 @@
---
description: "Project context for TestApp — always applied"
alwaysApply: true
description: "Stack summary and product context for TestApp"
globs: ["project-brief.yaml", ".cursor/**/*.md", ".cursor/**/*.mdc", "pubspec.yaml"]
alwaysApply: false
---
# Project Context — TestApp
@@ -0,0 +1,24 @@
---
description: How Cursor rules in this repository must be written and maintained.
globs: [".cursor/rules/**/*.mdc"]
alwaysApply: true
---
# Rule authoring — TestApp
## Context
Rules are version-controlled contracts for AI assistants. Poor rules waste context and silently steer every edit.
## Constraints
- One focused concern per file; split broad topics instead of one mega-rule
- Every rule MUST have a clear `description` in frontmatter (one sentence)
- Prefer `alwaysApply: false` with **narrow** `globs` for domain rules — reserve `alwaysApply: true` for meta and safety
- `globs` must be as specific as possible — never `["**/*"]` unless tooling requires it
- Code samples in rules MUST be valid for this project (Dart/Flutter/YAML as appropriate)
- Deprecated guidance is removed, not left commented out
- Each substantive rule includes **Context** (why), **Constraints** (must/must not), and where helpful **Patterns** / **Anti-patterns**
## Anti-patterns
- Domain rules (testing, l10n, a feature) with `alwaysApply: true` — burns context
- Rules with no concrete examples when the topic is code-facing
- Stale feature rules after modules are removed — run `tool/cursor_audit.sh` periodically
@@ -1,6 +1,7 @@
---
description: "UI/UX standards for TestApp — always applied"
alwaysApply: true
description: "UI/UX standards for TestApp"
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
alwaysApply: false
---
# UI / UX Standards — TestApp
@@ -346,6 +346,7 @@ Follow Red → Green → Refactor strictly. Show actual terminal output at each
flutter test test/features/[feature]/ --no-pub
```
**Paste the actual output here before proceeding.**
If failures are unclear or non-deterministic after one iteration, use **`/debug`** with full pasted output before guessing fixes.
### Step 3b — Green: Implement
@@ -374,6 +375,8 @@ Follow Red → Green → Refactor strictly. Show actual terminal output at each
**Paste the actual output here before proceeding.**
3. Run tests once more to confirm still green.
If output stays red or errors are ambiguous after two focused attempts, stop and use **`/debug`** with the full failing command and log before changing more code.
---
## Phase 4: Integration Test Generation
@@ -506,6 +509,8 @@ VERIFICATION REQUIRED — paste real output for each:
```
If any check fails: invoke `superpowers:systematic-debugging` to diagnose before retrying.
For noisy errors or weak reproduction, run **`/debug`** and fill the BugReport skeleton with logs before retrying.
For small, isolated changes, **`/verify`** is enough to re-check tests and analyze without re-reading this whole skill.
Do not proceed to Phase 7 until all four checks are green.
---
@@ -0,0 +1,89 @@
---
name: Debug issue
description: Triage failing tests, analyze, CI, or runtime errors with an evidence-first BugReport. Use /debug and paste logs; invokes systematic-debugging before fixes. Stack BLoC / Cubit / Clean Architecture / Firebase / ios, android.
---
# Debug — TestApp
Triage failures (tests, CI, runtime, or build) **without** jumping to fixes. Stay in hypothesis-and-evidence mode until root cause is stated.
**Stack context:** **BLoC / Cubit** / **Clean Architecture** / **Firebase** / platforms: ios, android. Flavors: dev, prod. Codegen: freezed.
## Usage
```
/debug <what failed — paste error output, command, or symptom>
```
**Examples:**
- `/debug flutter test fails on auth_cubit_test — paste output`
- `/debug CI analyze step — paste log excerpt`
- `/debug app crashes on cold start after last change`
---
## Phase 0 — Normalize the report (BugReport)
Emit this skeleton **before** deep analysis. If the user already pasted logs, map them into the fields instead of re-asking.
| Field | Content |
|-------|---------|
| **Summary** | One line: what broke |
| **Expected** | What should happen |
| **Actual** | What happened (symptom + error text) |
| **Repro steps** | Numbered, minimal |
| **Scope / files touched** | Paths or PR slice |
| **Environment** | OS, Flutter/Dart version if known, device vs simulator, flavor |
| **Evidence** | Pasted command output, stack trace, or screenshot notes |
---
## Phase 1 — Evidence checklist (Flutter-aware)
Gather or request **concrete** evidence. Do not guess versions or config.
1. **`flutter doctor -v`** — paste output when environment is unknown or iOS/Android toolchain errors appear.
2. **Failing command** — full invocation + **verbatim** tail of output (e.g. `flutter test …`, `dart test …`, `flutter analyze`).
3. **`flutter analyze`** — if not already in the failure log, run or ask the user to run and paste.
4. **Flavors** — this project uses: **dev, prod**. Confirm which flavor was active if the failure is env-specific.
5. **Platforms****ios, android**. Narrow reproduction to the platform that failed when relevant.
6. **Codegen** — tools: **freezed**. When this is not `none`, remind to run `dart run build_runner build --delete-conflicting-outputs` after generated files changed, and to align with `.cursor/hooks/` / `lefthook run pre-commit` when hooks are present.
7. **Testing depth****unit_widget**; E2E tool: **patrol**. Match the failure to the right layer (unit vs widget vs integration).
---
## Phase 2 — Root cause (no code yet)
> **Invoke skill: `superpowers:systematic-debugging`**
Produce **one paragraph**: hypothesis tied to **specific lines** in the pasted evidence. Mark confidence (high / medium / low). **No code changes** in this phase.
---
## Phase 3 — Fix (only after Phase 2)
> **Invoke skill: `superpowers:systematic-debugging`** again while iterating fixes.
When proposing changes:
- Respect architecture boundaries for **Clean Architecture**:
- presentation/ MUST NOT import from data/
- domain/ MUST NOT import from data/ or presentation/
- data/ CAN import from domain/ (implements interfaces)
- Use dependency injection to invert data → domain dependency
- Always consider: `.cursor/rules/flutter-core.mdc`, `.cursor/rules/security-standards.mdc`, `.cursor/rules/project-context.mdc`, and state-management rules for **BLoC / Cubit**.
After each fix attempt, re-run the **same** failing command and paste new output.
---
## ACTION REQUIRED
If evidence is missing, **stop** and print:
1. Exact commands to run (copy-paste ready).
2. What to paste back (full error blocks, not summaries).
3. If the user cannot run commands: state assumptions explicitly and set confidence to **low**.
**Template version:** 1.0.4
@@ -0,0 +1,83 @@
---
name: Explain code
description: Explain what code does without editing it. Use /explain with a path or symbol; covers BLoC / Cubit state, Firebase I/O, routing GoRouter, and failure modes. Ask when facts are not in the repo.
---
# Explain — TestApp
Explain **what the code is doing****do not** change production code unless the user explicitly asks for a fix.
**Stack:** **BLoC / Cubit** / **Clean Architecture** / **GoRouter** / **Firebase** / platforms: ios, android. Package: `com.test.testapp`.
## Usage
```
/explain <file path, widget name, class, or symbol>
```
**Examples:**
- `/explain lib/features/cart/cart_cubit.dart`
- `/explain how checkout routes after payment`
- `/explain CartPage build method`
---
## Output format (use these headings in order)
### Purpose
One short paragraph: why this code exists in the product context (**TestApp** — Test app for golden tests).
### Public API
Surface area: public classes/methods, constructors, and what callers are expected to pass. Note codegen involvement when **freezed** is not `none`.
### Call flow
Ordered steps from entry point (e.g. widget `build`, route handler, Bloc `on<Event>`, Riverpod `build`, GetX controller lifecycle) through collaborators. Tie navigation to **GoRouter** where relevant.
### State and side effects
How state is held and updated for **BLoC / Cubit** (bloc). Mention async work, listeners, and disposal. Reference **- presentation/ MUST NOT import from data/
- domain/ MUST NOT import from data/ or presentation/
- data/ CAN import from domain/ (implements interfaces)
- Use dependency injection to invert data → domain dependency** if layering is unclear.
### I/O and backends
Network, local storage, or platform channels touching **Firebase** (and **Firebase Auth** where auth applies: firebase_auth). Do **not** invent API shapes not visible in the repo.
### Failure modes
What can go wrong: null paths, error states, race conditions, missing permissions on ios, android, auth edge cases.
### Suggested tests
Ideas aligned with **unit_widget** and **patrol**; for **BLoC / Cubit**, prefer patterns like:
```
blocTest<MyCubit, MyState>(description, build: () => MyCubit(), act: (c) => c.method(), expect: () => [MyState()])
```
### Unknowns — questions for you
If behavior depends on runtime config, native projects, remote API contracts, or secrets not in tree: **stop** and list **specific** questions. Do not fabricate facts.
---
## References
- **Project brief:** `project-brief.yaml` — feature modules: auth, home, products; special features: .
- **Scale:** medium; i18n locales: en (when explaining localization).
- **Design:** none; Figma URL: .
- **API docs format:** none (path: ).
- **Related repos (if any):**
_No Git repository URLs listed._ Add entries under `references.repos` in project-brief.yaml when other repos are part of the product context.
- **Local paths (if any):**
_No local paths listed._ Add monorepo packages or sibling folders under `references.local_paths` in project-brief.yaml when relevant.
**Template version:** 1.0.4
@@ -0,0 +1,73 @@
---
name: Verify change
description: Post-change or pre-PR verification without the full /build lifecycle. Use /verify with optional scope; respects testing depth unit_widget and E2E patrol; no success claims without pasted outputs.
---
# Verify — TestApp
Run a **focused** verification gate after a change or before a small PR — without replaying the entire `/build` document.
**Stack:** **BLoC / Cubit** / **Clean Architecture** / **Firebase** / ios, android. **Testing depth:** unit_widget. **E2E tool:** patrol. **Codegen:** freezed.
## Usage
```
/verify [optional scope: paths, “small PR”, or feature name]
```
**Examples:**
- `/verify lib/features/auth/`
- `/verify small PR before push`
- `/verify after dependency bump`
---
## Checklist (adapt to testing depth)
> **Invoke skill: `superpowers:verification-before-completion`**
**Do not claim success** until the user (or you, in a trusted environment) has pasted **real** output for each applicable item below.
### Always (typical Flutter repo)
- [ ] **Unit / widget tests** for touched code — e.g. `flutter test <path> --no-pub` or full suite as appropriate.
**Required in paste:** a line showing tests passed (or the exact failure to fix).
- [ ] **`flutter analyze`**
**Required in paste:** `No issues found!` or the analyzer errors to address.
### When `testing.depth` is `full` or `e2e` (this brief: **unit_widget**)
- [ ] **Integration / E2E** — use **patrol** patterns from `.cursor/rules/` (e.g. Patrol). Run on a device or emulator when scenarios require it; paste run output.
### When `testing.depth` is `unit_widget` only
- [ ] **Integration / device E2E***not* mandatory unless the change touches integration-only surfaces; if skipped, say so explicitly in the paste.
### Hooks and codegen
- [ ] **`lefthook run pre-commit`** — run when the repo has Lefthook configured (especially when **freezed** is not `none`). Paste hook summary.
If hooks are not set up for this workspace, write *“skipped — hooks not configured”* instead of failing silently.
### CI alignment
- [ ] For **GitHub Actions** (github_actions): confirm the same commands the pipeline runs (analyze + tests) are green locally. Note flavor-scoped secrets for **dev, prod**.
---
## ACTION REQUIRED — paste block
Print this table and wait for pasted output before declaring done:
```
VERIFICATION — paste real output for each line you executed:
[ ] flutter test … → (paste: pass count or failures)
[ ] flutter analyze → (paste: no issues or errors)
[ ] integration / e2e (if depth is full/e2e or change requires it) →
[ ] lefthook run pre-commit → (paste or "skipped — not configured")
```
If anything fails: switch to **`/debug`** with the failing log before guessing.
**Template version:** 1.0.4
@@ -0,0 +1,20 @@
# Cursor — LegacyApp
## Quick start
1. Open this repo in **Cursor** so `.cursor/rules/` and `.cursor/skills/` load automatically.
2. Read **`rules/universal/rule-authoring.mdc`** — how we maintain AI rules.
3. Stack and product context live in **`project-brief.yaml`** at the repo root; regenerate `.cursor/` with `cursor_gen` after changing it.
4. **Slash skills** (primary workflows): open the Command Palette and use the project commands, or reference:
- `.cursor/skills/build/SKILL.md` — end-to-end feature implementation
- `.cursor/skills/debug-issue/SKILL.md` — structured debugging
- `.cursor/skills/verify-change/SKILL.md` — pre-PR verification
- `.cursor/skills/explain-code/SKILL.md` — explain-only walkthroughs
5. **Agents** (`.cursor/agents/*.mdc`) are reusable reviewer personas — attach when asking for code review or focused passes.
6. **Custom overrides**: files under `.cursor/custom/` and `CURSOR:CUSTOM` blocks in generated files are preserved on `cursor_gen --refresh` (see generator docs).
## Optional
- **`integrations.mcp.enabled`** in `project-brief.yaml` — generates `.cursor/mcp.json` with env-based server entries (no secrets in git).
- **`telemetry_opt_in: true`** — emits local telemetry helpers under `.cursor/telemetry/` (never commit usage logs if you enable logging).
- Run **`bash tool/cursor_audit.sh`** from the project root periodically to catch stale feature rules and overly broad `alwaysApply` usage.
@@ -0,0 +1,27 @@
# Build artefacts
build/
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
*.g.dart
*.freezed.dart
*.gr.dart
*.config.dart
# Secrets
.env
.env.*
firebase_options.dart
google-services.json
GoogleService-Info.plist
# Large binary assets
assets/fonts/
assets/videos/
*.aab
*.apk
*.ipa
# IDE
.idea/
*.iml
@@ -3,3 +3,5 @@
Repo-level notes for AI assistants. Authoritative stack and conventions are in `project-brief.yaml` and `.cursor/` (regenerate with `cursor_gen` from the project root).
- **Package:** `com.test.legacy`
- **Onboarding:** `.cursor/ONBOARDING.md` — layout, slash commands → skills, MCP opt-in, audits
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain` (see `.cursor/commands/*.md`)
@@ -1,4 +1,5 @@
# LegacyApp — generated by cursor_gen; adjust commands to your repo
# Optional: run `bash tool/cursor_audit.sh` after changing features.modules or rule files.
pre-commit:
commands:
flutter-analyze:
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# LegacyApp — Cursor rule hygiene (generated by cursor_gen)
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CURSOR="${ROOT}/.cursor"
RULES="${CURSOR}/rules"
echo "== cursor_audit (${ROOT}) =="
if [[ ! -d "$CURSOR" ]]; then
echo "ERROR: missing ${CURSOR}"
exit 1
fi
if [[ -d "$RULES" ]]; then
ac="$(grep -R "alwaysApply: true" "$RULES" --include='*.mdc' 2>/dev/null | wc -l | tr -d ' ')"
echo "alwaysApply: true occurrences in .cursor/rules: ${ac}"
echo " (expect a small number — meta/safety; prefer scoped globs for domain rules)"
else
echo "WARN: no ${RULES}"
fi
if [[ -d "$RULES/features" ]]; then
shopt -s nullglob
for f in "$RULES/features"/*.mdc; do
base="$(basename "$f" .mdc)"
if [[ ! -d "${ROOT}/lib/features/${base}" ]] && [[ ! -d "${ROOT}/lib/feature_${base}" ]]; then
echo "WARN: rules/features/${base}.mdc has no obvious lib/features/${base} folder — update features.modules or lib layout"
fi
done
shopt -u nullglob
fi
echo "OK — review warnings above after brief or folder renames"
@@ -0,0 +1 @@
End-to-end feature implementation (research, TDD, integration tests, verification). Follow the workflow and constraints in `@file:.cursor/skills/build/SKILL.md`. Use `project-brief.yaml` as the source of truth for stack and platforms.
@@ -0,0 +1 @@
Structured bug triage and evidence-first debugging. Follow `@file:.cursor/skills/debug-issue/SKILL.md`. Gather reproduction steps, logs, and failing commands before proposing fixes.
@@ -0,0 +1 @@
Explain-only walkthrough of code paths and stack behavior (no edits). Follow `@file:.cursor/skills/explain-code/SKILL.md`. Do not modify source files unless the user explicitly asks.
@@ -0,0 +1 @@
Pre-PR verification checklist (analyze, tests, hooks) without full /build lifecycle. Follow `@file:.cursor/skills/verify-change/SKILL.md` for the change in scope.
@@ -0,0 +1,57 @@
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"."
],
"description": "Read/write project files under the workspace root"
},
"flutter-docs": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-fetch"
],
"env": {
"BASE_URL": "https://api.flutter.dev/flutter"
},
"description": "Flutter API documentation lookup"
},
"dart-pub": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-fetch"
],
"env": {
"BASE_URL": "https://pub.dev/api"
},
"description": "Pub.dev package metadata and versions"
},
"github": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
},
"description": "GitHub issues and PR context (requires GITHUB_TOKEN)"
},
"openapi-ref": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-fetch"
],
"env": {
"OPENAPI_SPEC_URL": "${OPENAPI_SPEC_URL}"
},
"description": "Optional fetch MCP — point OPENAPI_SPEC_URL at a hosted spec or file:// URL you expose locally"
}
}
}
@@ -0,0 +1,29 @@
---
description: CI/CD, flavours, and quality gates for LegacyApp
globs: [".github/**", "codemagic.yaml", "Makefile", "pubspec.yaml", "fastlane/**"]
alwaysApply: false
---
# CI/CD & flavours — LegacyApp
## Context
Pipeline and flavour setup must stay aligned with how the app is built and released.
## Flavours
- Documented in `project-brief.yaml`: **dev, prod**
- Use `--flavor` / `-t lib/main_<flavour>.dart` (or your projects entrypoints) consistently across local, CI, and store builds
- Configuration via `--dart-define` / `--dart-define-from-file` — **never** hardcode secrets in source
## Quality gates (recommended stages)
- **Lint:** `dart format --set-exit-if-changed .` and `flutter analyze`
- **Unit + widget:** `flutter test` (with coverage if the team tracks it)
- **Goldens:** fixed device/locale; CI fails on drift unless intentionally updated
- **Smoke build:** e.g. `flutter build apk` or `flutter build ios --no-codesign` for the primary flavour
- **E2E:** when `testing.depth` includes e2e — patrol on CI devices or Firebase Test Lab
## Cursor integration
- After substantive edits: run analyze and relevant tests before PR
- For release-oriented tasks, use the **deploy** skill at `.cursor/skills/deploy/SKILL.md` when present
## CI/CD tool
- Selected in brief: **Codemagic** (`codemagic`)
@@ -0,0 +1,21 @@
---
description: "Feature module auth — contracts, boundaries, and ownership (fill after design)"
globs: ["lib/**/auth/**", "test/**/auth/**"]
alwaysApply: false
---
# Feature — Auth
## Context
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `auth` so agents do not invent cross-feature wiring.
## Constraints
- List external dependencies (other features, packages, backend endpoints) explicitly
- Document invariants (auth required, idempotency, offline behavior) when known
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
## Patterns
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
## Anti-patterns
- Empty file left forever — either fill it or delete the module entry from the brief
@@ -0,0 +1,21 @@
---
description: "Feature module dashboard — contracts, boundaries, and ownership (fill after design)"
globs: ["lib/**/dashboard/**", "test/**/dashboard/**"]
alwaysApply: false
---
# Feature — Dashboard
## Context
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `dashboard` so agents do not invent cross-feature wiring.
## Constraints
- List external dependencies (other features, packages, backend endpoints) explicitly
- Document invariants (auth required, idempotency, offline behavior) when known
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
## Patterns
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
## Anti-patterns
- Empty file left forever — either fill it or delete the module entry from the brief
@@ -1,6 +1,7 @@
---
description: "Core Flutter conventions for LegacyApp — always applied"
alwaysApply: true
description: "Core Flutter conventions for LegacyApp"
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
alwaysApply: false
---
# Flutter Core Standards — LegacyApp
@@ -29,9 +30,10 @@ alwaysApply: true
- Private members: `_camelCase`
## Imports
- Order: dart: → package: → relative
- Use relative imports within a feature; absolute for cross-feature
- Never import a feature's internal files from outside that feature
### Imports (default)
- Order: `dart:` → `package:` → relative
- Relative imports are allowed **within** the same feature directory; use `package:` imports for cross-feature code
- Never import another feature's internals from outside that feature
## Code quality
- Max function length: 40 lines. Extract widgets and helpers aggressively
@@ -1,6 +1,7 @@
---
description: "Project context for LegacyApp — always applied"
alwaysApply: true
description: "Stack summary and product context for LegacyApp"
globs: ["project-brief.yaml", ".cursor/**/*.md", ".cursor/**/*.mdc", "pubspec.yaml"]
alwaysApply: false
---
# Project Context — LegacyApp
@@ -0,0 +1,24 @@
---
description: How Cursor rules in this repository must be written and maintained.
globs: [".cursor/rules/**/*.mdc"]
alwaysApply: true
---
# Rule authoring — LegacyApp
## Context
Rules are version-controlled contracts for AI assistants. Poor rules waste context and silently steer every edit.
## Constraints
- One focused concern per file; split broad topics instead of one mega-rule
- Every rule MUST have a clear `description` in frontmatter (one sentence)
- Prefer `alwaysApply: false` with **narrow** `globs` for domain rules — reserve `alwaysApply: true` for meta and safety
- `globs` must be as specific as possible — never `["**/*"]` unless tooling requires it
- Code samples in rules MUST be valid for this project (Dart/Flutter/YAML as appropriate)
- Deprecated guidance is removed, not left commented out
- Each substantive rule includes **Context** (why), **Constraints** (must/must not), and where helpful **Patterns** / **Anti-patterns**
## Anti-patterns
- Domain rules (testing, l10n, a feature) with `alwaysApply: true` — burns context
- Rules with no concrete examples when the topic is code-facing
- Stale feature rules after modules are removed — run `tool/cursor_audit.sh` periodically
@@ -1,6 +1,7 @@
---
description: "UI/UX standards for LegacyApp — always applied"
alwaysApply: true
description: "UI/UX standards for LegacyApp"
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
alwaysApply: false
---
# UI / UX Standards — LegacyApp
@@ -346,6 +346,7 @@ Follow Red → Green → Refactor strictly. Show actual terminal output at each
flutter test test/features/[feature]/ --no-pub
```
**Paste the actual output here before proceeding.**
If failures are unclear or non-deterministic after one iteration, use **`/debug`** with full pasted output before guessing fixes.
### Step 3b — Green: Implement
@@ -373,6 +374,8 @@ Follow Red → Green → Refactor strictly. Show actual terminal output at each
**Paste the actual output here before proceeding.**
3. Run tests once more to confirm still green.
If output stays red or errors are ambiguous after two focused attempts, stop and use **`/debug`** with the full failing command and log before changing more code.
---
## Phase 4: Integration Test Generation
@@ -505,6 +508,8 @@ VERIFICATION REQUIRED — paste real output for each:
```
If any check fails: invoke `superpowers:systematic-debugging` to diagnose before retrying.
For noisy errors or weak reproduction, run **`/debug`** and fill the BugReport skeleton with logs before retrying.
For small, isolated changes, **`/verify`** is enough to re-check tests and analyze without re-reading this whole skill.
Do not proceed to Phase 7 until all four checks are green.
---
@@ -0,0 +1,88 @@
---
name: Debug issue
description: Triage failing tests, analyze, CI, or runtime errors with an evidence-first BugReport. Use /debug and paste logs; invokes systematic-debugging before fixes. Stack GetX / MVC / REST API / ios, android.
---
# Debug — LegacyApp
Triage failures (tests, CI, runtime, or build) **without** jumping to fixes. Stay in hypothesis-and-evidence mode until root cause is stated.
**Stack context:** **GetX** / **MVC** / **REST API** / platforms: ios, android. Flavors: dev, prod. Codegen: none.
## Usage
```
/debug <what failed — paste error output, command, or symptom>
```
**Examples:**
- `/debug flutter test fails on auth_cubit_test — paste output`
- `/debug CI analyze step — paste log excerpt`
- `/debug app crashes on cold start after last change`
---
## Phase 0 — Normalize the report (BugReport)
Emit this skeleton **before** deep analysis. If the user already pasted logs, map them into the fields instead of re-asking.
| Field | Content |
|-------|---------|
| **Summary** | One line: what broke |
| **Expected** | What should happen |
| **Actual** | What happened (symptom + error text) |
| **Repro steps** | Numbered, minimal |
| **Scope / files touched** | Paths or PR slice |
| **Environment** | OS, Flutter/Dart version if known, device vs simulator, flavor |
| **Evidence** | Pasted command output, stack trace, or screenshot notes |
---
## Phase 1 — Evidence checklist (Flutter-aware)
Gather or request **concrete** evidence. Do not guess versions or config.
1. **`flutter doctor -v`** — paste output when environment is unknown or iOS/Android toolchain errors appear.
2. **Failing command** — full invocation + **verbatim** tail of output (e.g. `flutter test …`, `dart test …`, `flutter analyze`).
3. **`flutter analyze`** — if not already in the failure log, run or ask the user to run and paste.
4. **Flavors** — this project uses: **dev, prod**. Confirm which flavor was active if the failure is env-specific.
5. **Platforms****ios, android**. Narrow reproduction to the platform that failed when relevant.
6. **Codegen** — tools: **none**. When this is not `none`, remind to run `dart run build_runner build --delete-conflicting-outputs` after generated files changed, and to align with `.cursor/hooks/` / `lefthook run pre-commit` when hooks are present.
7. **Testing depth****unit_widget**; E2E tool: **patrol**. Match the failure to the right layer (unit vs widget vs integration).
---
## Phase 2 — Root cause (no code yet)
> **Invoke skill: `superpowers:systematic-debugging`**
Produce **one paragraph**: hypothesis tied to **specific lines** in the pasted evidence. Mark confidence (high / medium / low). **No code changes** in this phase.
---
## Phase 3 — Fix (only after Phase 2)
> **Invoke skill: `superpowers:systematic-debugging`** again while iterating fixes.
When proposing changes:
- Respect architecture boundaries for **MVC**:
- View (Widget) MUST NOT contain business logic
- Controller MUST NOT import Flutter widgets directly
- Model MUST be plain Dart, no framework dependencies
- Always consider: `.cursor/rules/flutter-core.mdc`, `.cursor/rules/security-standards.mdc`, `.cursor/rules/project-context.mdc`, and state-management rules for **GetX**.
After each fix attempt, re-run the **same** failing command and paste new output.
---
## ACTION REQUIRED
If evidence is missing, **stop** and print:
1. Exact commands to run (copy-paste ready).
2. What to paste back (full error blocks, not summaries).
3. If the user cannot run commands: state assumptions explicitly and set confidence to **low**.
**Template version:** 1.0.4
@@ -0,0 +1,82 @@
---
name: Explain code
description: Explain what code does without editing it. Use /explain with a path or symbol; covers GetX state, REST API I/O, routing GetX Navigation, and failure modes. Ask when facts are not in the repo.
---
# Explain — LegacyApp
Explain **what the code is doing****do not** change production code unless the user explicitly asks for a fix.
**Stack:** **GetX** / **MVC** / **GetX Navigation** / **REST API** / platforms: ios, android. Package: `com.test.legacy`.
## Usage
```
/explain <file path, widget name, class, or symbol>
```
**Examples:**
- `/explain lib/features/cart/cart_cubit.dart`
- `/explain how checkout routes after payment`
- `/explain CartPage build method`
---
## Output format (use these headings in order)
### Purpose
One short paragraph: why this code exists in the product context (**LegacyApp** — Legacy GetX app).
### Public API
Surface area: public classes/methods, constructors, and what callers are expected to pass. Note codegen involvement when **none** is not `none`.
### Call flow
Ordered steps from entry point (e.g. widget `build`, route handler, Bloc `on<Event>`, Riverpod `build`, GetX controller lifecycle) through collaborators. Tie navigation to **GetX Navigation** where relevant.
### State and side effects
How state is held and updated for **GetX** (getx). Mention async work, listeners, and disposal. Reference **- View (Widget) MUST NOT contain business logic
- Controller MUST NOT import Flutter widgets directly
- Model MUST be plain Dart, no framework dependencies** if layering is unclear.
### I/O and backends
Network, local storage, or platform channels touching **REST API** (and **JWT / REST Auth** where auth applies: jwt_rest). Do **not** invent API shapes not visible in the repo.
### Failure modes
What can go wrong: null paths, error states, race conditions, missing permissions on ios, android, auth edge cases.
### Suggested tests
Ideas aligned with **unit_widget** and **patrol**; for **GetX**, prefer patterns like:
```
Get.put(MyController()); final ctrl = Get.find<MyController>(); expect(ctrl.value, expected);
```
### Unknowns — questions for you
If behavior depends on runtime config, native projects, remote API contracts, or secrets not in tree: **stop** and list **specific** questions. Do not fabricate facts.
---
## References
- **Project brief:** `project-brief.yaml` — feature modules: auth, dashboard; special features: .
- **Scale:** medium; i18n locales: en (when explaining localization).
- **Design:** none; Figma URL: .
- **API docs format:** openapi (path: docs/api.yaml).
- **Related repos (if any):**
_No Git repository URLs listed._ Add entries under `references.repos` in project-brief.yaml when other repos are part of the product context.
- **Local paths (if any):**
_No local paths listed._ Add monorepo packages or sibling folders under `references.local_paths` in project-brief.yaml when relevant.
**Template version:** 1.0.4
@@ -0,0 +1,73 @@
---
name: Verify change
description: Post-change or pre-PR verification without the full /build lifecycle. Use /verify with optional scope; respects testing depth unit_widget and E2E patrol; no success claims without pasted outputs.
---
# Verify — LegacyApp
Run a **focused** verification gate after a change or before a small PR — without replaying the entire `/build` document.
**Stack:** **GetX** / **MVC** / **REST API** / ios, android. **Testing depth:** unit_widget. **E2E tool:** patrol. **Codegen:** none.
## Usage
```
/verify [optional scope: paths, “small PR”, or feature name]
```
**Examples:**
- `/verify lib/features/auth/`
- `/verify small PR before push`
- `/verify after dependency bump`
---
## Checklist (adapt to testing depth)
> **Invoke skill: `superpowers:verification-before-completion`**
**Do not claim success** until the user (or you, in a trusted environment) has pasted **real** output for each applicable item below.
### Always (typical Flutter repo)
- [ ] **Unit / widget tests** for touched code — e.g. `flutter test <path> --no-pub` or full suite as appropriate.
**Required in paste:** a line showing tests passed (or the exact failure to fix).
- [ ] **`flutter analyze`**
**Required in paste:** `No issues found!` or the analyzer errors to address.
### When `testing.depth` is `full` or `e2e` (this brief: **unit_widget**)
- [ ] **Integration / E2E** — use **patrol** patterns from `.cursor/rules/` (e.g. Patrol). Run on a device or emulator when scenarios require it; paste run output.
### When `testing.depth` is `unit_widget` only
- [ ] **Integration / device E2E***not* mandatory unless the change touches integration-only surfaces; if skipped, say so explicitly in the paste.
### Hooks and codegen
- [ ] **`lefthook run pre-commit`** — run when the repo has Lefthook configured (especially when **none** is not `none`). Paste hook summary.
If hooks are not set up for this workspace, write *“skipped — hooks not configured”* instead of failing silently.
### CI alignment
- [ ] For **Codemagic** (codemagic): confirm the same commands the pipeline runs (analyze + tests) are green locally. Note flavor-scoped secrets for **dev, prod**.
---
## ACTION REQUIRED — paste block
Print this table and wait for pasted output before declaring done:
```
VERIFICATION — paste real output for each line you executed:
[ ] flutter test … → (paste: pass count or failures)
[ ] flutter analyze → (paste: no issues or errors)
[ ] integration / e2e (if depth is full/e2e or change requires it) →
[ ] lefthook run pre-commit → (paste or "skipped — not configured")
```
If anything fails: switch to **`/debug`** with the failing log before guessing.
**Template version:** 1.0.4
@@ -0,0 +1,20 @@
# Cursor — TaskFlow
## Quick start
1. Open this repo in **Cursor** so `.cursor/rules/` and `.cursor/skills/` load automatically.
2. Read **`rules/universal/rule-authoring.mdc`** — how we maintain AI rules.
3. Stack and product context live in **`project-brief.yaml`** at the repo root; regenerate `.cursor/` with `cursor_gen` after changing it.
4. **Slash skills** (primary workflows): open the Command Palette and use the project commands, or reference:
- `.cursor/skills/build/SKILL.md` — end-to-end feature implementation
- `.cursor/skills/debug-issue/SKILL.md` — structured debugging
- `.cursor/skills/verify-change/SKILL.md` — pre-PR verification
- `.cursor/skills/explain-code/SKILL.md` — explain-only walkthroughs
5. **Agents** (`.cursor/agents/*.mdc`) are reusable reviewer personas — attach when asking for code review or focused passes.
6. **Custom overrides**: files under `.cursor/custom/` and `CURSOR:CUSTOM` blocks in generated files are preserved on `cursor_gen --refresh` (see generator docs).
## Optional
- **`integrations.mcp.enabled`** in `project-brief.yaml` — generates `.cursor/mcp.json` with env-based server entries (no secrets in git).
- **`telemetry_opt_in: true`** — emits local telemetry helpers under `.cursor/telemetry/` (never commit usage logs if you enable logging).
- Run **`bash tool/cursor_audit.sh`** from the project root periodically to catch stale feature rules and overly broad `alwaysApply` usage.
@@ -0,0 +1,27 @@
# Build artefacts
build/
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
*.g.dart
*.freezed.dart
*.gr.dart
*.config.dart
# Secrets
.env
.env.*
firebase_options.dart
google-services.json
GoogleService-Info.plist
# Large binary assets
assets/fonts/
assets/videos/
*.aab
*.apk
*.ipa
# IDE
.idea/
*.iml
@@ -3,3 +3,5 @@
Repo-level notes for AI assistants. Authoritative stack and conventions are in `project-brief.yaml` and `.cursor/` (regenerate with `cursor_gen` from the project root).
- **Package:** `com.test.taskflow`
- **Onboarding:** `.cursor/ONBOARDING.md` — layout, slash commands → skills, MCP opt-in, audits
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain` (see `.cursor/commands/*.md`)
@@ -1,4 +1,5 @@
# TaskFlow — generated by cursor_gen; adjust commands to your repo
# Optional: run `bash tool/cursor_audit.sh` after changing features.modules or rule files.
pre-commit:
commands:
flutter-analyze:
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# TaskFlow — Cursor rule hygiene (generated by cursor_gen)
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CURSOR="${ROOT}/.cursor"
RULES="${CURSOR}/rules"
echo "== cursor_audit (${ROOT}) =="
if [[ ! -d "$CURSOR" ]]; then
echo "ERROR: missing ${CURSOR}"
exit 1
fi
if [[ -d "$RULES" ]]; then
ac="$(grep -R "alwaysApply: true" "$RULES" --include='*.mdc' 2>/dev/null | wc -l | tr -d ' ')"
echo "alwaysApply: true occurrences in .cursor/rules: ${ac}"
echo " (expect a small number — meta/safety; prefer scoped globs for domain rules)"
else
echo "WARN: no ${RULES}"
fi
if [[ -d "$RULES/features" ]]; then
shopt -s nullglob
for f in "$RULES/features"/*.mdc; do
base="$(basename "$f" .mdc)"
if [[ ! -d "${ROOT}/lib/features/${base}" ]] && [[ ! -d "${ROOT}/lib/feature_${base}" ]]; then
echo "WARN: rules/features/${base}.mdc has no obvious lib/features/${base} folder — update features.modules or lib layout"
fi
done
shopt -u nullglob
fi
echo "OK — review warnings above after brief or folder renames"
@@ -0,0 +1 @@
End-to-end feature implementation (research, TDD, integration tests, verification). Follow the workflow and constraints in `@file:.cursor/skills/build/SKILL.md`. Use `project-brief.yaml` as the source of truth for stack and platforms.
@@ -0,0 +1 @@
Structured bug triage and evidence-first debugging. Follow `@file:.cursor/skills/debug-issue/SKILL.md`. Gather reproduction steps, logs, and failing commands before proposing fixes.
@@ -0,0 +1 @@
Explain-only walkthrough of code paths and stack behavior (no edits). Follow `@file:.cursor/skills/explain-code/SKILL.md`. Do not modify source files unless the user explicitly asks.
@@ -0,0 +1 @@
Pre-PR verification checklist (analyze, tests, hooks) without full /build lifecycle. Follow `@file:.cursor/skills/verify-change/SKILL.md` for the change in scope.
@@ -0,0 +1,29 @@
---
description: CI/CD, flavours, and quality gates for TaskFlow
globs: [".github/**", "codemagic.yaml", "Makefile", "pubspec.yaml", "fastlane/**"]
alwaysApply: false
---
# CI/CD & flavours — TaskFlow
## Context
Pipeline and flavour setup must stay aligned with how the app is built and released.
## Flavours
- Documented in `project-brief.yaml`: **dev, prod**
- Use `--flavor` / `-t lib/main_<flavour>.dart` (or your projects entrypoints) consistently across local, CI, and store builds
- Configuration via `--dart-define` / `--dart-define-from-file` — **never** hardcode secrets in source
## Quality gates (recommended stages)
- **Lint:** `dart format --set-exit-if-changed .` and `flutter analyze`
- **Unit + widget:** `flutter test` (with coverage if the team tracks it)
- **Goldens:** fixed device/locale; CI fails on drift unless intentionally updated
- **Smoke build:** e.g. `flutter build apk` or `flutter build ios --no-codesign` for the primary flavour
- **E2E:** when `testing.depth` includes e2e — patrol on CI devices or Firebase Test Lab
## Cursor integration
- After substantive edits: run analyze and relevant tests before PR
- For release-oriented tasks, use the **deploy** skill at `.cursor/skills/deploy/SKILL.md` when present
## CI/CD tool
- Selected in brief: **GitHub Actions** (`github_actions`)
@@ -0,0 +1,21 @@
---
description: "Feature module auth — contracts, boundaries, and ownership (fill after design)"
globs: ["lib/**/auth/**", "test/**/auth/**"]
alwaysApply: false
---
# Feature — Auth
## Context
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `auth` so agents do not invent cross-feature wiring.
## Constraints
- List external dependencies (other features, packages, backend endpoints) explicitly
- Document invariants (auth required, idempotency, offline behavior) when known
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
## Patterns
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
## Anti-patterns
- Empty file left forever — either fill it or delete the module entry from the brief
@@ -0,0 +1,21 @@
---
description: "Feature module profile — contracts, boundaries, and ownership (fill after design)"
globs: ["lib/**/profile/**", "test/**/profile/**"]
alwaysApply: false
---
# Feature — Profile
## Context
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `profile` so agents do not invent cross-feature wiring.
## Constraints
- List external dependencies (other features, packages, backend endpoints) explicitly
- Document invariants (auth required, idempotency, offline behavior) when known
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
## Patterns
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
## Anti-patterns
- Empty file left forever — either fill it or delete the module entry from the brief
@@ -0,0 +1,21 @@
---
description: "Feature module tasks — contracts, boundaries, and ownership (fill after design)"
globs: ["lib/**/tasks/**", "test/**/tasks/**"]
alwaysApply: false
---
# Feature — Tasks
## Context
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `tasks` so agents do not invent cross-feature wiring.
## Constraints
- List external dependencies (other features, packages, backend endpoints) explicitly
- Document invariants (auth required, idempotency, offline behavior) when known
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
## Patterns
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
## Anti-patterns
- Empty file left forever — either fill it or delete the module entry from the brief
@@ -1,6 +1,7 @@
---
description: "Localization / i18n conventions for TaskFlow"
alwaysApply: true
globs: ["lib/l10n/**", "lib/**/*.dart", "test/**/*.dart"]
alwaysApply: false
---
# Localization Standards — TaskFlow
@@ -0,0 +1,23 @@
---
description: Semantic colours and theme extensions for TaskFlow
globs: ["lib/**/*.dart", "test/**/*.dart"]
alwaysApply: false
---
# Theming — TaskFlow
## Context
Theme variants from brief: **light, dark, high contrast**.
- **High contrast:** validate contrast, borders, and focus in the high-contrast theme alongside light/dark (WCAG).
## Constraints
- Prefer **`ThemeExtension`** (or design-system equivalents) for app-specific colours and radii — avoid raw `Color(0xFF...)` in feature code except in central token definitions
- Use **`Theme.of(context).colorScheme`** / `TextTheme` for Material-aligned roles where appropriate
- **High contrast:** when supported, verify WCAG contrast for text and controls; never rely on colour alone for state (pair with icon or label)
- **High contrast theme:** validate loading, empty, and error states; never rely on color alone for meaning (use icons/text/semantics).
- Touch targets: respect platform minimums (e.g. ~48 logical pixels) for interactive widgets
## Anti-patterns
- Hard-coded `Colors.*` scattered across feature widgets instead of theme tokens
- Ignoring `MediaQuery.of(context).platformBrightness` / high-contrast modes when the product claims support
@@ -1,6 +1,7 @@
---
description: "Core Flutter conventions for TaskFlow — always applied"
alwaysApply: true
description: "Core Flutter conventions for TaskFlow"
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
alwaysApply: false
---
# Flutter Core Standards — TaskFlow
@@ -29,9 +30,10 @@ alwaysApply: true
- Private members: `_camelCase`
## Imports
- Order: dart: → package: → relative
- Use relative imports within a feature; absolute for cross-feature
- Never import a feature's internal files from outside that feature
### Imports (default)
- Order: `dart:` → `package:` → relative
- Relative imports are allowed **within** the same feature directory; use `package:` imports for cross-feature code
- Never import another feature's internals from outside that feature
## Code quality
- Max function length: 40 lines. Extract widgets and helpers aggressively
@@ -1,6 +1,7 @@
---
description: "Project context for TaskFlow — always applied"
alwaysApply: true
description: "Stack summary and product context for TaskFlow"
globs: ["project-brief.yaml", ".cursor/**/*.md", ".cursor/**/*.mdc", "pubspec.yaml"]
alwaysApply: false
---
# Project Context — TaskFlow
@@ -42,10 +43,12 @@ _No Git repository URLs listed._ Add entries under `references.repos` in project
_No local paths listed._ Add monorepo packages or sibling folders under `references.local_paths` in project-brief.yaml when relevant.
## Product UX / themes & roles
- **Theme variants:** light, dark
- **Theme variants:** light, dark, high contrast
- **Roles:** Not enabled (`app_context.roles_enabled: false`).
- **High contrast:** validate contrast, borders, and focus in the high-contrast theme alongside light/dark (WCAG).
## Reviews — which rule owns what
- **Theme, colors, typography, spacing/radius tokens** → `ui-ux-standards.mdc` (widgets read `Theme.of(context)` only)
- **User-visible copy & locales** → `localization.mdc` (ARB / `AppLocalizations`; no UI string literals)
@@ -0,0 +1,24 @@
---
description: How Cursor rules in this repository must be written and maintained.
globs: [".cursor/rules/**/*.mdc"]
alwaysApply: true
---
# Rule authoring — TaskFlow
## Context
Rules are version-controlled contracts for AI assistants. Poor rules waste context and silently steer every edit.
## Constraints
- One focused concern per file; split broad topics instead of one mega-rule
- Every rule MUST have a clear `description` in frontmatter (one sentence)
- Prefer `alwaysApply: false` with **narrow** `globs` for domain rules — reserve `alwaysApply: true` for meta and safety
- `globs` must be as specific as possible — never `["**/*"]` unless tooling requires it
- Code samples in rules MUST be valid for this project (Dart/Flutter/YAML as appropriate)
- Deprecated guidance is removed, not left commented out
- Each substantive rule includes **Context** (why), **Constraints** (must/must not), and where helpful **Patterns** / **Anti-patterns**
## Anti-patterns
- Domain rules (testing, l10n, a feature) with `alwaysApply: true` — burns context
- Rules with no concrete examples when the topic is code-facing
- Stale feature rules after modules are removed — run `tool/cursor_audit.sh` periodically
@@ -1,6 +1,7 @@
---
description: "UI/UX standards for TaskFlow — always applied"
alwaysApply: true
description: "UI/UX standards for TaskFlow"
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
alwaysApply: false
---
# UI / UX Standards — TaskFlow
@@ -46,3 +47,4 @@ alwaysApply: true
- Minimum contrast ratio: 4.5:1 (WCAG AA)
- Test with TalkBack / VoiceOver before each release
- **High contrast theme:** validate loading, empty, and error states; never rely on color alone for meaning (use icons/text/semantics).
@@ -346,6 +346,7 @@ Follow Red → Green → Refactor strictly. Show actual terminal output at each
flutter test test/features/[feature]/ --no-pub
```
**Paste the actual output here before proceeding.**
If failures are unclear or non-deterministic after one iteration, use **`/debug`** with full pasted output before guessing fixes.
### Step 3b — Green: Implement
@@ -373,6 +374,8 @@ Follow Red → Green → Refactor strictly. Show actual terminal output at each
**Paste the actual output here before proceeding.**
3. Run tests once more to confirm still green.
If output stays red or errors are ambiguous after two focused attempts, stop and use **`/debug`** with the full failing command and log before changing more code.
---
## Phase 4: Integration Test Generation
@@ -505,6 +508,8 @@ VERIFICATION REQUIRED — paste real output for each:
```
If any check fails: invoke `superpowers:systematic-debugging` to diagnose before retrying.
For noisy errors or weak reproduction, run **`/debug`** and fill the BugReport skeleton with logs before retrying.
For small, isolated changes, **`/verify`** is enough to re-check tests and analyze without re-reading this whole skill.
Do not proceed to Phase 7 until all four checks are green.
---
@@ -0,0 +1,88 @@
---
name: Debug issue
description: Triage failing tests, analyze, CI, or runtime errors with an evidence-first BugReport. Use /debug and paste logs; invokes systematic-debugging before fixes. Stack Riverpod / Feature-First / Supabase / ios, android, web.
---
# Debug — TaskFlow
Triage failures (tests, CI, runtime, or build) **without** jumping to fixes. Stay in hypothesis-and-evidence mode until root cause is stated.
**Stack context:** **Riverpod** / **Feature-First** / **Supabase** / platforms: ios, android, web. Flavors: dev, prod. Codegen: freezed, json_serializable.
## Usage
```
/debug <what failed — paste error output, command, or symptom>
```
**Examples:**
- `/debug flutter test fails on auth_cubit_test — paste output`
- `/debug CI analyze step — paste log excerpt`
- `/debug app crashes on cold start after last change`
---
## Phase 0 — Normalize the report (BugReport)
Emit this skeleton **before** deep analysis. If the user already pasted logs, map them into the fields instead of re-asking.
| Field | Content |
|-------|---------|
| **Summary** | One line: what broke |
| **Expected** | What should happen |
| **Actual** | What happened (symptom + error text) |
| **Repro steps** | Numbered, minimal |
| **Scope / files touched** | Paths or PR slice |
| **Environment** | OS, Flutter/Dart version if known, device vs simulator, flavor |
| **Evidence** | Pasted command output, stack trace, or screenshot notes |
---
## Phase 1 — Evidence checklist (Flutter-aware)
Gather or request **concrete** evidence. Do not guess versions or config.
1. **`flutter doctor -v`** — paste output when environment is unknown or iOS/Android toolchain errors appear.
2. **Failing command** — full invocation + **verbatim** tail of output (e.g. `flutter test …`, `dart test …`, `flutter analyze`).
3. **`flutter analyze`** — if not already in the failure log, run or ask the user to run and paste.
4. **Flavors** — this project uses: **dev, prod**. Confirm which flavor was active if the failure is env-specific.
5. **Platforms****ios, android, web**. Narrow reproduction to the platform that failed when relevant.
6. **Codegen** — tools: **freezed, json_serializable**. When this is not `none`, remind to run `dart run build_runner build --delete-conflicting-outputs` after generated files changed, and to align with `.cursor/hooks/` / `lefthook run pre-commit` when hooks are present.
7. **Testing depth****unit_widget**; E2E tool: **patrol**. Match the failure to the right layer (unit vs widget vs integration).
---
## Phase 2 — Root cause (no code yet)
> **Invoke skill: `superpowers:systematic-debugging`**
Produce **one paragraph**: hypothesis tied to **specific lines** in the pasted evidence. Mark confidence (high / medium / low). **No code changes** in this phase.
---
## Phase 3 — Fix (only after Phase 2)
> **Invoke skill: `superpowers:systematic-debugging`** again while iterating fixes.
When proposing changes:
- Respect architecture boundaries for **Feature-First**:
- features/auth/ MUST NOT import from features/home/ etc.
- Shared code lives in core/ or shared/ only
- Each feature is self-contained: screen + provider + model + repo
- Always consider: `.cursor/rules/flutter-core.mdc`, `.cursor/rules/security-standards.mdc`, `.cursor/rules/project-context.mdc`, and state-management rules for **Riverpod**.
After each fix attempt, re-run the **same** failing command and paste new output.
---
## ACTION REQUIRED
If evidence is missing, **stop** and print:
1. Exact commands to run (copy-paste ready).
2. What to paste back (full error blocks, not summaries).
3. If the user cannot run commands: state assumptions explicitly and set confidence to **low**.
**Template version:** 1.0.4
@@ -0,0 +1,82 @@
---
name: Explain code
description: Explain what code does without editing it. Use /explain with a path or symbol; covers Riverpod state, Supabase I/O, routing GoRouter, and failure modes. Ask when facts are not in the repo.
---
# Explain — TaskFlow
Explain **what the code is doing****do not** change production code unless the user explicitly asks for a fix.
**Stack:** **Riverpod** / **Feature-First** / **GoRouter** / **Supabase** / platforms: ios, android, web. Package: `com.test.taskflow`.
## Usage
```
/explain <file path, widget name, class, or symbol>
```
**Examples:**
- `/explain lib/features/cart/cart_cubit.dart`
- `/explain how checkout routes after payment`
- `/explain CartPage build method`
---
## Output format (use these headings in order)
### Purpose
One short paragraph: why this code exists in the product context (**TaskFlow** — Task management app).
### Public API
Surface area: public classes/methods, constructors, and what callers are expected to pass. Note codegen involvement when **freezed, json_serializable** is not `none`.
### Call flow
Ordered steps from entry point (e.g. widget `build`, route handler, Bloc `on<Event>`, Riverpod `build`, GetX controller lifecycle) through collaborators. Tie navigation to **GoRouter** where relevant.
### State and side effects
How state is held and updated for **Riverpod** (riverpod). Mention async work, listeners, and disposal. Reference **- features/auth/ MUST NOT import from features/home/ etc.
- Shared code lives in core/ or shared/ only
- Each feature is self-contained: screen + provider + model + repo** if layering is unclear.
### I/O and backends
Network, local storage, or platform channels touching **Supabase** (and **Supabase Auth** where auth applies: supabase_auth). Do **not** invent API shapes not visible in the repo.
### Failure modes
What can go wrong: null paths, error states, race conditions, missing permissions on ios, android, web, auth edge cases.
### Suggested tests
Ideas aligned with **unit_widget** and **patrol**; for **Riverpod**, prefer patterns like:
```
final container = ProviderContainer(overrides: [myProvider.overrideWithValue(mockValue)]); addTearDown(container.dispose);
```
### Unknowns — questions for you
If behavior depends on runtime config, native projects, remote API contracts, or secrets not in tree: **stop** and list **specific** questions. Do not fabricate facts.
---
## References
- **Project brief:** `project-brief.yaml` — feature modules: auth, tasks, profile; special features: .
- **Scale:** small; i18n locales: en, fr (when explaining localization).
- **Design:** none; Figma URL: .
- **API docs format:** none (path: ).
- **Related repos (if any):**
_No Git repository URLs listed._ Add entries under `references.repos` in project-brief.yaml when other repos are part of the product context.
- **Local paths (if any):**
_No local paths listed._ Add monorepo packages or sibling folders under `references.local_paths` in project-brief.yaml when relevant.
**Template version:** 1.0.4

Some files were not shown because too many files have changed in this diff Show More