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.
This commit is contained in:
2026-05-14 13:33:13 +05:30
parent 2ee257c630
commit da64f769da
109 changed files with 2076 additions and 85 deletions
@@ -8,6 +8,7 @@ import '../src/resolver.dart';
import '../src/renderer.dart';
import '../src/validator.dart';
import '../src/models.dart';
import '../src/mcp_json.dart';
void main() {
// ─── Resolver tests ─────────────────────────────────────────────────────────
@@ -17,10 +18,26 @@ void main() {
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'));
@@ -57,6 +74,9 @@ 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'));
});
@@ -72,6 +92,175 @@ 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(kGetxMvcRestBrief);
expect(files, contains('agents/migration-agent'));
@@ -245,6 +434,51 @@ 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 ─────────────────────────────────────────────────────────
@@ -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,4 +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`
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain`
- **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
@@ -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,4 +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`
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain`
- **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
@@ -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,4 +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`
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain`
- **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).
@@ -0,0 +1,91 @@
// Shared ProjectBrief fixtures for golden tests and tool/refresh_goldens.dart
import '../src/models.dart';
final kBlocCleanFirebaseBrief = 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'],
strictPackageImports: true,
);
final kRiverpodFfSupabaseBrief = 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'],
themeVariants: const ['light', 'dark', 'high_contrast'],
);
final kGetxMvcRestBrief = 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'],
mcpConfigEnabled: true,
mcpPreset: 'auto',
);