From c8d31ea2b85c18f3f150ebb081788d0a9075ad97 Mon Sep 17 00:00:00 2001 From: Michal Urbanek Date: Fri, 15 May 2026 09:24:17 +0200 Subject: [PATCH 1/9] chore: Optimize Skills for Claude --- .claude/CLAUDE.md | 19 ++++---- .claude/commands/feature-data-flow.md | 8 ++++ .claude/commands/feature-screen.md | 8 ++++ .claude/commands/pr-review.md | 8 ++++ .claude/commands/project-setup.md | 8 ++++ .claude/commands/release-builds.md | 8 ++++ .claude/commands/release-prepare.md | 8 ++++ .claude/commands/secrets-bootstrap.md | 8 ++++ .claude/commands/upgrade.md | 8 ++++ .claude/skills/feature-data-flow | 1 + .claude/skills/feature-screen | 1 + .claude/skills/pr-review | 1 + .claude/skills/project-setup | 1 + .claude/skills/release-builds | 1 + .claude/skills/release-prepare | 1 + .claude/skills/secrets-bootstrap | 1 + .claude/skills/upgrade | 1 + AGENTS.md | 45 +++++++++++++++---- README.md | 20 ++++----- .../SKILL.md | 4 +- .../SKILL.md | 2 +- .../SKILL.md | 2 +- .../SKILL.md | 4 +- .../SKILL.md | 12 ++--- .../scripts/archive_ios_ipa.sh | 2 +- .../SKILL.md | 2 +- .../SKILL.md | 2 +- .../SKILL.md | 2 +- 28 files changed, 145 insertions(+), 43 deletions(-) create mode 100644 .claude/commands/feature-data-flow.md create mode 100644 .claude/commands/feature-screen.md create mode 100644 .claude/commands/pr-review.md create mode 100644 .claude/commands/project-setup.md create mode 100644 .claude/commands/release-builds.md create mode 100644 .claude/commands/release-prepare.md create mode 100644 .claude/commands/secrets-bootstrap.md create mode 100644 .claude/commands/upgrade.md create mode 120000 .claude/skills/feature-data-flow create mode 120000 .claude/skills/feature-screen create mode 120000 .claude/skills/pr-review create mode 120000 .claude/skills/project-setup create mode 120000 .claude/skills/release-builds create mode 120000 .claude/skills/release-prepare create mode 120000 .claude/skills/secrets-bootstrap create mode 120000 .claude/skills/upgrade rename ai/skills/{flutter-template-feature-data-flow => feature-data-flow}/SKILL.md (97%) rename ai/skills/{flutter-template-feature-screen => feature-screen}/SKILL.md (98%) rename ai/skills/{flutter-template-pr-review => pr-review}/SKILL.md (98%) rename ai/skills/{flutter-template-project-setup => project-setup}/SKILL.md (98%) rename ai/skills/{flutter-template-release-builds => release-builds}/SKILL.md (90%) rename ai/skills/{flutter-template-release-builds => release-builds}/scripts/archive_ios_ipa.sh (93%) rename ai/skills/{flutter-template-release-prepare => release-prepare}/SKILL.md (97%) rename ai/skills/{flutter-template-secrets-bootstrap => secrets-bootstrap}/SKILL.md (97%) rename ai/skills/{flutter-template-upgrade => upgrade}/SKILL.md (98%) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 261a544..41c379b 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -1,10 +1,13 @@ @../AGENTS.md -Project-specific reusable AI workflows live in `../ai/skills/`: -- `../ai/skills/flutter-template-feature-screen/SKILL.md` -- `../ai/skills/flutter-template-feature-data-flow/SKILL.md` -- `../ai/skills/flutter-template-upgrade/SKILL.md` -- `../ai/skills/flutter-template-release-prepare/SKILL.md` -- `../ai/skills/flutter-template-release-builds/SKILL.md` -- `../ai/skills/flutter-template-secrets-bootstrap/SKILL.md` -- `../ai/skills/flutter-template-pr-review/SKILL.md` +Project-specific reusable AI workflows live in `../ai/skills/` and are surfaced +to Claude Code two ways: +- **auto-discovery**: `./skills/` is symlinked to `../ai/skills/`, + so Claude reads the SKILL.md frontmatter and triggers them based on context. +- **slash commands**: `./commands/.md` exposes each skill as an explicit + command — `/project-setup`, `/feature-screen`, `/feature-data-flow`, + `/upgrade`, `/release-prepare`, `/release-builds`, `/secrets-bootstrap`, + `/pr-review`. + +See the "Reusable Workflows" section of `AGENTS.md` for the canonical list of +skills and the four-step convention for adding a new one. diff --git a/.claude/commands/feature-data-flow.md b/.claude/commands/feature-data-flow.md new file mode 100644 index 0000000..0a1d49a --- /dev/null +++ b/.claude/commands/feature-data-flow.md @@ -0,0 +1,8 @@ +--- +description: Build a full backend-backed feature (DTOs, entities, use cases, state, UI). +argument-hint: [feature name + API endpoint(s) or data source] +--- + +Use the `feature-data-flow` skill to implement a complete data-backed feature. + +$ARGUMENTS diff --git a/.claude/commands/feature-screen.md b/.claude/commands/feature-screen.md new file mode 100644 index 0000000..33c9ebe --- /dev/null +++ b/.claude/commands/feature-screen.md @@ -0,0 +1,8 @@ +--- +description: Add a new screen / route / feature folder using the existing pattern. +argument-hint: [feature name or short description] +--- + +Use the `feature-screen` skill to add a new screen or route in `lib/features/`. + +$ARGUMENTS diff --git a/.claude/commands/pr-review.md b/.claude/commands/pr-review.md new file mode 100644 index 0000000..aaf6d33 --- /dev/null +++ b/.claude/commands/pr-review.md @@ -0,0 +1,8 @@ +--- +description: Bug-first review of the current branch or diff. Findings first, ordered by severity. +argument-hint: [optional branch, PR, or scope hints] +--- + +Use the `pr-review` skill to review the current branch / diff / PR. + +$ARGUMENTS diff --git a/.claude/commands/project-setup.md b/.claude/commands/project-setup.md new file mode 100644 index 0000000..763ee80 --- /dev/null +++ b/.claude/commands/project-setup.md @@ -0,0 +1,8 @@ +--- +description: Customize a fresh template (app identity, platforms, icons, splash, Firebase, secrets). +argument-hint: [setup phase or specific item] +--- + +Use the `project-setup` skill to customize this template for a new app. + +$ARGUMENTS diff --git a/.claude/commands/release-builds.md b/.claude/commands/release-builds.md new file mode 100644 index 0000000..e01efa9 --- /dev/null +++ b/.claude/commands/release-builds.md @@ -0,0 +1,8 @@ +--- +description: Post-merge release builds — Android tags and iOS IPA generation + archival. +argument-hint: [flavor or step: develop|staging|production] +--- + +Use the `release-builds` skill for post-merge release builds. Run only after the release PR has been merged. + +$ARGUMENTS diff --git a/.claude/commands/release-prepare.md b/.claude/commands/release-prepare.md new file mode 100644 index 0000000..9f3ec0e --- /dev/null +++ b/.claude/commands/release-prepare.md @@ -0,0 +1,8 @@ +--- +description: Prepare a release branch + PR (version bump, release notes, branch). +argument-hint: [target version, e.g. 1.4.0+12] +--- + +Use the `release-prepare` skill to prepare the release branch and PR. Do not create tags or build artifacts in this phase. + +$ARGUMENTS diff --git a/.claude/commands/secrets-bootstrap.md b/.claude/commands/secrets-bootstrap.md new file mode 100644 index 0000000..05726b4 --- /dev/null +++ b/.claude/commands/secrets-bootstrap.md @@ -0,0 +1,8 @@ +--- +description: Work with encrypted secrets, env files, and signing material safely. +argument-hint: [operation: decrypt | encrypt | clean | inspect] +--- + +Use the `secrets-bootstrap` skill. Prefer existing make targets and avoid logging secret values. + +$ARGUMENTS diff --git a/.claude/commands/upgrade.md b/.claude/commands/upgrade.md new file mode 100644 index 0000000..ca49a1f --- /dev/null +++ b/.claude/commands/upgrade.md @@ -0,0 +1,8 @@ +--- +description: Upgrade Flutter SDK and/or package dependencies, keeping everything aligned. +argument-hint: [target Flutter version or scope] +--- + +Use the `upgrade` skill to bump the Flutter SDK and dependencies. + +$ARGUMENTS diff --git a/.claude/skills/feature-data-flow b/.claude/skills/feature-data-flow new file mode 120000 index 0000000..3055f98 --- /dev/null +++ b/.claude/skills/feature-data-flow @@ -0,0 +1 @@ +../../ai/skills/feature-data-flow \ No newline at end of file diff --git a/.claude/skills/feature-screen b/.claude/skills/feature-screen new file mode 120000 index 0000000..3df57fb --- /dev/null +++ b/.claude/skills/feature-screen @@ -0,0 +1 @@ +../../ai/skills/feature-screen \ No newline at end of file diff --git a/.claude/skills/pr-review b/.claude/skills/pr-review new file mode 120000 index 0000000..dcb8e77 --- /dev/null +++ b/.claude/skills/pr-review @@ -0,0 +1 @@ +../../ai/skills/pr-review \ No newline at end of file diff --git a/.claude/skills/project-setup b/.claude/skills/project-setup new file mode 120000 index 0000000..73b95d9 --- /dev/null +++ b/.claude/skills/project-setup @@ -0,0 +1 @@ +../../ai/skills/project-setup \ No newline at end of file diff --git a/.claude/skills/release-builds b/.claude/skills/release-builds new file mode 120000 index 0000000..50332b4 --- /dev/null +++ b/.claude/skills/release-builds @@ -0,0 +1 @@ +../../ai/skills/release-builds \ No newline at end of file diff --git a/.claude/skills/release-prepare b/.claude/skills/release-prepare new file mode 120000 index 0000000..243af08 --- /dev/null +++ b/.claude/skills/release-prepare @@ -0,0 +1 @@ +../../ai/skills/release-prepare \ No newline at end of file diff --git a/.claude/skills/secrets-bootstrap b/.claude/skills/secrets-bootstrap new file mode 120000 index 0000000..fff4db6 --- /dev/null +++ b/.claude/skills/secrets-bootstrap @@ -0,0 +1 @@ +../../ai/skills/secrets-bootstrap \ No newline at end of file diff --git a/.claude/skills/upgrade b/.claude/skills/upgrade new file mode 120000 index 0000000..4bd522a --- /dev/null +++ b/.claude/skills/upgrade @@ -0,0 +1 @@ +../../ai/skills/upgrade \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 6206b90..88415bc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -43,12 +43,39 @@ Use this file as the entrypoint for automated work in this repository. - If you learn a stable, repo-specific convention while working, update `docs/PROJECT_OVERVIEW.md` or `docs/PROJECT_GUIDELINES.md` instead of adding duplicate instructions elsewhere. ## Reusable Workflows -- Shared AI workflow guides live under `ai/skills/`. -- Use them for repeatable procedures such as: - - creating a new feature screen - - building a full data-backed feature - - upgrading Flutter and dependencies - - preparing a release branch and PR - - running post-merge release builds - - working with encrypted secrets and signing material - - reviewing pull requests and diffs +Repeatable procedures live as skills under `ai/skills//SKILL.md`. Each +skill has YAML frontmatter (`name:`, `description:`) so it can be auto-discovered +by AI tools that support skills. + +Existing skills: +- `project-setup` — customize a new app from this template (identity, platforms, icons, splash, Firebase/secrets, validation) +- `feature-screen` — add a new route / screen using the existing feature pattern +- `feature-data-flow` — build a full backend-backed feature (DTOs, entities, use cases, state, UI) +- `upgrade` — upgrade Flutter SDK and package dependencies +- `release-prepare` — version bump, release notes, release branch, release PR +- `release-builds` — post-merge Android tags and iOS IPA generation + archival +- `secrets-bootstrap` — safe handling of encrypted secrets and signing material +- `pr-review` — bug-first review of branches / diffs / PRs + +### How AI tools find these skills +- **Codex** reads this `AGENTS.md` and the referenced `ai/skills//SKILL.md` + files. When delegating, mention the workflow by name, e.g. *"use the + feature-data-flow workflow"*. +- **Claude Code** auto-discovers skills through `.claude/skills/` symlinks + that point at `ai/skills//`. Each skill is also exposed as a slash + command at `.claude/commands/.md`, so `/feature-screen`, `/pr-review`, + `/release-prepare`, etc. work as explicit invocations. + +### Creating a new skill +When adding a new repeatable workflow, complete all four steps so both Codex and +Claude can use it: +1. **Author the skill.** Create `ai/skills//SKILL.md` with YAML frontmatter + (`name:` matching the folder, `description:` explaining when to use it) and + the workflow body. +2. **Mention it for Codex.** Add the skill to the "Existing skills" list above. +3. **Expose it to Claude Code (auto-discovery).** Add a symlink: + `ln -s ../../ai/skills/ .claude/skills/` +4. **Add a slash command.** Create `.claude/commands/.md` using one of the + existing commands as a template — a short frontmatter (`description`, + `argument-hint`) and a one-line body that invokes the skill, followed by + `$ARGUMENTS`. diff --git a/README.md b/README.md index 153c29b..ffce976 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ These are our four core values: ## Automated steps -The following steps can be completed or coordinated by `ai/skills/flutter-template-project-setup`. +The following steps can be completed or coordinated by `ai/skills/project-setup`. 1. - [ ] Remove any unused platforms (Android, iOS, web, Windows, Linux (+snap), macOS) - Remove them from the folder structure of the template. @@ -504,17 +504,17 @@ Canonical project files: - `.claude/CLAUDE.md` points Claude users at the shared project instructions. Reusable workflow guides live under `ai/skills/`: -- `flutter-template-project-setup` for app identity, icons, splash, platform cleanup, Firebase/secrets decisions, and initial validation. -- `flutter-template-feature-screen` for route and UI scaffolding. -- `flutter-template-feature-data-flow` for full backend-backed features with DTOs, entities, use cases, and state wiring. -- `flutter-template-upgrade` for Flutter and dependency upgrades. -- `flutter-template-release-prepare` for version bump, release notes, release branch, and PR preparation. -- `flutter-template-release-builds` for post-merge Android tags plus manual iOS IPA generation and archival. -- `flutter-template-secrets-bootstrap` for safe handling of encrypted secrets and signing material. -- `flutter-template-pr-review` for bug-first PR and diff review. +- `project-setup` for app identity, icons, splash, platform cleanup, Firebase/secrets decisions, and initial validation. +- `feature-screen` for route and UI scaffolding. +- `feature-data-flow` for full backend-backed features with DTOs, entities, use cases, and state wiring. +- `upgrade` for Flutter and dependency upgrades. +- `release-prepare` for version bump, release notes, release branch, and PR preparation. +- `release-builds` for post-merge Android tags plus manual iOS IPA generation and archival. +- `secrets-bootstrap` for safe handling of encrypted secrets and signing material. +- `pr-review` for bug-first PR and diff review. Recommended usage: -- When working with an AI agent, explicitly mention the workflow you want to use, for example `Use the flutter-template-feature-data-flow skill`. +- When working with an AI agent, explicitly mention the workflow you want to use, for example `Use the feature-data-flow skill`. - Keep long-term project rules in `AGENTS.md` and the docs, and keep repeatable procedures in `ai/skills/`. - Treat the repo-local workflow guides as project-specific assets that should evolve with the template. diff --git a/ai/skills/flutter-template-feature-data-flow/SKILL.md b/ai/skills/feature-data-flow/SKILL.md similarity index 97% rename from ai/skills/flutter-template-feature-data-flow/SKILL.md rename to ai/skills/feature-data-flow/SKILL.md index e1611a1..6826e0b 100644 --- a/ai/skills/flutter-template-feature-data-flow/SKILL.md +++ b/ai/skills/feature-data-flow/SKILL.md @@ -1,5 +1,5 @@ --- -name: flutter-template-feature-data-flow +name: feature-data-flow description: Build a full feature in this Flutter repository that includes backend or storage data flow: read API schema, create DTOs, map DTOs to entities, add Riverpod use cases, connect feature state, and render UI data. Use when a task goes beyond a screen and needs real data integration. --- @@ -14,7 +14,7 @@ Use this skill when implementing a complete feature with data flow, not just a r - a feature that should load data into Riverpod state - a feature that should read Swagger or backend schema before implementation -If the task is only a route and UI shell, prefer `flutter-template-feature-screen`. +If the task is only a route and UI shell, prefer `feature-screen`. ## Read First - `AGENTS.md` diff --git a/ai/skills/flutter-template-feature-screen/SKILL.md b/ai/skills/feature-screen/SKILL.md similarity index 98% rename from ai/skills/flutter-template-feature-screen/SKILL.md rename to ai/skills/feature-screen/SKILL.md index b87c9be..335a42f 100644 --- a/ai/skills/flutter-template-feature-screen/SKILL.md +++ b/ai/skills/feature-screen/SKILL.md @@ -1,5 +1,5 @@ --- -name: flutter-template-feature-screen +name: feature-screen description: Create a new Flutter screen in this repository using the existing feature structure, AutoRoute setup, Riverpod state pattern, and code generation workflow. Use when adding a new page, route, stateful screen, or feature folder in this template. --- diff --git a/ai/skills/flutter-template-pr-review/SKILL.md b/ai/skills/pr-review/SKILL.md similarity index 98% rename from ai/skills/flutter-template-pr-review/SKILL.md rename to ai/skills/pr-review/SKILL.md index 82ace2c..73493f5 100644 --- a/ai/skills/flutter-template-pr-review/SKILL.md +++ b/ai/skills/pr-review/SKILL.md @@ -1,5 +1,5 @@ --- -name: flutter-template-pr-review +name: pr-review description: Review pull requests and diffs in this Flutter repository with a bug-finding mindset. Use when asked to review changes, review a PR, audit a diff, or check for regressions, missing tests, release risks, or architecture mismatches. --- diff --git a/ai/skills/flutter-template-project-setup/SKILL.md b/ai/skills/project-setup/SKILL.md similarity index 98% rename from ai/skills/flutter-template-project-setup/SKILL.md rename to ai/skills/project-setup/SKILL.md index d2b4fd7..5442f12 100644 --- a/ai/skills/flutter-template-project-setup/SKILL.md +++ b/ai/skills/project-setup/SKILL.md @@ -1,5 +1,5 @@ --- -name: flutter-template-project-setup +name: project-setup description: Customize a new project created from this Flutter template, including app identity, package name, platform cleanup, icons, splash screen, Firebase/secrets decisions, setup tool execution, code generation, and validation. --- @@ -35,7 +35,7 @@ Use this skill when preparing a new app from this template or reviewing whether 4. Run `make setup` from the repository root and select the needed setup operation. 5. If platform support changes, run the Platform Cleanup Workflow below. 6. If Firebase support changes, run the Firebase Workflow below. -7. If secrets or signing material are needed, use the `flutter-template-secrets-bootstrap` workflow. +7. If secrets or signing material are needed, use the `secrets-bootstrap` workflow. 8. Update the README First steps checklist to mark any completed setup items with `[x]`. 9. Run `make gen` after setup changes that affect routes, localization, generated assets, or annotations. 10. Validate with `fvm flutter analyze` and the relevant tests. diff --git a/ai/skills/flutter-template-release-builds/SKILL.md b/ai/skills/release-builds/SKILL.md similarity index 90% rename from ai/skills/flutter-template-release-builds/SKILL.md rename to ai/skills/release-builds/SKILL.md index edf0cba..5851cc2 100644 --- a/ai/skills/flutter-template-release-builds/SKILL.md +++ b/ai/skills/release-builds/SKILL.md @@ -1,5 +1,5 @@ --- -name: flutter-template-release-builds +name: release-builds description: Run post-merge release build steps for this repository, including Android tag-driven releases and sequential iOS IPA generation with archival for Transporter upload and Crashlytics deobfuscation. Use after the release PR has been merged. --- @@ -14,7 +14,7 @@ Use this skill only after the release PR has been merged. - `pubspec.yaml` - `makefile` - `.github/workflows/` -- `ai/skills/flutter-template-release-builds/scripts/archive_ios_ipa.sh` +- `ai/skills/release-builds/scripts/archive_ios_ipa.sh` ## Goal This skill is for the post-merge release-build phase. @@ -62,13 +62,13 @@ Immediately after each IPA build, archive the IPA out of `build/ios/ipa/` and Fl Use: ```bash -sh ai/skills/flutter-template-release-builds/scripts/archive_ios_ipa.sh +sh ai/skills/release-builds/scripts/archive_ios_ipa.sh ``` Examples: -- `sh ai/skills/flutter-template-release-builds/scripts/archive_ios_ipa.sh develop` -- `sh ai/skills/flutter-template-release-builds/scripts/archive_ios_ipa.sh staging` -- `sh ai/skills/flutter-template-release-builds/scripts/archive_ios_ipa.sh production` +- `sh ai/skills/release-builds/scripts/archive_ios_ipa.sh develop` +- `sh ai/skills/release-builds/scripts/archive_ios_ipa.sh staging` +- `sh ai/skills/release-builds/scripts/archive_ios_ipa.sh production` The script copies the generated IPA into: diff --git a/ai/skills/flutter-template-release-builds/scripts/archive_ios_ipa.sh b/ai/skills/release-builds/scripts/archive_ios_ipa.sh similarity index 93% rename from ai/skills/flutter-template-release-builds/scripts/archive_ios_ipa.sh rename to ai/skills/release-builds/scripts/archive_ios_ipa.sh index 11bf2d1..7a020eb 100644 --- a/ai/skills/flutter-template-release-builds/scripts/archive_ios_ipa.sh +++ b/ai/skills/release-builds/scripts/archive_ios_ipa.sh @@ -3,7 +3,7 @@ set -eu if [ "$#" -ne 1 ]; then - echo "Usage: sh ai/skills/flutter-template-release-builds/scripts/archive_ios_ipa.sh " >&2 + echo "Usage: sh ai/skills/release-builds/scripts/archive_ios_ipa.sh " >&2 exit 1 fi diff --git a/ai/skills/flutter-template-release-prepare/SKILL.md b/ai/skills/release-prepare/SKILL.md similarity index 97% rename from ai/skills/flutter-template-release-prepare/SKILL.md rename to ai/skills/release-prepare/SKILL.md index 6909bb4..3a29b71 100644 --- a/ai/skills/flutter-template-release-prepare/SKILL.md +++ b/ai/skills/release-prepare/SKILL.md @@ -1,5 +1,5 @@ --- -name: flutter-template-release-prepare +name: release-prepare description: Prepare a release in this repository by bumping the app version, updating release notes, creating a release branch named release/, and preparing the PR for merge before any release builds or tags are created. --- diff --git a/ai/skills/flutter-template-secrets-bootstrap/SKILL.md b/ai/skills/secrets-bootstrap/SKILL.md similarity index 97% rename from ai/skills/flutter-template-secrets-bootstrap/SKILL.md rename to ai/skills/secrets-bootstrap/SKILL.md index 7f14425..937bef5 100644 --- a/ai/skills/flutter-template-secrets-bootstrap/SKILL.md +++ b/ai/skills/secrets-bootstrap/SKILL.md @@ -1,5 +1,5 @@ --- -name: flutter-template-secrets-bootstrap +name: secrets-bootstrap description: Safely work with encrypted secrets, environment files, and signing material in this repository. Use when a task requires loading, decrypting, validating, or explaining the repo's secrets and signing setup. --- diff --git a/ai/skills/flutter-template-upgrade/SKILL.md b/ai/skills/upgrade/SKILL.md similarity index 98% rename from ai/skills/flutter-template-upgrade/SKILL.md rename to ai/skills/upgrade/SKILL.md index 2e97c0c..b9fa14d 100644 --- a/ai/skills/flutter-template-upgrade/SKILL.md +++ b/ai/skills/upgrade/SKILL.md @@ -1,5 +1,5 @@ --- -name: flutter-template-upgrade +name: upgrade description: Upgrade Flutter and package dependencies in this repository while keeping .fvmrc, pubspec.yaml, code generation, CI, and tests aligned. Use when bumping Flutter, Dart constraints, direct dependencies, or generator toolchains. --- From fdd006fe3e2192ea41a4e76bc0b137e95ffcc39e Mon Sep 17 00:00:00 2001 From: Michal Urbanek Date: Fri, 15 May 2026 09:47:21 +0200 Subject: [PATCH 2/9] fix: Skills symlink and settings for permissions added --- .claude/CLAUDE.md | 6 ++++-- .claude/settings.json | 45 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 .claude/settings.json diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 41c379b..a0ed72c 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -2,8 +2,10 @@ Project-specific reusable AI workflows live in `../ai/skills/` and are surfaced to Claude Code two ways: -- **auto-discovery**: `./skills/` is symlinked to `../ai/skills/`, - so Claude reads the SKILL.md frontmatter and triggers them based on context. +- **auto-discovery**: `./skills/` is a symlink with target + `../../ai/skills/` (resolved from `.claude/skills/`, this points + at `/ai/skills/`), so Claude reads the SKILL.md frontmatter + and triggers them based on context. - **slash commands**: `./commands/.md` exposes each skill as an explicit command — `/project-setup`, `/feature-screen`, `/feature-data-flow`, `/upgrade`, `/release-prepare`, `/release-builds`, `/secrets-bootstrap`, diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..d61c709 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,45 @@ +{ + "permissions": { + "deny": [ + "Read(**/google-services.json)", + "Read(**/GoogleService-Info.plist)", + "Read(**/local.properties)", + "Read(**/keystore.properties)", + "Read(**/*.jks)", + "Read(**/*.keystore)", + "Read(**/*.p12)", + "Read(**/*.mobileprovision)", + "Read(**/*.provisionprofile)", + "Read(**/.env)", + "Read(**/.env.*)", + "Read(**/*.pem)", + "Read(**/*.key)", + "Read(**/*.cer)", + "Read(**/*.p8)", + "Read(**/secrets.json)", + "Read(**/secrets.yaml)", + "Read(**/secrets.properties)", + "Read(**/service-account*.json)", + "Read(**/.netrc)", + "Read(**/.npmrc)", + "Read(**/extras/**)", + "Read(**/.gitmodules)", + "Read(**/.gradle/**)", + "Read(**/.idea/**)", + "Read(**/.git/**)", + "Read(**/.kotlin/**)", + "Read(**/.run/**)", + "Read(**/build/**)", + "Read(**/.dart_tool/**)", + "Read(**/.fvm/**)", + "Read(**/Pods/**)", + "Read(**/DerivedData/**)", + "Read(**/xcuserdata/**)", + "Read(**/*.xcuserstate)", + "Read(**/Flutter/Generated.xcconfig)", + "Read(**/Flutter/flutter_export_environment.sh)", + "Read(**/coverage/**)", + "Read(**/.DS_Store)" + ] + } +} From 0ab16a5386e004a7fb557ec691f8c74e9072e933 Mon Sep 17 00:00:00 2001 From: Michal Urbanek Date: Fri, 15 May 2026 09:57:55 +0200 Subject: [PATCH 3/9] feat: Add templates --- ai/templates/prd.md | 68 +++++++++++++++++++++++++++++ ai/templates/task-list.md | 19 +++++++++ ai/templates/task.md | 84 ++++++++++++++++++++++++++++++++++++ ai/templates/techspec.md | 90 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 261 insertions(+) create mode 100644 ai/templates/prd.md create mode 100644 ai/templates/task-list.md create mode 100644 ai/templates/task.md create mode 100644 ai/templates/techspec.md diff --git a/ai/templates/prd.md b/ai/templates/prd.md new file mode 100644 index 0000000..bb9c8db --- /dev/null +++ b/ai/templates/prd.md @@ -0,0 +1,68 @@ +# Product Requirements Document (PRD) Template + +## Overview + +[Provide a high-level overview of your product/feature. Explain what problem it solves, who it's for, and why it's valuable.] + +## Objectives + +[List specific and measurable objectives for this feature: + +- What success looks like +- Key metrics to track +- Business objectives to achieve] + +## User Stories + +[Detail user narratives describing usage and benefits of the feature: + +- As a [user type], I want [to perform an action] so that [benefit] +- Include primary and secondary user personas +- Cover main flows and edge cases] + +## Main Features + +[List and describe the main features of your product. For each feature, include: + +- What it does +- Why it's important +- How it works at a high level +- Functional requirements (numbered for clarity)] + +## User Experience + +[Describe the user journey and experience: + +- User personas and their needs +- Main user flows and interactions +- UI/UX considerations and requirements +- Accessibility requirements] + +## High-Level Technical Constraints + +[Capture only high-level constraints and considerations: + +- Required external integrations or existing systems to interface with +- Compliance, regulatory, or security mandates +- Performance/scalability targets +- Data sensitivity/privacy considerations +- Non-negotiable technology or protocol requirements + +Implementation details will be addressed in the Technical Specification.] + +## Out of Scope + +[Clearly state what this feature will NOT include: + +- Explicitly excluded features +- Future considerations that are out of scope +- Boundaries and limitations] + +## Open Questions + +[List any remaining questions or areas needing additional clarification: + +- Unclear requirements or edge cases +- Questions about user needs or business objectives +- Dependencies on external business factors +- Areas requiring design or user research] diff --git a/ai/templates/task-list.md b/ai/templates/task-list.md new file mode 100644 index 0000000..15f6809 --- /dev/null +++ b/ai/templates/task-list.md @@ -0,0 +1,19 @@ +# Implementation Tasks for [Feature Name] + +## Overview +[Brief description] + +## Task List +### Phase 1: Foundation +- [ ] 1.0 [Task title] + +### Phase 2: Core Implementation +- [ ] 2.0 [Task title] + +### Phase 3: Integration +- [ ] 3.0 [Task title] + +## Dependency Graph +``` +1.0 → 2.0 → 3.0 +``` diff --git a/ai/templates/task.md b/ai/templates/task.md new file mode 100644 index 0000000..eb2c5b0 --- /dev/null +++ b/ai/templates/task.md @@ -0,0 +1,84 @@ + +## What are we building? +[Clear description of what this feature/system does] + +## Why are we building it? +[Business value, user problem being solved] + +## How does it connect to everything else? +[Where does data flow from/to? What other parts of the system does this touch?] + +## What does success look like? +[Concrete outcome - what should the user be able to do when this is done?] + + + +## Data Model + +### Entities +[Define the core entities, their fields, and relationships] + +### Seed Data +[Initial data needed] + +## Dependencies + +### Requires (inputs) +- [What existing data/APIs/services does this need?] + +### Provides (outputs) +- [What does this expose to other parts of the system?] + +### Third-party integrations +- [External APIs, services, data sources needed] + + + +## Core Behavior +[Describe the main flows and logic] + +## Key Screens/Components +[List main UI pieces without being overly prescriptive] + +## Edge Cases +[What happens when things go wrong? Empty states? Errors?] + + + +## Must Have +- [Non-negotiable requirement] + +## Must NOT Have +- [What to avoid - tech debt, patterns to skip] + +## Follow Existing Patterns From +- [Reference file/component to match] + + + +## No Gaping Problems +- [ ] [Check that prevents future refactoring] + +## Ready to Ship +- [ ] [What "good enough" looks like for v1] + + + +## Clarify Before Starting + +> If any of the following are unclear or missing, **ASK before implementing**. Do not assume or invent solutions. + +- [ ] Is the data model complete? Any missing fields or relationships? +- [ ] Are all dependencies available and accessible? +- [ ] Are there existing patterns in the codebase to follow? +- [ ] What's the priority - speed to ship or polish? + + + +## Reference Materials +- [Link to relevant PRD, wireframes, or specs] + +## Codebase Location +- Feature path: `[where this code should live]` +- Related code: `[existing code to reference]` + diff --git a/ai/templates/techspec.md b/ai/templates/techspec.md new file mode 100644 index 0000000..5ed98e5 --- /dev/null +++ b/ai/templates/techspec.md @@ -0,0 +1,90 @@ +# Technical Specification Template + +## Executive Summary + +[Provide a brief technical overview of the solution approach. Summarize main architectural decisions and implementation strategy in 1-2 paragraphs.] + +## System Architecture + +### Component Overview + +[Brief description of main components and their responsibilities: + +- Component names and primary functions +- Main relationships between components +- Data flow overview] + +## Implementation Design + +### Main Interfaces + +[Define main service interfaces (≤20 lines per example): + +```kotlin +// Example interface definition +interface ServiceName { + suspend fun methodName(input: InputType): OutputType +} +``` + +] + +### Data Models + +[Define essential data structures: + +- Main domain entities (if applicable) +- Request/response types +- Database schemas (if applicable)] + +## Integration Points + +[Include only if the feature requires external integrations: + +- External services or APIs +- Authentication requirements +- Error handling approach] + +## Development Sequencing + +### Build Order + +[Define implementation sequence: + +1. First component/feature (why first) +2. Second component/feature (dependencies) +3. Subsequent components +4. Integration and testing] + +### Technical Dependencies + +[List any blocking dependencies: + +- Required infrastructure +- External service availability] + +## Technical Considerations + +### Main Decisions + +[Document important technical decisions: + +- Approach choice and justification +- Trade-offs considered +- Rejected alternatives and why] + +### Known Risks + +[Identify technical risks: + +- Potential challenges +- Mitigation approaches +- Areas needing research] + +### Standards Compliance + +[Review the rules in `AGENTS.md` and the relevant `.claude/skills/*/SKILL.md` files that apply to this techspec and list them below:] + +### Relevant Files + +[List relevant files here] From eb824845f807aaf390cf5a9dfac631b08092f2e8 Mon Sep 17 00:00:00 2001 From: Michal Urbanek Date: Fri, 15 May 2026 10:03:33 +0200 Subject: [PATCH 4/9] chore: Convert templates to Kotlin oriented specs --- ai/templates/prd.md | 14 ++++--- ai/templates/task-list.md | 20 ++++++---- ai/templates/task.md | 53 +++++++++++++++--------- ai/templates/techspec.md | 84 ++++++++++++++++++++++++++------------- 4 files changed, 113 insertions(+), 58 deletions(-) diff --git a/ai/templates/prd.md b/ai/templates/prd.md index bb9c8db..69d1978 100644 --- a/ai/templates/prd.md +++ b/ai/templates/prd.md @@ -9,7 +9,7 @@ [List specific and measurable objectives for this feature: - What success looks like -- Key metrics to track +- Key metrics to track (events captured via Firebase Analytics if applicable) - Business objectives to achieve] ## User Stories @@ -36,16 +36,19 @@ - User personas and their needs - Main user flows and interactions - UI/UX considerations and requirements -- Accessibility requirements] +- Accessibility requirements (semantics, text scaling, contrast) +- Localization expectations (which languages are in scope)] ## High-Level Technical Constraints [Capture only high-level constraints and considerations: -- Required external integrations or existing systems to interface with +- Target platforms (iOS, Android, web, macOS, Windows, Linux) and minimum OS versions +- Required external integrations (backend APIs, Firebase services, third-party SDKs) - Compliance, regulatory, or security mandates -- Performance/scalability targets -- Data sensitivity/privacy considerations +- Performance/scalability targets (frame budget, cold start, payload size) +- Data sensitivity / privacy considerations (PII, encrypted storage, consent) +- Offline / poor-connectivity behavior expectations - Non-negotiable technology or protocol requirements Implementation details will be addressed in the Technical Specification.] @@ -55,6 +58,7 @@ Implementation details will be addressed in the Technical Specification.] [Clearly state what this feature will NOT include: - Explicitly excluded features +- Platforms not targeted by this iteration - Future considerations that are out of scope - Boundaries and limitations] diff --git a/ai/templates/task-list.md b/ai/templates/task-list.md index 15f6809..e653a64 100644 --- a/ai/templates/task-list.md +++ b/ai/templates/task-list.md @@ -4,16 +4,22 @@ [Brief description] ## Task List -### Phase 1: Foundation -- [ ] 1.0 [Task title] +### Phase 1: Foundation (data layer) +- [ ] 1.0 [Task title — DTOs, entities, repository, use cases; run `make gen` after annotation changes] -### Phase 2: Core Implementation -- [ ] 2.0 [Task title] +### Phase 2: Core Implementation (state + UI) +- [ ] 2.0 [Task title — `@riverpod` notifier, `*_state.dart`, `*_event.dart`, `*_page.dart`, `*_page_content.dart`] -### Phase 3: Integration -- [ ] 3.0 [Task title] +### Phase 3: Integration (navigation, services, platform) +- [ ] 3.0 [Task title — `@RoutePage` wiring, Firebase / platform integrations, analytics events, permissions] + +### Phase 4: Verification +- [ ] 4.0 `make gen` clean +- [ ] 4.1 `fvm flutter analyze` passes +- [ ] 4.2 `fvm flutter test` passes (with new tests for providers / use cases) +- [ ] 4.3 Smoke run on target platforms (`fvm flutter run -t lib/main_develop.dart`) ## Dependency Graph ``` -1.0 → 2.0 → 3.0 +1.0 → 2.0 → 3.0 → 4.0 ``` diff --git a/ai/templates/task.md b/ai/templates/task.md index eb2c5b0..7caf49f 100644 --- a/ai/templates/task.md +++ b/ai/templates/task.md @@ -6,7 +6,7 @@ [Business value, user problem being solved] ## How does it connect to everything else? -[Where does data flow from/to? What other parts of the system does this touch?] +[Where does data flow from/to? Which existing features, providers, repositories, or services does this touch?] ## What does success look like? [Concrete outcome - what should the user be able to do when this is done?] @@ -16,32 +16,40 @@ ## Data Model ### Entities -[Define the core entities, their fields, and relationships] +[Define the core entities, their fields, and relationships. +- DTOs live in `lib/common/data/dto/` (annotated with `@freezed` + `@JsonSerializable`) +- Domain entities live in `lib/common/data/entity/` (mapped from DTOs) +- Feature-scoped state/event types live next to the feature as `*_state.dart` / `*_event.dart`] ### Seed Data -[Initial data needed] +[Initial data needed — local fixtures, env defaults, remote config keys, etc.] ## Dependencies ### Requires (inputs) -- [What existing data/APIs/services does this need?] +- [APIs (`dio` endpoints), providers, repositories, or use cases this consumes] +- [Required Firebase services or platform permissions] ### Provides (outputs) -- [What does this expose to other parts of the system?] +- [New providers, repositories, routes, or use cases this exposes to the rest of the app] ### Third-party integrations -- [External APIs, services, data sources needed] +- [External APIs, SDKs, Firebase modules, or platform channels needed] ## Core Behavior -[Describe the main flows and logic] +[Describe the main flows and logic — user interactions, state transitions, side effects, error handling.] ## Key Screens/Components -[List main UI pieces without being overly prescriptive] +[List the main pages/widgets, following the project convention: +- `*_page.dart` — thin route widget (`@RoutePage`) +- `*_page_content.dart` — heavier UI composition +- `*_state.dart` / `*_event.dart` — Riverpod state + events +Reuse from `lib/common/` (widgets, extensions) before introducing new primitives.] ## Edge Cases -[What happens when things go wrong? Empty states? Errors?] +[What happens when things go wrong? Empty states, loading, errors, no network, permission denied, auth expired, etc.] @@ -49,18 +57,23 @@ - [Non-negotiable requirement] ## Must NOT Have -- [What to avoid - tech debt, patterns to skip] +- [What to avoid — tech debt, anti-patterns (e.g., IO directly in widgets, hand-editing generated `*.g.dart` / `*.freezed.dart` / `*.gr.dart`)] ## Follow Existing Patterns From -- [Reference file/component to match] +- [Reference feature folder under `lib/features//` whose page/content/state/event split should be mirrored] +- [Reference DTOs/entities/use cases under `lib/common/data/` to match] ## No Gaping Problems - [ ] [Check that prevents future refactoring] +- [ ] `make gen` runs clean after annotation changes +- [ ] `fvm flutter analyze` passes with no new warnings +- [ ] `fvm flutter test` passes (add tests for new providers/use cases) ## Ready to Ship - [ ] [What "good enough" looks like for v1] +- [ ] Smoke-tested on the supported platforms touched by this feature @@ -68,17 +81,21 @@ > If any of the following are unclear or missing, **ASK before implementing**. Do not assume or invent solutions. -- [ ] Is the data model complete? Any missing fields or relationships? -- [ ] Are all dependencies available and accessible? -- [ ] Are there existing patterns in the codebase to follow? -- [ ] What's the priority - speed to ship or polish? +- [ ] Is the data model complete? Any missing fields or relationships in DTOs/entities? +- [ ] Are all dependencies available (API endpoints, Firebase config, packages in `pubspec.yaml`)? +- [ ] Which existing feature under `lib/features/` should this match in structure? +- [ ] What's the priority — speed to ship or polish? ## Reference Materials -- [Link to relevant PRD, wireframes, or specs] +- [Link to relevant PRD, techspec, wireframes, or specs] +- `docs/PROJECT_OVERVIEW.md`, `docs/PROJECT_GUIDELINES.md`, `AGENTS.md` ## Codebase Location -- Feature path: `[where this code should live]` -- Related code: `[existing code to reference]` +- Feature path: `lib/features//` +- Shared data: `lib/common/data/dto/`, `lib/common/data/entity/` +- Shared UI / extensions: `lib/common/` +- Routes / app wiring: `lib/app/` +- Related code: `[existing feature(s) to reference]` diff --git a/ai/templates/techspec.md b/ai/templates/techspec.md index 5ed98e5..01f0c8c 100644 --- a/ai/templates/techspec.md +++ b/ai/templates/techspec.md @@ -2,7 +2,7 @@ ## Executive Summary -[Provide a brief technical overview of the solution approach. Summarize main architectural decisions and implementation strategy in 1-2 paragraphs.] +[Provide a brief technical overview of the solution approach. Summarize main architectural decisions and implementation strategy in 1-2 paragraphs. Mention which layers are touched: UI (`*_page.dart` / `*_page_content.dart`), state (`*_state.dart` / `*_event.dart`), data (DTOs/entities/use cases), and any platform integrations.] ## System Architecture @@ -10,40 +10,58 @@ [Brief description of main components and their responsibilities: -- Component names and primary functions -- Main relationships between components -- Data flow overview] +- Feature module under `lib/features//` — pages, content widgets, state notifier, events +- Shared widgets/extensions reused from `lib/common/` +- Data layer: DTOs in `lib/common/data/dto/`, domain entities in `lib/common/data/entity/`, use cases, repositories +- Riverpod providers / `@riverpod` notifiers and how state flows into the UI +- Navigation entry via `auto_route` (`@RoutePage`, route registration)] ## Implementation Design ### Main Interfaces -[Define main service interfaces (≤20 lines per example): +[Define main contracts (≤20 lines per example). Prefer Dart abstract classes for repositories/use cases and `@riverpod` for state. Examples: -```kotlin -// Example interface definition -interface ServiceName { - suspend fun methodName(input: InputType): OutputType +```dart +// Repository contract — implementations live in lib/common/data/ +abstract class ExampleRepository { + Future fetch(String id); + Stream> watchAll(); } ``` -] +```dart +// Riverpod state notifier — generated via riverpod_annotation +@riverpod +class ExampleController extends _$ExampleController { + @override + Future build() async => ref.read(exampleRepositoryProvider).load(); + + Future onEvent(ExampleEvent event) async { /* ... */ } +} +``` + +Run `make gen` after touching `@riverpod`, `@freezed`, `@RoutePage`, or other codegen annotations.] ### Data Models -[Define essential data structures: +[Define essential data structures using project conventions: -- Main domain entities (if applicable) -- Request/response types -- Database schemas (if applicable)] +- **DTOs** (`lib/common/data/dto/`) — wire-format models annotated with `@freezed` + `@JsonSerializable`, used by `dio` +- **Entities** (`lib/common/data/entity/`) — domain models; map from DTOs via factory or extension +- **State models** — feature-scoped `@freezed` classes alongside the feature +- **Events** — sealed/`@freezed` union types for user/system events feeding the state notifier +- Local persistence: `shared_preferences` keys/migrations if applicable] ## Integration Points [Include only if the feature requires external integrations: -- External services or APIs -- Authentication requirements -- Error handling approach] +- HTTP endpoints consumed via `dio` (auth, headers, error mapping through interceptors) +- Firebase services — Auth, Analytics, Crashlytics, Remote Config, Messaging +- Native platform channels (iOS / Android / desktop / web) if any +- Permissions handled via `permission_handler` and surfaced through `app_settings` +- Error handling: how failures are surfaced into state and logged via `talker`] ## Development Sequencing @@ -51,17 +69,20 @@ interface ServiceName { [Define implementation sequence: -1. First component/feature (why first) -2. Second component/feature (dependencies) -3. Subsequent components -4. Integration and testing] +1. Data layer — DTOs, entity mapping, repository, use cases (run `make gen`) +2. State layer — `@riverpod` notifier, state/event classes, unit tests +3. UI layer — `*_page.dart` (thin) + `*_page_content.dart` (heavy UI) +4. Navigation wiring — `@RoutePage`, route registration, deep link if needed +5. Localization strings, assets, and final QA on supported platforms] ### Technical Dependencies [List any blocking dependencies: -- Required infrastructure -- External service availability] +- Backend endpoints / API contracts ready +- Firebase project configuration (if new services are introduced) +- Required package additions to `pubspec.yaml` +- Native config changes (Android `build.gradle`, iOS `Info.plist`, entitlements)] ## Technical Considerations @@ -69,7 +90,7 @@ interface ServiceName { [Document important technical decisions: -- Approach choice and justification +- Approach choice and justification (e.g., Riverpod `Notifier` vs. `AsyncNotifier`, repository vs. direct use case) - Trade-offs considered - Rejected alternatives and why] @@ -77,14 +98,21 @@ interface ServiceName { [Identify technical risks: -- Potential challenges +- Potential challenges (codegen drift, platform-specific behavior, web/desktop parity) - Mitigation approaches -- Areas needing research] +- Areas needing spike or research] ### Standards Compliance -[Review the rules in `AGENTS.md` and the relevant `.claude/skills/*/SKILL.md` files that apply to this techspec and list them below:] +[Review the rules in `AGENTS.md`, `docs/PROJECT_OVERVIEW.md`, `docs/PROJECT_GUIDELINES.md`, and the relevant `.claude/skills/*/SKILL.md` files that apply to this techspec and list them below. + +Validation before merging: + +- `make gen` (after annotation changes) +- `fvm flutter analyze` +- `fvm flutter test` +- Platform smoke run where touched (`fvm flutter run -t lib/main_develop.dart`)] ### Relevant Files -[List relevant files here] +[List relevant files here — pages, content widgets, state/event, DTOs, entities, repositories, providers, route definitions, generated files to regenerate.] From ede359f05d06f897dfc516dba8c2f76f01535946 Mon Sep 17 00:00:00 2001 From: Michal Urbanek Date: Fri, 15 May 2026 10:34:43 +0200 Subject: [PATCH 5/9] chore: Update pr review skill --- ai/skills/pr-review/SKILL.md | 120 +++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 7 deletions(-) diff --git a/ai/skills/pr-review/SKILL.md b/ai/skills/pr-review/SKILL.md index 73493f5..7020939 100644 --- a/ai/skills/pr-review/SKILL.md +++ b/ai/skills/pr-review/SKILL.md @@ -1,6 +1,6 @@ --- name: pr-review -description: Review pull requests and diffs in this Flutter repository with a bug-finding mindset. Use when asked to review changes, review a PR, audit a diff, or check for regressions, missing tests, release risks, or architecture mismatches. +description: Review pull requests, branch diffs, and uncommitted changes in this Flutter repository with a bug-finding mindset. Use when asked to review changes, review a PR, audit a diff, check standards, check compliance, or look for regressions, missing tests, release risks, or architecture mismatches. --- # Flutter Template PR Review @@ -24,47 +24,152 @@ Do not treat the review as a style-polish exercise unless the user asks for that - `docs/PROJECT_GUIDELINES.md` - any changed files +## Determine Review Scope +Parse the user's request and choose the smallest matching diff scope. + +| User asks for | Review scope | +|:--|:--| +| default, branch review, PR review | `git diff ...HEAD` | +| uncommitted changes | `git diff` plus `git diff --cached` | +| a specific commit | `git show ` | +| last N commits | `git diff HEAD~N...HEAD` | +| branch X vs Y | `git diff X...Y` | +| explicit commit range | `git diff ` | + +Detect the default branch with: + +```bash +git symbolic-ref refs/remotes/origin/HEAD | sed 's|refs/remotes/origin/||' +``` + +If that fails, try `main`, then `master`. + +Gather: + +```bash +git diff --name-status +git diff --stat +git diff --unified=5 +``` + +For uncommitted reviews, gather both unstaged and staged diffs. If there are no changes, say so and stop. If there are more than 50 changed files, warn that it is a large review and ask whether to proceed or narrow the scope. + +## Classify Changed Files +Classify every non-deleted changed file before reviewing so the right standards are applied. A file can belong to multiple categories. + +| Category | File patterns | Review focus | +|:--|:--|:--| +| Feature UI | `lib/features/**/**_page.dart`, `lib/features/**/**_page_content.dart` | page thinness, shared widgets, localization, theme extensions, user-facing states | +| Feature state | `lib/features/**/**_state.dart`, `lib/features/**/**_event.dart` | Riverpod orchestration, async gaps, `freezed` unions, one-off events | +| Navigation | `lib/app/navigation/**`, changed `@RoutePage()` widgets | AutoRoute registration, generated route expectations, deep-link or shell behavior | +| Data and entities | `lib/common/data/dto/**`, `lib/common/data/entity/**`, `lib/common/data/enum/**` | DTO/entity separation, JSON/freezed annotations, resilient mapping | +| Use cases and providers | `lib/common/usecase/**`, `lib/common/provider/**`, `lib/core/**` | IO boundaries, provider lifetimes, startup assumptions, service wiring | +| Theme and shared UI | `lib/app/theme/**`, `lib/common/component/**`, `lib/common/composition/**` | reuse, accessibility, edge-to-edge/system bar behavior, visual consistency | +| Localization and assets | `assets/localization/**`, `pubspec.yaml`, asset inputs | generated accessors, `context.locale`, `make gen` expectations | +| Tests | `test/**`, `integration_test/**` | coverage quality, realistic assertions, Patrol vs widget-test boundaries | +| Platform files | `android/**`, `ios/**`, `web/**`, `macos/**`, `linux/**`, `windows/**` | flavor config, Firebase, signing, native build risks | +| Release and CI | `.github/**`, `makefile`, `release_notes.txt`, `.fvmrc`, `pubspec.yaml` | version alignment, workflow blast radius, release sequencing | +| Migration reference | imported Kotlin/Swift/KMP files, migration notes, copied source snippets | behavior parity only; do not require KMP/iOS style rules in Flutter code | + +Skip deleted files, generated files, and generated asset files unless the source change suggests a generation problem. Generated examples include `*.g.dart`, `*.freezed.dart`, `*.gr.dart`, `lib/assets/**`, `.generated.` files, and platform build outputs. + ## Workflow -1. Inspect the changed files and identify the behavioral surface area. +1. Inspect the changed files and classify the behavioral surface area. 2. Read the surrounding code, not just the diff hunk. -3. Check whether the change matches existing repo patterns for: +3. Apply every relevant repo-specific check for each file category. +4. Check whether the change matches existing repo patterns for: - feature structure - routing - Riverpod state handling - DTO/entity separation - codegen expectations - release/versioning workflow -4. Look for risk in: +5. Look for risk in: - startup/setup code - generated-code assumptions - notification and Firebase wiring - secrets handling - build or CI config - platform-specific files -5. Check whether tests should have changed. -6. Only after reviewing findings, summarize the overall change briefly. +6. Check whether tests should have changed. +7. Only report issues introduced by added or modified lines in the reviewed diff. Use surrounding code to understand the bug, but do not report pre-existing unrelated issues. +8. Only after reviewing findings, summarize the overall change briefly. + +## Parallel Review Lanes +When the environment supports parallel review agents and the user has asked for delegated or parallel agent work, split the diff by category and review lanes concurrently. Otherwise, perform the lanes yourself in sequence. + +Use only lanes that have matching files: + +| Lane | Categories | +|:--|:--| +| Flutter UI | Feature UI, Theme and shared UI, Localization and assets | +| Riverpod architecture | Feature state, Use cases and providers | +| Data flow | Data and entities, Use cases and providers | +| Navigation and startup | Navigation, startup/setup-facing providers, Platform files | +| Tests and release | Tests, Release and CI | +| Migration parity | Migration reference plus the Flutter files that implement the migrated behavior | + +Merge lane results by deduplicating identical file/line findings, then sort by severity. ## Output Format Present findings first, ordered by severity. Each finding should include: -- severity +- severity (`IMPORTANT` for must-fix defects or `NIT` for minor mechanical/style issues) - concise explanation of the problem - why it matters - file reference +- suggested fix After findings, optionally include: - open questions or assumptions - brief summary of what changed +- passed checklist areas, when useful If there are no findings, say so explicitly and mention any residual risk or untested area. +For standards-style reviews, use this structure: + +```text +Standards Review Report +Branch: +Compared against: +Files reviewed: +Review lanes: + +IMPORTANT Violations +... + +NIT Violations +... + +Passed Checklists +... +``` + +## Auto-Fixing NITs +If the user explicitly asks for standards/compliance review with fixes, or asks to apply safe fixes after the report, mechanically auto-fix only unambiguous `NIT` violations. + +Do: +- touch only files included in the review scope +- apply the smallest possible edit for each NIT +- leave the working tree unstaged +- list every applied NIT fix + +Do not: +- auto-fix `IMPORTANT` findings +- auto-fix ambiguous suggestions +- run broad formatting unless the NIT specifically requires it +- stage or commit fixes + ## Repo-Specific Watch Outs - Some services in this template are scaffolded but not fully enabled, especially in `lib/app/setup/setup_app.dart`. - Changes to routes, `@riverpod`, `@freezed`, DTOs, localization, or assets often imply `make gen`. - Generated files may change as part of legitimate work, but review the source change first. - Workflow and release file edits can have impact beyond local code behavior. - Widget tests under `test/` should run under `flutter test`; integration flows under `integration_test/` are separate. +- In KMP-to-Flutter migration work, check behavior parity against source material while still enforcing Flutter template architecture. +- Avoid importing KMP/iOS concepts directly into Flutter names or layers unless the destination codebase already has the equivalent abstraction. ## Good Review Questions - Does this change break the existing startup assumptions? @@ -72,3 +177,4 @@ If there are no findings, say so explicitly and mention any residual risk or unt - Does it introduce a mismatch between `.fvmrc`, `pubspec.yaml`, CI, or generated files? - Does it add behavior without adding or updating validation? - Does it change release, secrets, or notification behavior in a risky way? +- Does migrated behavior preserve user-visible flows without leaking source-platform architecture into Flutter? From 09e459cd1895b599023fc1002877d1bf0ac8bb26 Mon Sep 17 00:00:00 2001 From: Michal Urbanek Date: Fri, 15 May 2026 10:43:35 +0200 Subject: [PATCH 6/9] feat: Add skills from KMP project --- .claude/commands/build-verify.md | 8 + .claude/commands/create-pr.md | 8 + .claude/commands/implement-tasks-sequence.md | 8 + .claude/commands/implement.md | 8 + .claude/commands/lint-format.md | 8 + .claude/commands/prd.md | 8 + .claude/commands/review-pr-comments.md | 8 + .claude/commands/start-job.md | 8 + .claude/commands/tasks.md | 8 + .claude/commands/techspec.md | 8 + .claude/skills/build-verify | 1 + .claude/skills/create-pr | 1 + .claude/skills/implement | 1 + .claude/skills/implement-tasks-sequence | 1 + .claude/skills/lint-format | 1 + .claude/skills/prd | 1 + .claude/skills/review-pr-comments | 1 + .claude/skills/start-job | 1 + .claude/skills/tasks | 1 + .claude/skills/techspec | 1 + .claude/templates/prd.md | 1 + .claude/templates/task-list.md | 1 + .claude/templates/task.md | 1 + .claude/templates/techspec.md | 1 + AGENTS.md | 10 + ai/skills/build-verify/SKILL.md | 130 +++++++ ai/skills/build-verify/scripts/verify.sh | 385 +++++++++++++++++++ ai/skills/create-pr/SKILL.md | 200 ++++++++++ ai/skills/implement-tasks-sequence/SKILL.md | 81 ++++ ai/skills/implement/SKILL.md | 125 ++++++ ai/skills/lint_format/SKILL.md | 78 ++++ ai/skills/lint_format/scripts/lint_format.sh | 193 ++++++++++ ai/skills/prd/SKILL.md | 106 +++++ ai/skills/review-pr-comments/SKILL.md | 204 ++++++++++ ai/skills/start-job/SKILL.md | 92 +++++ ai/skills/tasks/SKILL.md | 125 ++++++ ai/skills/techspec/SKILL.md | 107 ++++++ 37 files changed, 1930 insertions(+) create mode 100644 .claude/commands/build-verify.md create mode 100644 .claude/commands/create-pr.md create mode 100644 .claude/commands/implement-tasks-sequence.md create mode 100644 .claude/commands/implement.md create mode 100644 .claude/commands/lint-format.md create mode 100644 .claude/commands/prd.md create mode 100644 .claude/commands/review-pr-comments.md create mode 100644 .claude/commands/start-job.md create mode 100644 .claude/commands/tasks.md create mode 100644 .claude/commands/techspec.md create mode 120000 .claude/skills/build-verify create mode 120000 .claude/skills/create-pr create mode 120000 .claude/skills/implement create mode 120000 .claude/skills/implement-tasks-sequence create mode 120000 .claude/skills/lint-format create mode 120000 .claude/skills/prd create mode 120000 .claude/skills/review-pr-comments create mode 120000 .claude/skills/start-job create mode 120000 .claude/skills/tasks create mode 120000 .claude/skills/techspec create mode 120000 .claude/templates/prd.md create mode 120000 .claude/templates/task-list.md create mode 120000 .claude/templates/task.md create mode 120000 .claude/templates/techspec.md create mode 100644 ai/skills/build-verify/SKILL.md create mode 100755 ai/skills/build-verify/scripts/verify.sh create mode 100644 ai/skills/create-pr/SKILL.md create mode 100644 ai/skills/implement-tasks-sequence/SKILL.md create mode 100644 ai/skills/implement/SKILL.md create mode 100644 ai/skills/lint_format/SKILL.md create mode 100755 ai/skills/lint_format/scripts/lint_format.sh create mode 100644 ai/skills/prd/SKILL.md create mode 100644 ai/skills/review-pr-comments/SKILL.md create mode 100644 ai/skills/start-job/SKILL.md create mode 100644 ai/skills/tasks/SKILL.md create mode 100644 ai/skills/techspec/SKILL.md diff --git a/.claude/commands/build-verify.md b/.claude/commands/build-verify.md new file mode 100644 index 0000000..458ff15 --- /dev/null +++ b/.claude/commands/build-verify.md @@ -0,0 +1,8 @@ +--- +description: Run the full build / test / analyze / format verification pass for this Flutter app. +argument-hint: [optional flags: --full | --skip-gen | --skip-builds | --ios-only | --android-only] +--- + +Use the `build-verify` skill to run codegen, analyze, test, native builds, and format. Nothing is committed. + +$ARGUMENTS diff --git a/.claude/commands/create-pr.md b/.claude/commands/create-pr.md new file mode 100644 index 0000000..7f4904a --- /dev/null +++ b/.claude/commands/create-pr.md @@ -0,0 +1,8 @@ +--- +description: Verify, commit, push, and create or update a GitHub PR. +argument-hint: [type, ticket, title, or base branch] +--- + +Use the `create-pr` skill to prepare and open a pull request. + +$ARGUMENTS diff --git a/.claude/commands/implement-tasks-sequence.md b/.claude/commands/implement-tasks-sequence.md new file mode 100644 index 0000000..ed889fc --- /dev/null +++ b/.claude/commands/implement-tasks-sequence.md @@ -0,0 +1,8 @@ +--- +description: Execute generated Flutter task files in dependency order without committing. +argument-hint: [feature name or task folder] +--- + +Use the `implement-tasks-sequence` skill to implement generated task files. + +$ARGUMENTS diff --git a/.claude/commands/implement.md b/.claude/commands/implement.md new file mode 100644 index 0000000..41f85b5 --- /dev/null +++ b/.claude/commands/implement.md @@ -0,0 +1,8 @@ +--- +description: Implement one generated Flutter task without committing. +argument-hint: [feature/task file or task number] +--- + +Use the `implement` skill to complete one Flutter task. + +$ARGUMENTS diff --git a/.claude/commands/lint-format.md b/.claude/commands/lint-format.md new file mode 100644 index 0000000..4d66eac --- /dev/null +++ b/.claude/commands/lint-format.md @@ -0,0 +1,8 @@ +--- +description: Run Flutter/Dart formatting and analyzer checks for the current worktree. +argument-hint: [auto|all|--check|--format-only|--analyze-only] +--- + +Use the `lint-format` skill to format and analyze Flutter code. + +$ARGUMENTS diff --git a/.claude/commands/prd.md b/.claude/commands/prd.md new file mode 100644 index 0000000..cf45e27 --- /dev/null +++ b/.claude/commands/prd.md @@ -0,0 +1,8 @@ +--- +description: Create a Flutter feature Product Requirements Document. +argument-hint: [feature name or brief] +--- + +Use the `prd` skill to create a product requirements document. + +$ARGUMENTS diff --git a/.claude/commands/review-pr-comments.md b/.claude/commands/review-pr-comments.md new file mode 100644 index 0000000..aa3a5e7 --- /dev/null +++ b/.claude/commands/review-pr-comments.md @@ -0,0 +1,8 @@ +--- +description: Triage and resolve AI or human GitHub PR review comments for the current branch. +argument-hint: [optional comment scope, reviewer, or fix instructions] +--- + +Use the `review-pr-comments` skill to handle PR feedback on the current branch. + +$ARGUMENTS diff --git a/.claude/commands/start-job.md b/.claude/commands/start-job.md new file mode 100644 index 0000000..a774310 --- /dev/null +++ b/.claude/commands/start-job.md @@ -0,0 +1,8 @@ +--- +description: Run the post-spec Flutter implementation pipeline end to end without committing. +argument-hint: [feature name or task folder] +--- + +Use the `start-job` skill to run tasks, implementation, verification, and PR review for a completed spec. + +$ARGUMENTS diff --git a/.claude/commands/tasks.md b/.claude/commands/tasks.md new file mode 100644 index 0000000..535a697 --- /dev/null +++ b/.claude/commands/tasks.md @@ -0,0 +1,8 @@ +--- +description: Break a PRD + tech spec into discrete, dependency-ordered implementation tasks. +argument-hint: [feature name or path to prd.md/techspec.md] +--- + +Use the `tasks` skill to generate the task list and individual task files under `.claude/tasks/[feature]/`. Requires a PRD and tech spec. + +$ARGUMENTS diff --git a/.claude/commands/techspec.md b/.claude/commands/techspec.md new file mode 100644 index 0000000..4f7a751 --- /dev/null +++ b/.claude/commands/techspec.md @@ -0,0 +1,8 @@ +--- +description: Translate a PRD into an implementation-ready Flutter tech spec. +argument-hint: [feature name or path to prd.md] +--- + +Use the `techspec` skill to author `.claude/tasks/[feature-name]/techspec.md` from the PRD, grounded in this codebase's Riverpod / Freezed / AutoRoute / Dio / Firebase stack. + +$ARGUMENTS diff --git a/.claude/skills/build-verify b/.claude/skills/build-verify new file mode 120000 index 0000000..038789c --- /dev/null +++ b/.claude/skills/build-verify @@ -0,0 +1 @@ +../../ai/skills/build-verify \ No newline at end of file diff --git a/.claude/skills/create-pr b/.claude/skills/create-pr new file mode 120000 index 0000000..d71079b --- /dev/null +++ b/.claude/skills/create-pr @@ -0,0 +1 @@ +../../ai/skills/create-pr \ No newline at end of file diff --git a/.claude/skills/implement b/.claude/skills/implement new file mode 120000 index 0000000..74bd3bf --- /dev/null +++ b/.claude/skills/implement @@ -0,0 +1 @@ +../../ai/skills/implement \ No newline at end of file diff --git a/.claude/skills/implement-tasks-sequence b/.claude/skills/implement-tasks-sequence new file mode 120000 index 0000000..9b015d6 --- /dev/null +++ b/.claude/skills/implement-tasks-sequence @@ -0,0 +1 @@ +../../ai/skills/implement-tasks-sequence \ No newline at end of file diff --git a/.claude/skills/lint-format b/.claude/skills/lint-format new file mode 120000 index 0000000..8757067 --- /dev/null +++ b/.claude/skills/lint-format @@ -0,0 +1 @@ +../../ai/skills/lint_format \ No newline at end of file diff --git a/.claude/skills/prd b/.claude/skills/prd new file mode 120000 index 0000000..97e3cf4 --- /dev/null +++ b/.claude/skills/prd @@ -0,0 +1 @@ +../../ai/skills/prd \ No newline at end of file diff --git a/.claude/skills/review-pr-comments b/.claude/skills/review-pr-comments new file mode 120000 index 0000000..f6b35ff --- /dev/null +++ b/.claude/skills/review-pr-comments @@ -0,0 +1 @@ +../../ai/skills/review-pr-comments \ No newline at end of file diff --git a/.claude/skills/start-job b/.claude/skills/start-job new file mode 120000 index 0000000..d9ea860 --- /dev/null +++ b/.claude/skills/start-job @@ -0,0 +1 @@ +../../ai/skills/start-job \ No newline at end of file diff --git a/.claude/skills/tasks b/.claude/skills/tasks new file mode 120000 index 0000000..c56e514 --- /dev/null +++ b/.claude/skills/tasks @@ -0,0 +1 @@ +../../ai/skills/tasks \ No newline at end of file diff --git a/.claude/skills/techspec b/.claude/skills/techspec new file mode 120000 index 0000000..291e8e3 --- /dev/null +++ b/.claude/skills/techspec @@ -0,0 +1 @@ +../../ai/skills/techspec \ No newline at end of file diff --git a/.claude/templates/prd.md b/.claude/templates/prd.md new file mode 120000 index 0000000..f1808a0 --- /dev/null +++ b/.claude/templates/prd.md @@ -0,0 +1 @@ +../../ai/templates/prd.md \ No newline at end of file diff --git a/.claude/templates/task-list.md b/.claude/templates/task-list.md new file mode 120000 index 0000000..0333e67 --- /dev/null +++ b/.claude/templates/task-list.md @@ -0,0 +1 @@ +../../ai/templates/task-list.md \ No newline at end of file diff --git a/.claude/templates/task.md b/.claude/templates/task.md new file mode 120000 index 0000000..17961ee --- /dev/null +++ b/.claude/templates/task.md @@ -0,0 +1 @@ +../../ai/templates/task.md \ No newline at end of file diff --git a/.claude/templates/techspec.md b/.claude/templates/techspec.md new file mode 120000 index 0000000..44313c5 --- /dev/null +++ b/.claude/templates/techspec.md @@ -0,0 +1 @@ +../../ai/templates/techspec.md \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 88415bc..0f8cf8f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -56,6 +56,16 @@ Existing skills: - `release-builds` — post-merge Android tags and iOS IPA generation + archival - `secrets-bootstrap` — safe handling of encrypted secrets and signing material - `pr-review` — bug-first review of branches / diffs / PRs +- `review-pr-comments` — triage and resolve AI or human GitHub PR feedback +- `create-pr` — verify, commit, push, and create or update a GitHub PR +- `lint-format` — run Flutter/Dart formatting and analyzer checks +- `build-verify` — full build/test/analyze/format pass (codegen + analyze + test, then iOS + Android builds in parallel, then `dart format`); auto-scopes to the diff and leaves the working tree dirty for review +- `start-job` — run the post-spec implementation pipeline (`tasks` → `implement-tasks-sequence` → `build-verify` → `pr-review`) +- `prd` — create a Flutter feature Product Requirements Document under `.claude/tasks//prd.md` +- `tasks` — break a PRD + tech spec into discrete, dependency-ordered Flutter implementation tasks under `.claude/tasks//` using `ai/templates/task.md` and `ai/templates/task-list.md` +- `implement` — implement one generated Flutter task using the repo architecture and verification rules +- `implement-tasks-sequence` — execute generated task files in dependency order before final verification +- `techspec` — translate a PRD into an implementation-ready Flutter tech spec at `.claude/tasks//techspec.md`, grounded in the Riverpod / Freezed / AutoRoute / Dio / Firebase stack ### How AI tools find these skills - **Codex** reads this `AGENTS.md` and the referenced `ai/skills//SKILL.md` diff --git a/ai/skills/build-verify/SKILL.md b/ai/skills/build-verify/SKILL.md new file mode 100644 index 0000000..41a5f5c --- /dev/null +++ b/ai/skills/build-verify/SKILL.md @@ -0,0 +1,130 @@ +--- +name: build-verify +description: > + Build/test/lint verification pass for this Flutter app — runs codegen, analyze, test, + then iOS + Android native builds in parallel, then `dart format`. Does NOT commit + anything; leaves the working tree dirty so the user can review and commit on demand. + Used at the end of the prd → techspec → tasks → implement-tasks-sequence flow before + `pr-review`, and can also be invoked manually when the user says "verify build", "run + full verification", or "check everything". +allowed-tools: Bash, Read, Grep, Glob, Edit, Skill +model: claude-sonnet-4-6 +--- + +# Build Verify + +Run the full verification suite once after all implementation work is done. This replaces +per-task verification — the implementation flow is uninterrupted and centralizes all +build / test / analyze / format checks here. + +## Usage + +Run the orchestrator script: + +```bash +.claude/skills/build-verify/scripts/verify.sh +``` + +It runs the **Dart phase** (codegen + analyze + test) sequentially with fail-fast, then +runs the **iOS** and **Android** native builds **in parallel**, then `dart format` once +both have passed. + +By default the script **auto-scopes** based on what changed (committed vs `${BASE_REF:-main}` +plus uncommitted). Auto-scoping skips irrelevant work so small, single-platform changes +aren't forced to build everything: + +| Diff shape | Auto-behavior | +|:------------------------------------------------------------|:---------------------------------------| +| All changes under `ios/` only | Skip Android native build | +| All changes under `android/` only | Skip iOS native build | +| All changes under `test/` only | Skip both native builds | +| No annotation- or pubspec-relevant changes | Skip `make gen` codegen | +| Mixed, empty, or no diff | Run everything | + +The auto-scope decision is printed at the top of the run so it's never silent. + +### Flags + +| Flag | What it does | +|:-------------------|:------------------------------------------------------------------------------| +| `--full` | Disable auto-scoping — run everything regardless of diff | +| `--skip-gen` | Explicitly skip `make gen` (assume codegen is current — also disables auto-scope) | +| `--skip-builds` | Skip native iOS + Android builds (only run Dart phase + format) | +| `--ios-only` | Run only the iOS native build (still runs Dart phase; also disables auto-scope) | +| `--android-only` | Run only the Android native build (still runs Dart phase; also disables auto-scope) | + +### Environment + +| Var | Default | Used for | +|:----------|:-------------------|:------------------------------------------------------| +| `FLAVOR` | `develop` | Flutter build flavor + entrypoint (`lib/main_$FLAVOR.dart`) | +| `BASE_REF`| auto-detected | Branch to diff against for auto-scoping | + +Example: `FLAVOR=staging ./.claude/skills/build-verify/scripts/verify.sh`. + +## What each phase does + +**Dart phase** — sequential, fail-fast (runs from the repo root): + +1. `fvm flutter pub get` (always — cheap and ensures deps are in sync). +2. `make gen` — unless `--skip-gen` or auto-skipped. Runs `flutter gen-l10n` and + `dart run build_runner build --delete-conflicting-outputs`. +3. `fvm flutter analyze`. +4. `fvm flutter test`. + +**Native builds** — both run in parallel after the Dart phase passes: + +- iOS: `fvm flutter build ios --no-codesign --flavor "$FLAVOR" -t "lib/main_$FLAVOR.dart"` +- Android: `fvm flutter build apk --debug --flavor "$FLAVOR" -t "lib/main_$FLAVOR.dart"` + +Both verify compilation on each platform; iOS skips codesigning so it doesn't need +provisioning profiles, and Android uses the debug variant so it doesn't need a release +keystore. + +**Format** — runs after native builds pass: `fvm dart format lib test`. This +auto-rewrites files; the script reports how many files changed so the user can review. + +## Output + +Each native track writes to its own log under a temp directory. On success, only a short +summary is printed. On failure, the last 150 lines of the failing track's log are printed +and the full log path is included for inspection. + +Report a concise summary to the user: +- Pub get / codegen: `[OK]` / `[SKIPPED]` +- Analyze: `[OK]` / `[FAIL]` +- Test: `[OK]` / `[FAIL]` +- iOS build: `[OK]` / `[FAIL]` / `[SKIPPED]` +- Android build: `[OK]` / `[FAIL]` / `[SKIPPED]` +- Format: `[OK]` (and how many files were auto-formatted, if any) + +Remind the user that **nothing has been committed** — they can now run `pr-review`, +review and commit manually, or invoke `create-pr` when ready. + +## Failure Handling + +If the script exits non-zero: +1. Read the printed log tail carefully; open the full log if needed. +2. Fix the underlying issue in the source code. Do NOT disable checks, skip tests, or + paper over the issue. +3. Re-run. If only one native track failed, you can re-run just that track with + `--ios-only` / `--android-only` to save time — but always do a full `verify.sh` run + before declaring done. + +If a step fails repeatedly (3+ attempts) and the fix is not obvious, stop and report the +failure to the user rather than continuing. + +## Rules + +- **Never commit.** Even if format auto-rewrites files, leave them uncommitted. +- **Never skip phases silently.** The script prints its auto-scope decision; include that + line in the summary you report to the user so they know what ran vs. what was skipped. + If you use explicit flags (`--ios-only` / `--android-only` / `--skip-gen` / + `--skip-builds` / `--full`), say so explicitly as well. +- **Trust the auto-scope default.** Don't reach for `--full` unless you actually need to + validate cross-platform or you've changed shared infra (e.g. `pubspec.yaml`, theming, + routing) the auto-scoper can't classify. +- **Root-cause fixes only.** Don't suppress warnings with `// ignore:` or `dynamic`, + and don't disable a test to make verification pass. +- **Use FVM.** All Flutter / Dart invocations go through `fvm` so the pinned SDK in + `.fvmrc` is used. The script checks for `fvm` and exits early if it isn't on `PATH`. diff --git a/ai/skills/build-verify/scripts/verify.sh b/ai/skills/build-verify/scripts/verify.sh new file mode 100755 index 0000000..fba555e --- /dev/null +++ b/ai/skills/build-verify/scripts/verify.sh @@ -0,0 +1,385 @@ +#!/bin/bash + +# Description: +# Build / test / analyze / format verification for this Flutter app. +# +# Sequence: +# 1. Dart phase (sequential, fail-fast): +# fvm flutter pub get +# make gen (unless --skip-gen or auto-skipped) +# fvm flutter analyze +# fvm flutter test +# 2. Native builds (parallel, after Dart phase passes): +# iOS: fvm flutter build ios --no-codesign --flavor "$FLAVOR" -t lib/main_$FLAVOR.dart +# Android: fvm flutter build apk --debug --flavor "$FLAVOR" -t lib/main_$FLAVOR.dart +# 3. Format (sequential, after native builds pass): +# fvm dart format lib test +# +# By default the script auto-scopes based on what changed (committed vs default branch + +# uncommitted): +# - All changes under ios/ only -> skip Android native build +# - All changes under android/ only -> skip iOS native build +# - All changes under test/ only -> skip both native builds +# - No annotation / pubspec / l10n changes -> skip `make gen` codegen +# - Mixed or no diff -> run everything +# +# Usage: +# ./verify.sh # Auto-scoped verify (default) +# ./verify.sh --full # Force-run everything (no auto-skip) +# ./verify.sh --skip-gen # Skip `make gen` codegen (explicit) +# ./verify.sh --skip-builds # Skip native iOS + Android builds +# ./verify.sh --ios-only # Only run the iOS native build +# ./verify.sh --android-only # Only run the Android native build +# +# Environment: +# FLAVOR default: develop build flavor + entrypoint (lib/main_$FLAVOR.dart) +# BASE_REF auto-detected branch to diff against for auto-scoping + +set -euo pipefail + +# Short-circuit --help / -h before doing anything else (so the help works even +# if fvm or git isn't installed yet). +for arg in "$@"; do + case "$arg" in + -h|--help) + sed -n '3,36p' "$0" + exit 0 + ;; + esac +done + +SKIP_GEN=0 +SKIP_BUILDS=0 +IOS_ONLY=0 +ANDROID_ONLY=0 +FULL=0 + +# Parse flags first so typos error with "Unknown flag" before we complain about +# missing prerequisites like fvm or git. +for arg in "$@"; do + case "$arg" in + --full) FULL=1 ;; + --skip-gen) SKIP_GEN=1 ;; + --skip-builds) SKIP_BUILDS=1 ;; + --ios-only) IOS_ONLY=1 ;; + --android-only) ANDROID_ONLY=1 ;; + -h|--help) ;; # handled above before prerequisites + *) + echo "Unknown flag: $arg" >&2 + exit 2 + ;; + esac +done + +if [ $IOS_ONLY -eq 1 ] && [ $ANDROID_ONLY -eq 1 ]; then + echo "ERROR: --ios-only and --android-only are mutually exclusive." >&2 + exit 2 +fi + +# --- Prerequisites ------------------------------------------------------- +if ! command -v git >/dev/null 2>&1; then + echo "ERROR: git not found on PATH." >&2 + exit 1 +fi +if ! command -v fvm >/dev/null 2>&1; then + echo "ERROR: fvm not found on PATH. Install it with: dart pub global activate fvm" >&2 + echo " (or see the project README / Makefile 'install' target.)" >&2 + exit 1 +fi + +REPO_ROOT="$(git rev-parse --show-toplevel)" +cd "$REPO_ROOT" + +detect_default_branch() { + local branch + branch="$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||' || true)" + if [ -n "$branch" ]; then + if git rev-parse --verify "$branch" >/dev/null 2>&1; then + echo "$branch" + return + fi + if git rev-parse --verify "origin/$branch" >/dev/null 2>&1; then + echo "origin/$branch" + return + fi + echo "$branch" + return + fi + if git rev-parse --verify main >/dev/null 2>&1; then + echo "main" + return + fi + if git rev-parse --verify origin/main >/dev/null 2>&1; then + echo "origin/main" + return + fi + if git rev-parse --verify master >/dev/null 2>&1; then + echo "master" + return + fi + if git rev-parse --verify origin/master >/dev/null 2>&1; then + echo "origin/master" + return + fi + echo "main" +} + +BASE_REF="${BASE_REF:-$(detect_default_branch)}" +FLAVOR="${FLAVOR:-develop}" + +# Sanity: flavor entrypoint exists. +if [ ! -f "$REPO_ROOT/lib/main_$FLAVOR.dart" ]; then + echo "ERROR: lib/main_$FLAVOR.dart not found. Set FLAVOR to one of: develop, staging, production." >&2 + exit 2 +fi + +# --- Auto-scope detection ------------------------------------------------ +# Runs unless --full or any explicit narrowing flag is set. +EXPLICIT_SCOPE=0 +if [ $IOS_ONLY -eq 1 ] || [ $ANDROID_ONLY -eq 1 ] || [ $SKIP_GEN -eq 1 ] || [ $SKIP_BUILDS -eq 1 ]; then + EXPLICIT_SCOPE=1 +fi + +AUTO_MSG="" +if [ $FULL -eq 0 ] && [ $EXPLICIT_SCOPE -eq 0 ]; then + # Collect changed paths: committed-on-branch vs base + uncommitted tracked + staged + untracked. + CHANGED="$( + { + git diff --name-only "$BASE_REF"...HEAD 2>/dev/null || true + git diff --name-only 2>/dev/null || true + git diff --cached --name-only 2>/dev/null || true + git ls-files --others --exclude-standard 2>/dev/null || true + } | sort -u + )" + + # Filter out tooling / doc / generated paths that don't affect builds. + RELEVANT="$(printf '%s\n' "$CHANGED" \ + | grep -Ev '^(\.claude/|ai/|docs/|\.github/|README|\.gitignore$|\.editorconfig$|\.fvmrc$|\.vscode/|\.idea/)' \ + | grep -Ev '\.(g|freezed|gr|gen|config)\.dart$' \ + | grep -Ev '^lib/assets/' \ + || true)" + + if [ -z "$RELEVANT" ]; then + AUTO_MSG="no build-relevant changes detected; running everything (use explicit flags to narrow)" + else + HAS_IOS=0 + HAS_ANDROID=0 + HAS_DART=0 + HAS_TEST=0 + HAS_NON_TEST=0 + HAS_CODEGEN_INPUT=0 + + while IFS= read -r path; do + [ -z "$path" ] && continue + case "$path" in + ios/*) HAS_IOS=1; HAS_NON_TEST=1 ;; + android/*) HAS_ANDROID=1; HAS_NON_TEST=1 ;; + test/*) HAS_TEST=1 ;; + lib/*) HAS_DART=1; HAS_NON_TEST=1 ;; + pubspec.yaml|pubspec.lock) HAS_DART=1; HAS_CODEGEN_INPUT=1; HAS_NON_TEST=1 ;; + assets/localization/*) HAS_CODEGEN_INPUT=1; HAS_NON_TEST=1 ;; + analysis_options.yaml) HAS_NON_TEST=1 ;; + *) HAS_NON_TEST=1 ;; + esac + # Any lib/*.dart edit (non-generated, filtered above) is a potential codegen input. + case "$path" in + lib/*.dart|lib/**/*.dart) HAS_CODEGEN_INPUT=1 ;; + esac + done <<< "$RELEVANT" + + # Test-only diff -> skip native builds. + if [ $HAS_TEST -eq 1 ] && [ $HAS_NON_TEST -eq 0 ]; then + SKIP_BUILDS=1 + AUTO_MSG="all changes are test-only; skipping native builds" + else + # Single-platform native changes -> skip the other platform's native build. + if [ $HAS_IOS -eq 1 ] && [ $HAS_ANDROID -eq 0 ] && [ $HAS_DART -eq 0 ]; then + IOS_ONLY=1 + AUTO_MSG="all changes are iOS-only; skipping Android native build" + elif [ $HAS_ANDROID -eq 1 ] && [ $HAS_IOS -eq 0 ] && [ $HAS_DART -eq 0 ]; then + ANDROID_ONLY=1 + AUTO_MSG="all changes are Android-only; skipping iOS native build" + fi + fi + + # No codegen inputs touched -> skip `make gen`. + if [ $HAS_CODEGEN_INPUT -eq 0 ]; then + SKIP_GEN=1 + if [ -n "$AUTO_MSG" ]; then + AUTO_MSG="$AUTO_MSG; no codegen inputs changed, skipping make gen" + else + AUTO_MSG="no codegen inputs changed, skipping make gen" + fi + fi + fi +fi + +LOG_DIR="$(mktemp -d -t build-verify-XXXXXX)" +DART_LOG="$LOG_DIR/dart.log" +IOS_LOG="$LOG_DIR/ios.log" +ANDROID_LOG="$LOG_DIR/android.log" +FMT_LOG="$LOG_DIR/format.log" + +echo "=== build-verify ===" +echo " flavor: $FLAVOR (entrypoint: lib/main_$FLAVOR.dart)" +echo " base: $BASE_REF" +if [ -n "$AUTO_MSG" ]; then + echo " auto-scope: $AUTO_MSG" +fi +echo " dart log: $DART_LOG" +if [ $SKIP_BUILDS -eq 0 ]; then + [ $ANDROID_ONLY -eq 0 ] && echo " iOS log: $IOS_LOG" + [ $IOS_ONLY -eq 0 ] && echo " Android log: $ANDROID_LOG" +fi +echo "" + +overall_start=$(date +%s) + +# --- Dart phase ---------------------------------------------------------- +dart_start=$(date +%s) +DART_EXIT=0 +GEN_STATUS="SKIPPED" +{ + set -e + echo "[dart] fvm flutter pub get" + fvm flutter pub get + + if [ $SKIP_GEN -eq 0 ]; then + echo "[dart] make gen" + if make -n gen >/dev/null 2>&1; then + make gen + else + echo " Makefile 'gen' target not found; falling back to inline codegen." + fvm flutter gen-l10n \ + --arb-dir "assets/localization" \ + --template-arb-file "app_en.arb" \ + --output-localization-file "app_localizations.gen.dart" \ + --output-dir "lib/assets" + fvm dart run build_runner build --delete-conflicting-outputs + fi + else + echo "[dart] make gen SKIPPED" + fi + + echo "[dart] fvm flutter analyze" + fvm flutter analyze + + echo "[dart] fvm flutter test" + fvm flutter test +} > "$DART_LOG" 2>&1 || DART_EXIT=$? +dart_done=$(date +%s) +dart_s=$(( dart_done - dart_start )) + +if [ $SKIP_GEN -eq 0 ]; then + GEN_STATUS="OK" +fi + +if [ $DART_EXIT -ne 0 ]; then + echo " [FAIL] Dart phase (${dart_s}s, exit $DART_EXIT)" + echo "" + echo "--- Dart log tail (last 150 lines) ---" + tail -n 150 "$DART_LOG" + echo "--- full Dart log: $DART_LOG ---" + exit 1 +fi +echo " [OK] Dart phase (${dart_s}s) (codegen: $GEN_STATUS)" +echo "" + +# --- Native builds (parallel) -------------------------------------------- +IOS_PID="" +ANDROID_PID="" +IOS_EXIT=0 +ANDROID_EXIT=0 +ios_done=$dart_done +android_done=$dart_done +native_start=$(date +%s) + +if [ $SKIP_BUILDS -eq 0 ]; then + if [ $ANDROID_ONLY -eq 0 ]; then + ( + set -e + echo "[iOS] fvm flutter build ios --no-codesign --flavor $FLAVOR" + fvm flutter build ios --no-codesign --flavor "$FLAVOR" -t "lib/main_$FLAVOR.dart" + ) > "$IOS_LOG" 2>&1 & + IOS_PID=$! + echo " iOS started (pid $IOS_PID)" + fi + + if [ $IOS_ONLY -eq 0 ]; then + ( + set -e + echo "[Android] fvm flutter build apk --debug --flavor $FLAVOR" + fvm flutter build apk --debug --flavor "$FLAVOR" -t "lib/main_$FLAVOR.dart" + ) > "$ANDROID_LOG" 2>&1 & + ANDROID_PID=$! + echo " Android started (pid $ANDROID_PID)" + fi + + if [ -n "$IOS_PID" ] || [ -n "$ANDROID_PID" ]; then + echo "" + fi + + if [ -n "$IOS_PID" ]; then + wait "$IOS_PID" || IOS_EXIT=$? + ios_done=$(date +%s) + fi + if [ -n "$ANDROID_PID" ]; then + wait "$ANDROID_PID" || ANDROID_EXIT=$? + android_done=$(date +%s) + fi + + ios_s=$(( ios_done - native_start )) + android_s=$(( android_done - native_start )) + + if [ -n "$IOS_PID" ]; then + if [ $IOS_EXIT -eq 0 ]; then + echo " [OK] iOS (${ios_s}s)" + else + echo " [FAIL] iOS (${ios_s}s, exit $IOS_EXIT)" + fi + fi + if [ -n "$ANDROID_PID" ]; then + if [ $ANDROID_EXIT -eq 0 ]; then + echo " [OK] Android (${android_s}s)" + else + echo " [FAIL] Android (${android_s}s, exit $ANDROID_EXIT)" + fi + fi + echo "" + + if [ $IOS_EXIT -ne 0 ] || [ $ANDROID_EXIT -ne 0 ]; then + if [ $IOS_EXIT -ne 0 ]; then + echo "--- iOS log tail (last 150 lines) ---" + tail -n 150 "$IOS_LOG" + echo "--- full iOS log: $IOS_LOG ---" + echo "" + fi + if [ $ANDROID_EXIT -ne 0 ]; then + echo "--- Android log tail (last 150 lines) ---" + tail -n 150 "$ANDROID_LOG" + echo "--- full Android log: $ANDROID_LOG ---" + echo "" + fi + exit 1 + fi +else + echo " Native builds SKIPPED" + echo "" +fi + +# --- Format -------------------------------------------------------------- +echo "=== Format ===" +before_fmt="$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')" +fvm dart format lib test 2>&1 | tee "$FMT_LOG" +after_fmt="$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')" +fmt_delta=$(( after_fmt - before_fmt )) +if [ "$fmt_delta" -gt 0 ]; then + echo " [OK] Format auto-rewrote files ($fmt_delta new entries in git status). Review before committing." +else + echo " [OK] Format produced no changes." +fi + +total_elapsed=$(( $(date +%s) - overall_start )) +echo "" +echo "build-verify completed successfully in ${total_elapsed}s." +echo "Nothing has been committed. Run pr-review or create-pr when ready." diff --git a/ai/skills/create-pr/SKILL.md b/ai/skills/create-pr/SKILL.md new file mode 100644 index 0000000..19c3f7c --- /dev/null +++ b/ai/skills/create-pr/SKILL.md @@ -0,0 +1,200 @@ +--- +name: create-pr +description: > + Create or update a GitHub PR for this Flutter repository using gh CLI. Verifies the work with + build-verify and pr-review, generates an inline PR description, commits pending changes when + approved, pushes, and opens or updates the PR. Supports stacked PRs by asking for the base + branch when detection is ambiguous. Use when the user says "create PR", "open PR", "push PR", + or wants to submit their work for review. +allowed-tools: Bash, Read, Write, Grep, Glob, Skill, Agent +user-invocable: true +model: claude-sonnet-4-6 +--- + +# Flutter Template Create Pull Request + +Create or update a GitHub PR for the current branch. This workflow may commit and push, so ask before changing branches, committing, or pushing unless the user's request already clearly authorizes those actions. + +## Read First +- `AGENTS.md` +- `docs/PROJECT_OVERVIEW.md` +- `docs/PROJECT_GUIDELINES.md` +- `git status` +- relevant task docs under `.claude/tasks/`, when present + +## Step 1: Collect PR Metadata + +If the user did not provide these when invoking the skill, ask before proceeding: + +1. **Type of work**: one of `chore`, `feat`, `fix`, `refactor` +2. **Ticket number**: e.g. `MOB-120`, or confirm that there is no ticket +3. **Short description**: plain-English summary for the commit and PR title + +## Step 2: Decide Branch And Base + +This repo may use stacked PRs. The PR base is the branch the current branch should merge into, which is not always the default branch. + +Try to detect the parent branch: + +```bash +git show-branch --all 2>/dev/null \ + | grep '\*' \ + | grep -v "$(git rev-parse --abbrev-ref HEAD)" \ + | head -1 \ + | sed 's/.*\[\(.*\)\].*/\1/' \ + | sed 's/[\^~].*//' +``` + +Alternative: use `git log --format=%D HEAD --decorate` and pick the nearest branch that is not `HEAD`. + +If detection fails or is ambiguous, ask the user which branch this PR should target. + +Ask whether to create a new branch or push the current branch unless the user already made that clear: + +> Should I create a new branch for these changes, or push to the current branch ``? +> The PR will target ``. + +If creating a new branch, ask for the branch name or derive one from `//`. + +## Step 3: Verify Build And Review + +Run the `build-verify` skill: + +```bash +.claude/skills/build-verify/scripts/verify.sh +``` + +It runs the Flutter verification suite for this repo: dependency sync, code generation when needed, analyzer, tests, iOS and Android native builds when in scope, and formatting. If it fails, fix the root cause and re-run before continuing. + +After build verification passes, run `pr-review uncommitted` if it has not already been run for the current diff. Address IMPORTANT findings before continuing. If addressing findings changes code, rerun `build-verify` before continuing to the commit step. + +## Step 4: Include Task Documentation + +Stage and commit relevant files under `.claude/tasks/` when they describe the implemented feature, including `prd.md`, `techspec.md`, `tasks.md`, and individual task files. These are part of the deliverable and should not be left untracked when they document the PR's work. + +If the implementation diverged from the original plan, update task docs only if the user or project workflow expects docs to reflect the final implementation. Do not rewrite PRD or tech spec casually during PR creation. + +## Step 5: Generate PR Description Inline + +Compose the PR body in memory and pass it directly to `gh`. Never write `pr_description.md` or any other temporary PR body file to disk. + +Analyze the changes against the confirmed base branch: + +```bash +git diff --stat ...HEAD +git log ..HEAD --oneline +``` + +Use this format when sections apply: + +```markdown +## New Features +- + +## Improvements +- + +## Refactor +- + +## Fixes +- + +## Chores +- + +## Screenshot +TODO +``` + +For small PRs, skip section headers and write 1-3 concise bullets plus `## Screenshot` when appropriate. + +Style: +- One sentence per bullet. +- High-level, not file-by-file. +- Light on jargon. Type names, file paths, provider names, generated route names, and DTO names belong in the diff, not the PR body. +- Keep it to roughly 3-6 bullets. +- Do not include test plans, checklists, screenshots, or architecture deep dives. + +## Step 6: Commit Pending Changes + +Run `git status` to check for uncommitted changes. If there are pending changes and the user approved committing, stage the intended files and create a commit. + +Commit message format: + +```text +(): +``` + +If there is no ticket: + +```text +: +``` + +Example: + +```text +feat(MOB-120): add profile detail screen +``` + +Add co-author trailers only when the project or user explicitly asks for them. + +## Step 7: Push Branch + +Push the current branch to remote when the user approved pushing: + +```bash +git push -u origin HEAD +``` + +## Step 8: Create Or Update PR + +Create the PR with the confirmed base branch: + +```bash +gh pr create --title "" --body "$(cat <<'EOF' +<pr body here> +EOF +)" --base "<base-branch>" --assignee @me +``` + +If a PR already exists for this branch, update it: + +```bash +gh pr edit --title "<title>" --body "$(cat <<'EOF' +<pr body here> +EOF +)" --base "<base-branch>" +``` + +Title format: + +```text +<type>: <ticket> <short description> +``` + +Example: + +```text +feat: MOB-120 add profile detail screen +``` + +If there is no ticket, omit it from the title. + +## Step 9: Report Result + +Output: +- PR URL +- base branch +- verification summary +- commit hash, if a commit was created +- push status + +## Rules + +- Use `fvm`, `make gen`, `build-verify`, and `pr-review`; do not run KMP, Gradle, Spotless, Detekt, Tuist, SwiftLint, or SwiftFormat checks from this workflow. +- Do not write a PR description file to disk. +- Do not hand-edit generated files to make verification pass. +- Do not omit `.claude/tasks/` docs when they describe the implemented feature. +- Do not push or create a PR if verification or IMPORTANT review findings remain unresolved, unless the user explicitly asks to publish a draft with known issues. diff --git a/ai/skills/implement-tasks-sequence/SKILL.md b/ai/skills/implement-tasks-sequence/SKILL.md new file mode 100644 index 0000000..c1670ab --- /dev/null +++ b/ai/skills/implement-tasks-sequence/SKILL.md @@ -0,0 +1,81 @@ +--- +name: implement-tasks-sequence +description: > + Orchestrates implementation of all tasks for a feature using an agent team. Respects task + dependencies, runs tasks in correct order, parallelizes independent tasks. Does NOT build, run + tests, or commit at any point — verification is delegated to the caller (typically `/start-job`, + which runs `build-verify` and `pr-review uncommitted` afterwards). + Use when the user says "implement all tasks", "run the task sequence", "implement the feature", + or wants to execute multiple tasks from a task list end-to-end. +allowed-tools: Bash, Read, Grep, Glob, Edit, Write, Agent +model: claude-sonnet-4-6 +--- + +# Implement Tasks Sequence + +Orchestrate the full implementation of a feature by executing all tasks from a task list using an +agent team. The flow runs uninterrupted — no per-task builds, no per-task tests, no commits, and +no final verification. Verification is the caller's responsibility (normally `/start-job`, which +runs `build-verify` and then `pr-review uncommitted` after this skill completes). + +## Step 1: Load the Task List + +Read `.claude/tasks/[feature-name]/tasks.md` to understand: +- All tasks and their phases +- The dependency graph +- Which tasks can run in parallel vs. which must be sequential + +## Step 2: Plan Execution Order + +Build an execution plan from the dependency graph: +1. Group tasks into **waves** — each wave contains tasks whose dependencies are all satisfied by prior waves. +2. Tasks within the same wave that have **no mutual dependencies** can be dispatched to agents **in parallel**. +3. Tasks that depend on a previous task must wait for it to complete. + +Briefly summarize the execution plan (wave count, parallel groups) and proceed — no approval needed. + +## Step 3: Execute Each Wave + +For each wave, dispatch tasks to agents: + +### Per-Task Agent Instructions +Each agent receives: +- The task file (`.claude/tasks/[feature-name]/[num]_task.md`) +- The PRD (`.claude/tasks/[feature-name]/prd.md`) +- The Tech Spec (`.claude/tasks/[feature-name]/techspec.md`) +- Instructions to follow the `/implement` skill workflow for coding conventions and applicable + skills — **BUT skip all build, test, lint, and commit steps**. Only source code changes should + be made. Verification is centralized at the end of the sequence. + +Explicitly tell each agent: +> Do NOT run builds, do NOT run tests, do NOT run lint-format, do NOT commit. Only write the code +> changes for your assigned task. Verification and commit decisions happen at the end of the +> overall flow. + +### Wave Completion Gate +A wave is complete when all tasks in the wave have finished writing their code changes. Since there +is no per-task verification, the gate is just task completion. Do not start the next wave until the +current wave's agents have all returned. + +## Step 4: Report Results + +Provide a concise summary: +- Which tasks were implemented (list, with a one-line description each) +- Any tasks that could not complete (and why) +- Reminder: nothing has been committed, nothing has been verified — that is the caller's + responsibility. When invoked by `/start-job`, `build-verify` runs next, followed by + `pr-review uncommitted`. + +## Important Rules + +- **No per-task verification.** Do not run builds, tests, or lint between tasks. This slows the + flow without catching anything the final pass wouldn't catch. +- **No per-task commits.** Everything stays uncommitted until the user reviews and commits. +- **Respect dependencies** — never start a task before its dependencies are done. +- **Parallelize when safe** — tasks in the same wave with no mutual dependencies should run as + parallel agents. +- **Use worktree isolation** — when running parallel agents, use `isolation: "worktree"` to avoid + file conflicts. Merge changes back after each wave. +- **Stop on hard failure** — if an agent reports it cannot complete its task (e.g. missing + context, conflicting changes), stop and surface to the user rather than continuing with a broken + base. diff --git a/ai/skills/implement/SKILL.md b/ai/skills/implement/SKILL.md new file mode 100644 index 0000000..8dfcf31 --- /dev/null +++ b/ai/skills/implement/SKILL.md @@ -0,0 +1,125 @@ +--- +name: implement +description: > + Implement a single Flutter task following this repository's Riverpod, Freezed, AutoRoute, + DTO/entity, codegen, and verification conventions. Reads the task definition, PRD, and + tech spec, then executes the implementation. When invoked standalone, verifies the change; + when invoked by implement-tasks-sequence, writes code only and leaves verification to + start-job/build-verify. + Use when the user says "implement task X", "work on task X", or wants to execute + a specific task from the task list. +allowed-tools: Bash, Read, Grep, Glob, Edit, Write, Agent +model: claude-sonnet-4-6 +--- + +# Flutter Template Task Implementation + +You are responsible for implementing one task from a Flutter feature plan while following the repository standards. + +## Objectives +1. Read and understand the task definition +2. Review the PRD and tech spec for context +3. Apply relevant Flutter skills and repository conventions +4. Execute the implementation +5. Verify the change when running standalone, or explicitly skip verification when called by `implement-tasks-sequence` + +## File Locations +- PRD: `.claude/tasks/[feature-name]/prd.md` +- Tech Spec: `.claude/tasks/[feature-name]/techspec.md` +- Task: `.claude/tasks/[feature-name]/[num]_task.md` +- Task list: `.claude/tasks/[feature-name]/tasks.md` + +## Applicable Skills +- `feature-screen` — when the task adds or changes a screen, route, page split, UI state, or navigation. +- `feature-data-flow` — when the task adds backend/storage data flow, DTOs, entities, use cases, or state that loads real data. +- `lint-format` — when running standalone and the change does not need the broader `build-verify` suite. +- `build-verify` — when running standalone and the task changed behavior, generated-code inputs, routes, platform setup, dependencies, tests, or other shared behavior. +- `pr-review` — optional standalone final check when the user asks for a review after implementation. + +Do not use KMP, Swift, iOS coordinator, Gradle, Spotless, Detekt, Tuist, or native iOS test-runner skills in this Flutter workflow. + +## Invocation Modes + +### Standalone mode +Use when the user directly asks to implement one task. Complete implementation and run the appropriate verification commands before reporting done. + +### Sequence mode +Use when called by `implement-tasks-sequence`. In this mode: +- read the same task, PRD, and tech spec +- write only the source changes for the assigned task +- do not run builds, tests, `lint-format`, `build-verify`, or `pr-review` +- do not commit or stage +- report what changed and return control to the orchestrator + +## Workflow + +### Step 1: Pre-Task Setup + +Read the task file, PRD, and tech spec. Understand: +- What this task should accomplish +- How it fits into the broader feature +- Dependencies on prior tasks (verify they are complete) +- Whether this task is part of a currently running sequence or standalone + +### Step 2: Task Analysis + +Identify: +- Which files under `lib/features/<feature>/`, `lib/common/`, `lib/core/`, `assets/localization/`, platform folders, or tests need to be created or modified +- Whether the task is UI-only, stateful, data-backed, navigation-related, platform/setup-related, or test-only +- Which generated-code inputs are affected: `@riverpod`, `@freezed`, `@RoutePage`, DTO JSON serialization, localization, or assets +- The testing and verification strategy for standalone mode + +### Step 3: Implementation Plan + +Before writing code, briefly outline the approach. For non-trivial standalone tasks, share the plan with the user if the user asked to review the approach first. When called by `implement-tasks-sequence`, keep the plan internal and proceed. + +### Step 4: Execute Implementation + +Write the code following `AGENTS.md`, `docs/PROJECT_OVERVIEW.md`, `docs/PROJECT_GUIDELINES.md`, and the relevant feature skills. + +Use these default patterns: +- Put feature route widgets in `lib/features/<feature>/<feature>_page.dart`. +- Put larger widget trees in `lib/features/<feature>/<feature>_page_content.dart`. +- Use `*_state.dart` with `freezed` and `@riverpod` when the feature owns async or mutable state. +- Use `*_event.dart` with `EventNotifier` for one-off effects such as navigation, dialogs, or snackbars. +- Keep IO in `lib/common/usecase/`; do not wire network or storage directly in widgets. +- Keep transport models in `lib/common/data/dto/` and app-facing models in `lib/common/data/entity/`. +- Register routes in `lib/app/navigation/app_router.dart` when adding `@RoutePage()` widgets. +- Use shared widgets from `lib/common/component/` and `lib/common/composition/` before adding new primitives. +- Use `context.colorScheme`, `context.textTheme`, and `context.locale`. +- Add localization strings to `assets/localization/*.arb` and use generated localization accessors. +- Do not hand-edit generated files such as `*.g.dart`, `*.freezed.dart`, `*.gr.dart`, or `lib/assets/**`. +- Check `lib/app/setup/setup_app.dart` before assuming Firebase, notifications, or Remote Config startup behavior is active. + +**Critical: no workarounds.** Implement root-cause solutions. If you hit a blocker, investigate the cause rather than suppressing warnings, bypassing architecture, editing generated output, or adding temporary shims. + +### Step 5: Testing & Verification (Mandatory) + +In standalone mode, verify before considering the task complete. + +Use the smallest sufficient verification: +- Run `make gen` when annotations, routes, DTOs, localization, or asset inputs changed. +- Run `ai/skills/lint_format/scripts/lint_format.sh` for normal Dart/Flutter code changes. +- Run `fvm flutter test` when behavior, state, use cases, widgets, or tests changed. +- Run `ai/skills/build-verify/scripts/verify.sh` for broad, cross-platform, dependency, startup, routing, generated-code, or PR-ready tasks. +- Run `make integration_test` only when Patrol integration flows changed or the user asks for it. + +If any step fails, fix the underlying issue and re-run the failed verification. Do not disable checks, delete tests, add broad `// ignore:` comments, or hand-edit generated files to make verification pass. + +In sequence mode, skip this step and explicitly state that final verification is delegated to `build-verify`. + +### Step 6: Mark Task Complete + +Update the matching task checkbox in `.claude/tasks/[feature-name]/tasks.md` to `[x]` only after the task's source changes are complete. + +If the task cannot be completed, leave the checkbox unchecked and report the blocker clearly. + +## Rules + +- Do not edit the PRD or tech spec unless the user explicitly asks for spec updates. +- Do not stage, commit, or push. +- Do not touch files outside the task scope unless the task cannot work without that change. +- Preserve unrelated user or agent changes in the worktree. +- Prefer existing repo patterns over new abstractions. +- Add or update tests when the task changes behavior, state, validation, data mapping, or user-facing flows. +- Report what was implemented, which files changed, verification run or intentionally skipped, and any decisions or blockers. diff --git a/ai/skills/lint_format/SKILL.md b/ai/skills/lint_format/SKILL.md new file mode 100644 index 0000000..4ca9ae8 --- /dev/null +++ b/ai/skills/lint_format/SKILL.md @@ -0,0 +1,78 @@ +--- +name: lint-format +description: > + Run Flutter/Dart formatting and static analysis for this repository. Use after completing Dart, + Flutter, generated-source-input, or project configuration changes; when the user asks to lint, + format, analyze, or check code style; or when preparing code for a pull request. +allowed-tools: Bash, Read, Grep, Glob +model: claude-sonnet-4-6 +--- + +# Flutter Template Lint and Format + +## MANDATORY +Run this skill after completing Flutter/Dart code changes unless a broader verification skill already ran equivalent checks. Never declare code work complete with known formatting or analyzer failures. + +## Read First +- `AGENTS.md` +- `docs/PROJECT_GUIDELINES.md` +- `analysis_options.yaml` +- `pubspec.yaml` + +## Usage + +Run the wrapper script from the repo root: + +```bash +ai/skills/lint_format/scripts/lint_format.sh +``` + +The script auto-detects whether Flutter-relevant files changed. When relevant files changed, it formats changed Dart files and runs a project-wide analyzer pass. + +Claude-discovered path: + +```bash +.claude/skills/lint-format/scripts/lint_format.sh +``` + +## Flags + +| Flag | What it does | +|:--|:--| +| `all` or `--all` | Format standard Dart source directories even if no changed files are detected, then analyze. | +| `--check` | Check formatting without writing changes, then analyze. | +| `--format-only` | Run only `fvm dart format`. | +| `--analyze-only` | Run only `fvm flutter analyze`. | +| `--help` | Show script usage. | + +## What It Runs + +| Step | Command | +|:--|:--| +| Format | `fvm dart format <changed Dart files>` | +| Format check | `fvm dart format --set-exit-if-changed <changed Dart files>` | +| Analyze | `fvm flutter analyze` | + +The default formatter target is changed non-generated Dart files. It skips generated outputs such as `*.g.dart`, `*.freezed.dart`, `*.gr.dart`, and `lib/assets/**`. + +If changed annotations, routes, DTOs, localization, or asset inputs require generated files, run `make gen` before this skill so the analyzer sees the current generated code. + +## Feedback Loop + +1. Run the script. +2. If formatting changed files, inspect the diff. +3. If analyzer failures appear, fix the underlying source issue. +4. Run `make gen` when the failure points to stale generated code. +5. Re-run the script until all checks pass. +6. Only then declare work complete. + +## Prerequisites +- FVM installed and configured for the repo. +- Dependencies fetched with `fvm flutter pub get`. +- Generated files are current when the change touched codegen inputs. + +## Rules +- Prefer `fvm dart format` and `fvm flutter analyze` over global Dart or Flutter commands. +- Do not hand-edit generated files to satisfy the analyzer. +- Do not run platform-native Swift, Gradle, Spotless, Detekt, or KMP checks from this skill. +- Do not stage or commit formatting changes automatically. diff --git a/ai/skills/lint_format/scripts/lint_format.sh b/ai/skills/lint_format/scripts/lint_format.sh new file mode 100755 index 0000000..221ab74 --- /dev/null +++ b/ai/skills/lint_format/scripts/lint_format.sh @@ -0,0 +1,193 @@ +#!/usr/bin/env bash + +# Runs Flutter/Dart format and analyzer checks for this repository. +# +# Usage: +# ./lint_format.sh # Auto-detect changed Flutter-relevant files +# ./lint_format.sh all # Format standard Dart source directories, then analyze +# ./lint_format.sh --check # Check formatting without writing changes, then analyze +# ./lint_format.sh --format-only # Run only dart format +# ./lint_format.sh --analyze-only # Run only flutter analyze + +set -euo pipefail + +usage() { + cat <<'EOF' +Usage: lint_format.sh [auto|all|--all] [--check] [--format-only|--analyze-only] + +Default auto mode: + - formats changed non-generated Dart files + - runs fvm flutter analyze when Flutter-relevant files changed + +Flags: + all, --all Format standard Dart source directories, then analyze + --check Check formatting without writing changes + --format-only Run only fvm dart format + --analyze-only Run only fvm flutter analyze + --help Show this help +EOF +} + +REPO_ROOT="$(git rev-parse --show-toplevel)" +cd "$REPO_ROOT" + +mode="auto" +check_format=false +run_format=true +run_analyze=true + +for arg in "$@"; do + case "$arg" in + auto) + mode="auto" + ;; + all|--all) + mode="all" + ;; + --check) + check_format=true + ;; + --format-only) + run_analyze=false + ;; + --analyze-only) + run_format=false + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "Unknown argument: $arg" + usage + exit 1 + ;; + esac +done + +if ! command -v fvm >/dev/null 2>&1; then + echo "fvm not found. Install FVM or make sure it is available on PATH." + exit 1 +fi + +is_generated_dart() { + local file="$1" + [[ "$file" == *.g.dart ]] || + [[ "$file" == *.freezed.dart ]] || + [[ "$file" == *.gr.dart ]] || + [[ "$file" == lib/assets/* ]] +} + +is_flutter_relevant() { + local file="$1" + [[ "$file" == *.dart ]] || + [[ "$file" == pubspec.yaml ]] || + [[ "$file" == pubspec.lock ]] || + [[ "$file" == analysis_options.yaml ]] || + [[ "$file" == build.yaml ]] || + [[ "$file" == assets/localization/* ]] || + [[ "$file" == lib/* ]] || + [[ "$file" == test/* ]] || + [[ "$file" == integration_test/* ]] +} + +collect_changed_files() { + { + git diff --name-only HEAD 2>/dev/null || git diff --name-only 2>/dev/null || true + git diff --cached --name-only 2>/dev/null || true + git ls-files --others --exclude-standard 2>/dev/null || true + } | sort -u +} + +changed_files="$(collect_changed_files)" +has_flutter_changes=false + +while IFS= read -r file; do + if [[ -n "$file" ]] && is_flutter_relevant "$file"; then + has_flutter_changes=true + break + fi +done <<< "$changed_files" + +if [[ "$mode" == "auto" && "$has_flutter_changes" == false ]]; then + echo "No Flutter/Dart-relevant changes detected. Nothing to lint or format." + exit 0 +fi + +format_targets=() + +if [[ "$mode" == "all" ]]; then + for dir in lib test integration_test; do + if [[ -d "$dir" ]]; then + format_targets+=("$dir") + fi + done +else + while IFS= read -r file; do + if [[ -z "$file" || "$file" != *.dart || ! -f "$file" ]]; then + continue + fi + if is_generated_dart "$file"; then + continue + fi + format_targets+=("$file") + done <<< "$changed_files" +fi + +format_failed=false +analyze_failed=false + +if [[ "$run_format" == true ]]; then + echo "=== Dart format ===" + if [[ "${#format_targets[@]}" -eq 0 ]]; then + echo "No changed non-generated Dart files to format." + else + format_cmd=(fvm dart format) + if [[ "$check_format" == true ]]; then + format_cmd+=(--set-exit-if-changed) + fi + format_cmd+=("${format_targets[@]}") + + if "${format_cmd[@]}"; then + echo "Dart format: PASSED" + else + echo "Dart format: FAILED" + format_failed=true + fi + fi +fi + +if [[ "$run_analyze" == true ]]; then + echo "" + echo "=== Flutter analyze ===" + if fvm flutter analyze; then + echo "Flutter analyze: PASSED" + else + echo "Flutter analyze: FAILED" + analyze_failed=true + fi +fi + +echo "" +echo "=== Summary ===" +if [[ "$run_format" == true ]]; then + if [[ "$format_failed" == true ]]; then + echo "Dart format: FAILED" + else + echo "Dart format: PASSED" + fi +fi +if [[ "$run_analyze" == true ]]; then + if [[ "$analyze_failed" == true ]]; then + echo "Flutter analyze: FAILED" + else + echo "Flutter analyze: PASSED" + fi +fi + +if [[ "$format_failed" == true || "$analyze_failed" == true ]]; then + exit 1 +fi + +echo "" +echo "All checks passed." diff --git a/ai/skills/prd/SKILL.md b/ai/skills/prd/SKILL.md new file mode 100644 index 0000000..1d0eeef --- /dev/null +++ b/ai/skills/prd/SKILL.md @@ -0,0 +1,106 @@ +--- +name: prd +description: > + Create a Flutter feature Product Requirements Document through a structured + clarify-plan-draft workflow. Outputs a PRD using the repository template under + `.claude/tasks/<feature-name>/prd.md`. Use when the user says "create a PRD", + "write requirements", "define the feature", "start a feature spec", or wants to + specify a feature before techspec/tasks/start-job. +allowed-tools: Bash, Read, Grep, Glob, Write, Edit +model: claude-opus-4-7 +--- + +# Flutter Template PRD Creation + +You are a PRD creation specialist focused on producing clear, actionable product requirements for this Flutter template. + +## Objectives +1. Capture complete, clear, and testable requirements +2. Separate product behavior from implementation design +3. Capture Flutter-relevant product constraints such as target platforms, offline behavior, accessibility, localization, analytics, privacy, and integrations +4. Generate a PRD using the standardized template + +## Template Reference +- Template: `ai/templates/prd.md` (also reachable as `.claude/templates/prd.md`) +- Output: `.claude/tasks/[feature-name]/prd.md` + +## Read First +- `AGENTS.md` +- `docs/PROJECT_OVERVIEW.md` +- `docs/PROJECT_GUIDELINES.md` +- `ai/templates/prd.md` +- any user-provided brief, ticket, design, API notes, or KMP/source-platform reference material + +## Scope Boundary +A PRD describes **what** the feature should do and **why** it matters. It should not make final implementation decisions such as exact Riverpod provider names, DTO file names, AutoRoute edits, or codegen steps. Those belong in `techspec`. + +It is still useful to capture high-level constraints that affect implementation, such as: +- target Flutter platforms: Android, iOS, web, macOS, Windows, Linux +- required backend, Firebase, notification, analytics, or native integrations +- offline or poor-connectivity expectations +- accessibility, text scaling, contrast, and localization requirements +- data sensitivity, consent, PII, storage, or security expectations +- KMP-to-Flutter migration parity requirements when the PRD is based on an existing source feature + +## Workflow + +### Step 1: Clarify (Mandatory) + +Before writing anything, ask the user targeted questions about: +- The problem being solved and who it affects +- Core functionality and expected behavior +- Target platforms and any platform-specific behavior +- UX expectations, accessibility, and localization scope +- Backend/API/Firebase/notification/analytics dependencies +- Data sensitivity, privacy, and storage expectations +- Offline support, sync, loading, empty, and error states +- Migration parity if this is being converted from KMP or another source implementation +- Scope boundaries: what is explicitly out of scope + +Do not proceed until you have enough clarity to draft a complete PRD. + +### Step 2: Plan (Mandatory) + +Summarize back to the user: +- Your understanding of the feature +- A product-level plan at a high level +- Target users and primary flows +- Scope and out-of-scope boundaries +- Flutter/platform constraints that should be captured +- Assumptions you are making + +Get explicit confirmation before drafting. + +### Step 3: Draft the PRD (Mandatory) + +Read the template at `ai/templates/prd.md` and use it to draft the PRD. +- Focus on **WHAT** and **WHY**, not implementation details. +- Keep requirements testable and unambiguous. +- Reference domain entities from existing project docs, user input, or migration material where relevant. +- Include measurable acceptance criteria through objectives, user stories, and functional requirements. +- Include target platforms and non-functional constraints in "High-Level Technical Constraints". +- Keep open questions explicit rather than guessing product decisions. + +### Step 4: Create Directory and Save + +```bash +mkdir -p .claude/tasks/[feature-name] +``` + +Save the PRD to `.claude/tasks/[feature-name]/prd.md`. + +Choose a stable kebab-case feature folder name, for example `profile-detail`, `event-check-in`, or `push-notification-settings`. If a matching task folder already exists, ask before overwriting an existing PRD. + +### Step 5: Report Results + +- Confirm the file path +- Summarize key decisions and scope +- List open questions, if any remain +- Suggest next step: run `/techspec [feature-name]` to create the technical specification + +## Rules +- Do not edit `techspec.md`, `tasks.md`, or task files from this skill. +- Do not start `/techspec`, `/tasks`, or `/start-job` automatically. +- Do not over-specify implementation details; leave architecture to `techspec`. +- Do not use KMP, Android-native, or iOS-native architecture terms as requirements unless the user explicitly needs migration parity. Translate source behavior into Flutter product behavior. +- Preserve unrelated files and existing task folders. diff --git a/ai/skills/review-pr-comments/SKILL.md b/ai/skills/review-pr-comments/SKILL.md new file mode 100644 index 0000000..777ec5e --- /dev/null +++ b/ai/skills/review-pr-comments/SKILL.md @@ -0,0 +1,204 @@ +--- +name: review-pr-comments +description: > + Review and resolve PR review comments on the current branch's PR in this Flutter repository, + from both AI reviewers (CodeRabbit, CodiumAI, CodePilot, Copilot, etc.) and human reviewers. + Fetches comments via `gh`, splits them into AI and human groups, verifies each comment against + the actual Flutter code, triages them, proposes fixes, and optionally applies fixes, replies to + comments, and pushes. + Use when the user asks to review PR comments, resolve PR feedback, review AI comments, review + human review comments, or handle code review feedback. +allowed-tools: Agent, Bash, Read, Edit, Write, Grep, Glob +model: claude-sonnet-4-6 +--- + +# Flutter Template Review PR Comments + +Handle review feedback on the current PR from both automated AI reviewers and human reviewers. Results are always presented split into **AI** and **Human** sections so the user can read them separately. + +## Read First +- `AGENTS.md` +- `docs/PROJECT_OVERVIEW.md` +- `docs/PROJECT_GUIDELINES.md` +- the files referenced by PR comments +- nearby source files when a comment depends on local context + +## Preconditions +- The GitHub CLI `gh` must be installed and authenticated. +- The current branch must have an open PR. +- Do not apply fixes, reply to comments, commit, or push until the user approves those actions. + +## Step 1: Find the PR + +```bash +gh pr list --head "$(git branch --show-current)" --json number,url --jq '.[0]' +``` + +If no PR is found, inform the user and stop. If `gh` is not available or not authenticated, report the blocker and the command that failed. + +## Step 2: Fetch All Review Comments + +Extract the owner/repo from `gh repo view --json nameWithOwner --jq '.nameWithOwner'`. + +Fetch all PR review comments, including inline comments on code: + +```bash +gh api repos/{owner}/{repo}/pulls/{number}/comments --paginate \ + --jq '.[] | {id: .id, user: .user.login, user_type: .user.type, path: .path, line: .line, original_line: .original_line, diff_hunk: .diff_hunk, body: .body}' +``` + +Also fetch top-level issue-style comments on the PR (some reviewers use these): + +```bash +gh api repos/{owner}/{repo}/issues/{number}/comments --paginate \ + --jq '.[] | {id: .id, user: .user.login, user_type: .user.type, body: .body}' +``` + +Optionally fetch the PR review summaries if the user asks for every review artifact: + +```bash +gh api repos/{owner}/{repo}/pulls/{number}/reviews --paginate \ + --jq '.[] | {id: .id, user: .user.login, user_type: .user.type, state: .state, body: .body}' +``` + +## Step 3: Classify Each Comment — AI vs Human + +Split every comment into one of two buckets: + +- **AI** — the author login matches a known bot pattern (case-insensitive): + `coderabbit`, `codiumai`, `codepilot`, `copilot`, `sonarcloud`, `deepsource`, `sourcery` + OR the GitHub `user.type` is `Bot`. +- **Human** — everything else. + +Group comments by reviewer within each bucket (so the user sees "CodeRabbit: 3", "Alice: 2", etc). + +If both buckets are empty, inform the user and stop. + +## Step 4: Triage Each Comment + +For each comment (in both buckets): +1. Read the referenced file and line range to understand the actual code. +2. Read surrounding Flutter template context when needed, especially providers, use cases, route registration, DTO/entity mapping, localization, and generated source inputs. +3. Determine if the issue described actually exists in the current branch. +4. Classify as one of: + - **Must-Fix**: compile/analyze errors, runtime crashes, broken navigation, data loss, security issues, secrets exposure, invalid generated-code assumptions, or release/build breakage. + - **Should-Fix**: real bugs, incorrect Riverpod lifecycle handling, bad async/ref usage, DTO/entity mapping mistakes, localization/assets/codegen issues, test failures, or logic errors that affect correctness. + - **Nice-to-Have**: valid but low-impact suggestions such as naming, readability, small UI polish, or minor refactors that are not required for correctness. + - **Irrelevant**: false positive, already handled, obsolete/outdated diff context, generated file comment where the source is correct, or not applicable to this Flutter template. + +Human comments deserve more deference than AI comments. If a human raised a concern you do not fully understand, surface it to the user rather than classifying it as Irrelevant. + +When comments mention source-platform concepts from KMP, Android, or iOS migration work, translate the concern into Flutter terms before deciding. For example, check the destination feature state, use case, route, or widget behavior rather than preserving Kotlin/Swift architecture literally. + +## Flutter-Specific Checks +Use these checks when comments touch related code: + +- Feature files should follow the repo pattern: `*_page.dart`, `*_page_content.dart`, `*_state.dart`, and `*_event.dart` when state/events are needed. +- Route widgets should use `@RoutePage()` and be registered in `lib/app/navigation/app_router.dart`; generated route files should not be hand-edited. +- Riverpod notifiers should keep IO in use cases, guard page-scoped async follow-up with `ref.mounted`, and use `keepAlive` only for app-scoped state or deliberate async lifetimes. +- DTOs belong in `lib/common/data/dto/`, entities in `lib/common/data/entity/`, and UI should not consume transport models directly. +- Shared UI should prefer `lib/common/component/`, `lib/common/composition/`, `context.colorScheme`, `context.textTheme`, and `context.locale`. +- Localization changes belong in `assets/localization/*.arb` and require generated accessors under `lib/assets/`. +- Generated files such as `*.g.dart`, `*.freezed.dart`, `*.gr.dart`, and `lib/assets/**` should be fixed through their source inputs and `make gen`. +- Firebase, notifications, Remote Config, and startup comments must be checked against `lib/app/setup/setup_app.dart` because some template hooks are scaffolded or disabled. +- Secrets and decrypted environment files should not be modified unless the review comment is explicitly about secrets setup. + +## Step 5: Present Findings (Split by AI / Human) + +Present results in two clearly labeled sections. Within each, group by severity. + +```text +### AI Reviewer Comments +Reviewers: CodeRabbit (3), Copilot (1) + +#### Must-Fix +... + +#### Should-Fix +... + +#### Nice-to-Have +... + +#### Irrelevant +... + +--- + +### Human Reviewer Comments +Reviewers: @alice (2), @bob (1) + +#### Must-Fix +... + +#### Should-Fix +... + +#### Nice-to-Have +... + +#### Irrelevant +... +``` + +Each row or bullet includes: +- comment id or stable number from the fetched list +- reviewer login +- file and line when available +- issue summary +- classification +- proposed fix for relevant comments +- reason when classified as Irrelevant + +Wait for user confirmation before applying any fixes. The user may respond with per-comment decisions: +- **fix**: apply the proposed fix +- **skip**: leave as-is, no reply needed unless the user asks +- **defer**: reply with a short explanation of why it is deferred +- **reply**: answer the comment without code changes +- **ignore**: for AI comments only; use the reviewer-specific ignore command only when supported, such as `@coderabbitai ignore` for CodeRabbit + +Do not use AI ignore commands for human comments. + +## Step 6: Apply Fixes (After User Approval) + +1. Make only the code changes approved by the user. +2. Keep changes scoped to the commented files and the directly required source inputs. +3. If a generated file would need edits, change the annotated/source file and run `make gen`. +4. Verify the relevant Flutter checks: + - run `make gen` when annotations, routes, DTOs, localization, or assets changed + - run `fvm flutter analyze` + - run `fvm flutter test` when behavior, widgets, state, use cases, or tests changed + - run `make integration_test` only when Patrol integration flows changed or the user asks for it +5. Commit changes only if the user explicitly approved a commit. +6. Reply to each comment on the PR based on the user's decision: + - **Fixed** comments: brief description of what was done. + - **Deferred** comments: explanation of why. + - **Irrelevant / not applicable** comments: explanation of why it is not applicable. + - **Ignored** AI comments: reviewer-specific ignore command when supported. + +For inline PR review comments, reply with: + +```bash +gh api repos/{owner}/{repo}/pulls/{number}/comments/{comment_id}/replies \ + -f body="<reply message>" +``` + +For top-level issue comments or review summaries, use a normal PR comment when a direct reply endpoint is not available: + +```bash +gh pr comment {number} --body "<reply message>" +``` + +7. Push changes only if the user explicitly approved a push. + +## Rules + +- Always verify comments against the actual code before accepting them. +- Never blindly apply AI-suggested fixes; they may be wrong or incomplete. +- Give human reviewers' concerns more weight. When uncertain, ask the user rather than dismissing. +- Present findings split by AI / Human before making any changes. +- Do not edit generated files directly. Fix the source and regenerate. +- Do not touch files outside the approved PR-comment scope unless necessary for the approved fix. +- Do not stage, commit, push, or reply to PR comments without user approval. +- Do not preserve KMP, Android, or iOS architecture terms in Flutter code unless the Flutter project already has the equivalent abstraction. +- Leave clear notes for comments that cannot be resolved mechanically or require product/design judgment. diff --git a/ai/skills/start-job/SKILL.md b/ai/skills/start-job/SKILL.md new file mode 100644 index 0000000..5e72133 --- /dev/null +++ b/ai/skills/start-job/SKILL.md @@ -0,0 +1,92 @@ +--- +name: start-job +description: > + Top-level orchestrator for Flutter feature implementation. Runs the full uninterrupted pipeline: + tasks → implement-tasks-sequence → build-verify → pr-review uncommitted. Use after a PRD + and tech spec are complete. Trigger phrases: "start job", "start the job", + "run the full pipeline", "do it all", "implement the feature end-to-end". +allowed-tools: Bash, Read, Grep, Glob, Edit, Write, Agent, Skill +user-invocable: true +model: claude-sonnet-4-6 +--- + +# Flutter Template Start Job + +Single entry point that runs the post-spec Flutter implementation pipeline. It is designed to be invoked once, with no user input between phases, so the feature goes from "spec approved" to "verified, uncommitted implementation" in one shot. + +Use this only after the PRD and tech spec are finished. If another agent or developer is still editing the tech spec, do not start implementation yet. + +## Prerequisites + +- PRD exists at `.claude/tasks/[feature-name]/prd.md` +- Tech Spec exists at `.claude/tasks/[feature-name]/techspec.md` +- The tech spec is complete and no other agent is actively editing it. +- The current working tree does not contain unresolved conflicts in `.claude/tasks/[feature-name]/`. + +If the PRD or techspec is missing, stop and ask the user to run `/prd` and/or `/techspec` +first. If the tech spec appears to be in progress, stop and ask the user to confirm it is ready. + +## Pipeline + +Run each phase in order. Do NOT ask for user approval between phases. Do NOT commit anything +at any point. If a phase fails hard (cannot proceed), stop and surface to the user. + +> **Critical orchestration rule:** when a sub-skill returns control, do not treat its output +> as the end of your turn. You are still inside this `/start-job` orchestrator. Immediately +> invoke the next phase's skill in the same response. Do not stop, do not summarize, do not +> pause for user input between phases. The only valid stops are: (a) hard failure, (b) the +> Final Report after Phase 4. + +### Phase 1 — Task Breakdown + +Invoke the `tasks` skill. It generates `tasks.md` and individual task files under +`.claude/tasks/[feature-name]/`. No approval prompt. + +**After `tasks` returns: do not stop, do not wait for input, do not summarize. Immediately +invoke `implement-tasks-sequence` (Phase 2) in the same response.** + +### Phase 2 — Implementation + +Invoke the `implement-tasks-sequence` skill. It executes all generated tasks in dependency +order, parallelizing when safe. No per-task builds, tests, or commits — agents only write +code changes. + +**After `implement-tasks-sequence` returns: immediately invoke `build-verify` (Phase 3).** + +### Phase 3 — Build & Test Verification + +Invoke the `build-verify` skill. It runs the Flutter verification suite for this repo: dependency sync, code generation when needed, analyzer, tests, iOS and Android native builds when in scope, and formatting. Fix any failures it surfaces with root-cause changes until everything is green. + +**After `build-verify` returns: immediately invoke `pr-review uncommitted` (Phase 4).** + +### Phase 4 — Standards Review + +Invoke the `pr-review uncommitted` skill. It reviews the actual diff against Flutter template standards after the build/test/analyze gate has passed. Fix any IMPORTANT findings it surfaces outside the review skill, rerun `build-verify`, and then rerun `pr-review uncommitted` until no IMPORTANT findings remain, unless the fix needs user judgment. + +**After `pr-review` returns cleanly or only leaves accepted follow-up NITs: produce +the Final Report. This is the only place the pipeline stops on success.** + +## Final Report + +Output a single consolidated summary: +- Feature name and task count +- Implementation result (which tasks completed, any that were blocked) +- `build-verify` result (✓/✗ per step, with the auto-scope decision repeated) +- `pr-review` result (IMPORTANT/NIT counts and any auto-fixed NITs) +- **Reminder:** nothing has been committed. The user reviews the diff and commits, or + invokes `create-pr`, on their own terms. + +## Rules + +- **Never commit.** The entire pipeline leaves the working tree dirty for the user to review. +- **No intermediate approvals.** Uninterrupted execution is the whole point. +- **Do not edit specs.** `start-job` reads PRD and tech spec inputs. It should not rewrite them unless the user explicitly asks. +- **Stop on hard failure.** If a phase cannot proceed (missing spec, repeated build failures, + an agent reports it cannot implement a task), stop and surface — don't continue on a + broken base. +- **Do not re-run phases already completed.** If `/start-job` is invoked on a feature that + already has `tasks.md`, confirm whether to re-generate tasks or pick up from + implementation. +- **Implementation standards are reviewed after verification (via `/pr-review`).** + Build/test/lint failures are resolved first; standards findings are handled as the final + pre-PR review pass. diff --git a/ai/skills/tasks/SKILL.md b/ai/skills/tasks/SKILL.md new file mode 100644 index 0000000..fa494ef --- /dev/null +++ b/ai/skills/tasks/SKILL.md @@ -0,0 +1,125 @@ +--- +name: tasks +description: > + Task Breakdown Command. Breaks a feature into discrete, dependency-ordered implementation tasks + from a PRD and tech spec. Creates a task list and individual task files with no approval prompt. + When run inside the `/start-job` pipeline, return control to that orchestrator so it can invoke + the implementation phase. When invoked standalone, stop after generating tasks and prompting + for the next step. + Use when the user says "break this down into tasks", "create tasks", "task breakdown", + or after the tech spec is complete and the user wants to plan implementation. +allowed-tools: Bash, Read, Grep, Glob, Write, Edit +model: claude-sonnet-4-6 +--- + +# Task Breakdown + +You are specialized in breaking down features into discrete, manageable implementation tasks. + +## Objectives +1. Break down the feature into independently completable tasks +2. Establish clear dependency ordering +3. Create task files that an agent can execute without ambiguity + +## Prerequisites +- PRD: `.claude/tasks/[feature-name]/prd.md` +- Tech Spec: `.claude/tasks/[feature-name]/techspec.md` + +## Workflow + +### CRITICAL: Do NOT ask for approval. +The user does not want to review the task list before implementation. Generate the tasks, keep the +total count reasonable (aim for cohesive tasks, not micro-tasks), and stop after reporting. +The caller (`/start-job` or the user directly) decides what runs next. + +### Step 1: Analyze PRD and Tech Spec + +Read both documents and identify: +- All components that need to be built +- The dependency graph between components +- Which tasks can be parallelized + +### Step 2: Generate Task Structure + +Order tasks following this Flutter-stack progression (mirrors the `ai/templates/task-list.md` +phases): + +1. **Foundation (data layer)** — DTOs in `lib/common/data/dto/` (`@freezed` + + `@JsonSerializable`), domain entities in `lib/common/data/entity/`, repositories, and + use cases. Run `make gen` after annotation changes. +2. **Core implementation (state + UI)** — `@riverpod` notifiers, `*_state.dart` / + `*_event.dart` (feature-scoped freezed types), and the page split: + `*_page.dart` (thin `@RoutePage` widget) + `*_page_content.dart` (heavier UI). +3. **Integration (navigation, services, platform)** — `@RoutePage` wiring in + `lib/app/`, Firebase / platform integrations, analytics events, permissions, native + channels. +4. **Tests and verification** — only when explicitly required by the PRD / techspec. + Standard analyze / test / build verification is handled by `build-verify` at the end of + the flow, so don't add a "run analyze" task unless the feature itself requires custom + coverage. + +Group tasks into phases. Each task should be: +- Small enough to complete in one focused session +- Large enough to be meaningful (not trivially small) +- Scoped so later tasks don't have to unwind earlier ones + +Keep the total number of tasks reasonable — prefer fewer, well-scoped tasks over many tiny ones. + +### Step 3: Create Task Summary + +Use the template at `ai/templates/task-list.md` (also reachable as +`.claude/templates/task-list.md` via symlink) to generate: +`.claude/tasks/[feature-name]/tasks.md` + +### Step 4: Generate Individual Task Files + +Use the template at `ai/templates/task.md` (also reachable as `.claude/templates/task.md` +via symlink) to create: +`.claude/tasks/[feature-name]/[num]_task.md` + +Each task file should include: +- Clear vision of what the task accomplishes +- Data model details — DTO / entity / state / event types and their location under + `lib/common/data/` or `lib/features/<feature>/` +- Implementation steps — referencing the existing feature pattern + (`*_page.dart` + `*_page_content.dart` + `*_state.dart` + `*_event.dart`) +- Constraints — no IO in widgets, no hand-edits to generated files (`*.g.dart`, + `*.freezed.dart`, `*.gr.dart`), reuse from `lib/common/` before adding new primitives +- Quality gates — `make gen` clean, `fvm flutter analyze` passes, `fvm flutter test` passes + +### Step 5: Brief Summary + +Output a one-paragraph summary (what was generated, how many tasks, dependency shape). Keep it +tight. Do NOT invoke any follow-up skills. + +### Step 6: Prompt Next-Step Choice + +**If (and only if) this skill was invoked directly by the user** (not by `/start-job`), end by +asking how they want to proceed: + +> **Next step — how do you want to continue?** +> +> - **`/start-job`** — run the remaining phases in one shot: implement-tasks-sequence → +> build-verify → pr-review. Nothing will be committed. +> - **Manual** — step through each phase yourself (`/implement-tasks-sequence`, then +> `/build-verify`, then `/pr-review`). + +Wait for the user's choice. Do NOT auto-run anything. + +When invoked by `/start-job`: skip the prompt above and return control to the `/start-job` +orchestrator. The orchestrator must then invoke `implement-tasks-sequence` as Phase 2 without +pausing for user input. + +## Project context + +This is a Flutter app using: +- `flutter_riverpod` + `riverpod_annotation` for state and DI +- `freezed` + `json_serializable` for data classes (DTOs, entities, states, events) +- `auto_route` for navigation (`@RoutePage`) +- `dio` for HTTP, Firebase services for backend +- FVM-pinned Flutter SDK (see `.fvmrc`) + +Refer to `AGENTS.md`, `docs/PROJECT_OVERVIEW.md`, and `docs/PROJECT_GUIDELINES.md` for the +canonical conventions to bake into task descriptions. Prefer reusing primitives from +`lib/common/` before introducing new ones, and follow the existing feature folders under +`lib/features/<feature>/` as the structural reference. diff --git a/ai/skills/techspec/SKILL.md b/ai/skills/techspec/SKILL.md new file mode 100644 index 0000000..fa0a1f4 --- /dev/null +++ b/ai/skills/techspec/SKILL.md @@ -0,0 +1,107 @@ +--- +name: techspec +description: > + Technical Specification Command. Translates a PRD into an implementation-ready technical spec + through deep project analysis and clarification. Use when the user says "create a tech spec", + "write the technical design", "spec this out", or after a PRD is complete and the user wants + to move to technical planning. +allowed-tools: Bash, Read, Grep, Glob, Write, Edit +model: claude-opus-4-7 +--- + +# Technical Specification + +You are a technical specification expert translating PRDs into implementation-ready specs for +this Flutter app. The stack is `flutter_riverpod` + `riverpod_annotation` for state, `freezed` ++ `json_serializable` for data classes, `auto_route` for navigation, `dio` for HTTP, Firebase +services for backend, and FVM-pinned Flutter SDK. + +## Objectives +1. Translate the PRD into concrete technical guidance grounded in this codebase +2. Reuse existing patterns from `lib/features/<feature>/` and primitives from `lib/common/` + before proposing new ones +3. Specify the data → state → UI → integration build order so the `tasks` skill can break it + into ordered work units + +## Prerequisites +- Required: `.claude/tasks/[feature-name]/prd.md` +- Output: `.claude/tasks/[feature-name]/techspec.md` + +## Workflow + +### Step 1: Analyze PRD + +Read the PRD at `.claude/tasks/[feature-name]/prd.md` and extract: +- Core requirements and constraints +- Domain entities involved (data shapes, sources, lifetimes) +- Platform scope — which of Android / iOS / web / desktop are in scope, and whether any + platform-specific behaviors apply +- Whether the feature touches Firebase services, native channels, or other integrations + +### Step 2: Deep Project Analysis + +Explore the codebase to ground the spec in reality: +- Look for existing features under `lib/features/` that follow a similar shape and should be + mirrored (the canonical pattern is `*_page.dart` + `*_page_content.dart` + `*_state.dart` + + `*_event.dart`). +- Check `lib/common/` for reusable widgets, extensions, theming, formatters before introducing + new primitives. +- Inspect existing DTOs (`lib/common/data/dto/`), entities (`lib/common/data/entity/`), + repositories, and use cases for naming / mapping conventions. +- Check `lib/app/setup/setup_app.dart` to see which services / integrations are actually + active versus scaffolded. +- Read `AGENTS.md`, `docs/PROJECT_OVERVIEW.md`, and `docs/PROJECT_GUIDELINES.md` for the + canonical conventions. + +### Step 3: Technical Clarifications + +Ask the user about any ambiguities: +- Data flow: where does data originate (API via `dio`, Firebase service, local cache, + platform channel) and where is it persisted (in-memory only, `shared_preferences`, secure + storage)? +- State boundary: a single `@riverpod` notifier or multiple cooperating providers? Sync + `Notifier` or `AsyncNotifier`? +- Navigation: new `@RoutePage` route(s), modal vs. full-screen, deep-link entry? +- Codegen scope: which annotations are involved (`@freezed`, `@JsonSerializable`, + `@riverpod`, `@RoutePage`) — this drives when `make gen` needs to run. +- Testing strategy: which providers / use cases warrant unit tests; any widget tests required? +- Any domain-specific logic that needs clarification. + +Do not proceed until clarifications are resolved. + +### Step 4: Generate Tech Spec + +Read the template at `ai/templates/techspec.md` (also reachable at +`.claude/templates/techspec.md` via symlink) and draft the spec. + +- Reference concrete files and modules from the codebase +- Follow the project's architecture rules from `AGENTS.md`, + `docs/PROJECT_OVERVIEW.md`, and `docs/PROJECT_GUIDELINES.md` +- Include a clear build order in Development Sequencing — typically: + 1. Data layer (DTOs, entities, repository, use cases) — `make gen` after annotations + 2. State layer (`@riverpod` notifier, `*_state.dart`, `*_event.dart`) + 3. UI layer (`*_page.dart` + `*_page_content.dart`) + 4. Integration / navigation (`@RoutePage` wiring, Firebase services, analytics, permissions) + 5. Localization strings (`assets/localization/*.arb`) and final QA +- Call out files to **not** hand-edit: `*.g.dart`, `*.freezed.dart`, `*.gr.dart`, + `*.gen.dart`, `lib/assets/` + +### Step 5: Save Tech Spec + +Save to `.claude/tasks/[feature-name]/techspec.md`. + +- Confirm the file path +- Summarize key architectural decisions (state model, data sources, navigation shape, + any new packages needed in `pubspec.yaml`) + +### Step 6: Final next-step prompt + +After saving the techspec, end with this guidance: + +> **What to do next** +> +> Run `/start-job [feature-name]` to run the full implementation pipeline +> (`tasks` → `implement-tasks-sequence` → `build-verify` → `pr-review`), or step through +> manually with `/tasks` first. + +Wait for the user to act. Do NOT auto-run `/start-job` or `/tasks`. From 43579ee7f3f23fa8806afae0f2bcaaa02f4e46e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Urb=C3=A1nek?= <michal.urbanek@strv.com> Date: Fri, 15 May 2026 12:07:11 +0200 Subject: [PATCH 7/9] chore: document AI workflow tool setup --- README.md | 14 ++++++++ ai/skills/build-verify/scripts/verify.sh | 10 ++++-- ai/skills/lint_format/scripts/lint_format.sh | 19 ++++++++--- ai/skills/project-setup/SKILL.md | 33 +++++++++++++++++-- ai/skills/release-builds/SKILL.md | 8 ++--- .../release-builds/scripts/archive_ios_ipa.sh | 2 +- docs/PROJECT_GUIDELINES.md | 10 ++++++ 7 files changed, 80 insertions(+), 16 deletions(-) mode change 100644 => 100755 ai/skills/release-builds/scripts/archive_ios_ipa.sh diff --git a/README.md b/README.md index ffce976..0b3749b 100644 --- a/README.md +++ b/README.md @@ -507,12 +507,26 @@ Reusable workflow guides live under `ai/skills/`: - `project-setup` for app identity, icons, splash, platform cleanup, Firebase/secrets decisions, and initial validation. - `feature-screen` for route and UI scaffolding. - `feature-data-flow` for full backend-backed features with DTOs, entities, use cases, and state wiring. +- `prd`, `techspec`, `tasks`, `implement`, `implement-tasks-sequence`, and `start-job` for the structured spec-to-implementation pipeline. +- `build-verify` and `lint-format` for repo-local verification scripts. +- `create-pr` and `review-pr-comments` for GitHub PR workflows. - `upgrade` for Flutter and dependency upgrades. - `release-prepare` for version bump, release notes, release branch, and PR preparation. - `release-builds` for post-merge Android tags plus manual iOS IPA generation and archival. - `secrets-bootstrap` for safe handling of encrypted secrets and signing material. - `pr-review` for bug-first PR and diff review. +AI workflow prerequisites: +- Run `make install` so FVM and project CLIs are installed. If your shell cannot find `fvm`, make sure `$HOME/.pub-cache/bin` is on `PATH`. +- Install GitHub CLI for PR workflows (`brew install gh` on macOS) and authenticate with `gh auth login --hostname github.com --git-protocol ssh --web`. +- Verify GitHub CLI with `gh auth status`. If an invalid `GITHUB_TOKEN` or `GH_TOKEN` is set in your environment, clear or replace it so the stored login can be used. +- Repo-local scripts should be executable and syntax-check clean: + - `ai/skills/build-verify/scripts/verify.sh --help` + - `ai/skills/lint_format/scripts/lint_format.sh --help` + - `bash -n ai/skills/build-verify/scripts/verify.sh` + - `bash -n ai/skills/lint_format/scripts/lint_format.sh` + - `sh -n ai/skills/release-builds/scripts/archive_ios_ipa.sh` + Recommended usage: - When working with an AI agent, explicitly mention the workflow you want to use, for example `Use the feature-data-flow skill`. - Keep long-term project rules in `AGENTS.md` and the docs, and keep repeatable procedures in `ai/skills/`. diff --git a/ai/skills/build-verify/scripts/verify.sh b/ai/skills/build-verify/scripts/verify.sh index fba555e..ed494d2 100755 --- a/ai/skills/build-verify/scripts/verify.sh +++ b/ai/skills/build-verify/scripts/verify.sh @@ -82,9 +82,13 @@ if ! command -v git >/dev/null 2>&1; then exit 1 fi if ! command -v fvm >/dev/null 2>&1; then - echo "ERROR: fvm not found on PATH. Install it with: dart pub global activate fvm" >&2 - echo " (or see the project README / Makefile 'install' target.)" >&2 - exit 1 + if [ -x "$HOME/.pub-cache/bin/fvm" ]; then + export PATH="$HOME/.pub-cache/bin:$PATH" + else + echo "ERROR: fvm not found on PATH. Install it with: dart pub global activate fvm" >&2 + echo " (or see the project README / Makefile 'install' target.)" >&2 + exit 1 + fi fi REPO_ROOT="$(git rev-parse --show-toplevel)" diff --git a/ai/skills/lint_format/scripts/lint_format.sh b/ai/skills/lint_format/scripts/lint_format.sh index 221ab74..53e4a50 100755 --- a/ai/skills/lint_format/scripts/lint_format.sh +++ b/ai/skills/lint_format/scripts/lint_format.sh @@ -28,9 +28,6 @@ Flags: EOF } -REPO_ROOT="$(git rev-parse --show-toplevel)" -cd "$REPO_ROOT" - mode="auto" check_format=false run_format=true @@ -65,11 +62,23 @@ for arg in "$@"; do esac done -if ! command -v fvm >/dev/null 2>&1; then - echo "fvm not found. Install FVM or make sure it is available on PATH." +if ! command -v git >/dev/null 2>&1; then + echo "git not found on PATH." exit 1 fi +if ! command -v fvm >/dev/null 2>&1; then + if [[ -x "$HOME/.pub-cache/bin/fvm" ]]; then + export PATH="$HOME/.pub-cache/bin:$PATH" + else + echo "fvm not found. Install FVM with 'dart pub global activate fvm' or run 'make install'." + exit 1 + fi +fi + +REPO_ROOT="$(git rev-parse --show-toplevel)" +cd "$REPO_ROOT" + is_generated_dart() { local file="$1" [[ "$file" == *.g.dart ]] || diff --git a/ai/skills/project-setup/SKILL.md b/ai/skills/project-setup/SKILL.md index 5442f12..1dfb8e1 100644 --- a/ai/skills/project-setup/SKILL.md +++ b/ai/skills/project-setup/SKILL.md @@ -36,9 +36,36 @@ Use this skill when preparing a new app from this template or reviewing whether 5. If platform support changes, run the Platform Cleanup Workflow below. 6. If Firebase support changes, run the Firebase Workflow below. 7. If secrets or signing material are needed, use the `secrets-bootstrap` workflow. -8. Update the README First steps checklist to mark any completed setup items with `[x]`. -9. Run `make gen` after setup changes that affect routes, localization, generated assets, or annotations. -10. Validate with `fvm flutter analyze` and the relevant tests. +8. Run the AI Workflow Tooling Check below so repo-local skills and scripts are usable. +9. Update the README First steps checklist to mark any completed setup items with `[x]`. +10. Run `make gen` after setup changes that affect routes, localization, generated assets, or annotations. +11. Validate with `fvm flutter analyze` and the relevant tests. + +## AI Workflow Tooling Check +Use this when setting up a new clone, preparing AI workflows, or debugging skill scripts. + +1. Install project tooling: + - Run `make install` to activate FVM, install the pinned Flutter SDK, and install project CLIs. + - Ensure `fvm` is available either on `PATH` or at `$HOME/.pub-cache/bin/fvm`. Repo scripts fall back to that path when possible. +2. Install and authenticate GitHub CLI when PR workflows are needed: + - Install `gh` with the platform package manager, for example `brew install gh` on macOS. + - Run `gh auth login --hostname github.com --git-protocol ssh --web`. + - Run `gh auth status` and fix any invalid `GITHUB_TOKEN` / `GH_TOKEN` environment variables if they override the stored login. +3. Verify repo-local script permissions and syntax: + - `test -x ai/skills/build-verify/scripts/verify.sh` + - `test -x ai/skills/lint_format/scripts/lint_format.sh` + - `test -x ai/skills/release-builds/scripts/archive_ios_ipa.sh` + - `bash -n ai/skills/build-verify/scripts/verify.sh` + - `bash -n ai/skills/lint_format/scripts/lint_format.sh` + - `sh -n ai/skills/release-builds/scripts/archive_ios_ipa.sh` +4. Verify Claude discovery wiring when Claude Code support is needed: + - every `ai/skills/<name>/SKILL.md` has a matching `.claude/skills/<name>` symlink, except folder/name aliases such as `lint_format` -> `lint-format` + - every skill has a matching `.claude/commands/<name>.md` + - each symlink resolves to a `SKILL.md` +5. Run lightweight help checks: + - `ai/skills/build-verify/scripts/verify.sh --help` + - `ai/skills/lint_format/scripts/lint_format.sh --help` + - `ai/skills/release-builds/scripts/archive_ios_ipa.sh` should print usage and exit non-zero when no flavor is supplied. ## Platform Cleanup Workflow Use this workflow to automate step 4 from the README First steps checklist. diff --git a/ai/skills/release-builds/SKILL.md b/ai/skills/release-builds/SKILL.md index 5851cc2..4781ec8 100644 --- a/ai/skills/release-builds/SKILL.md +++ b/ai/skills/release-builds/SKILL.md @@ -62,13 +62,13 @@ Immediately after each IPA build, archive the IPA out of `build/ios/ipa/` and Fl Use: ```bash -sh ai/skills/release-builds/scripts/archive_ios_ipa.sh <flavor> +ai/skills/release-builds/scripts/archive_ios_ipa.sh <flavor> ``` Examples: -- `sh ai/skills/release-builds/scripts/archive_ios_ipa.sh develop` -- `sh ai/skills/release-builds/scripts/archive_ios_ipa.sh staging` -- `sh ai/skills/release-builds/scripts/archive_ios_ipa.sh production` +- `ai/skills/release-builds/scripts/archive_ios_ipa.sh develop` +- `ai/skills/release-builds/scripts/archive_ios_ipa.sh staging` +- `ai/skills/release-builds/scripts/archive_ios_ipa.sh production` The script copies the generated IPA into: diff --git a/ai/skills/release-builds/scripts/archive_ios_ipa.sh b/ai/skills/release-builds/scripts/archive_ios_ipa.sh old mode 100644 new mode 100755 index 7a020eb..e752a23 --- a/ai/skills/release-builds/scripts/archive_ios_ipa.sh +++ b/ai/skills/release-builds/scripts/archive_ios_ipa.sh @@ -3,7 +3,7 @@ set -eu if [ "$#" -ne 1 ]; then - echo "Usage: sh ai/skills/release-builds/scripts/archive_ios_ipa.sh <develop|staging|production>" >&2 + echo "Usage: ai/skills/release-builds/scripts/archive_ios_ipa.sh <develop|staging|production>" >&2 exit 1 fi diff --git a/docs/PROJECT_GUIDELINES.md b/docs/PROJECT_GUIDELINES.md index 572cdea..fff8ab2 100644 --- a/docs/PROJECT_GUIDELINES.md +++ b/docs/PROJECT_GUIDELINES.md @@ -100,12 +100,22 @@ Not every feature needs every file. Simple screens in the template only use `*_p ## FVM And Commands - Flutter is managed with FVM. The pinned version lives in `.fvmrc`. - Prefer `fvm flutter ...` and `fvm dart ...` commands over machine-global Flutter commands. +- If a non-interactive shell cannot find `fvm`, check `$HOME/.pub-cache/bin/fvm`; repo-local skill scripts use that fallback when available. - Common commands: - `make gen` - `make watch` - `fvm flutter analyze` - `fvm flutter test` +## AI Workflow Tooling +- Repo-local skills live under `ai/skills/` and Claude Code symlinks live under `.claude/skills/`. +- Skill scripts should be executable and syntax-check clean before relying on them: + - `bash -n ai/skills/build-verify/scripts/verify.sh` + - `bash -n ai/skills/lint_format/scripts/lint_format.sh` + - `sh -n ai/skills/release-builds/scripts/archive_ios_ipa.sh` +- PR-related skills use GitHub CLI. Install it locally and authenticate with `gh auth login`; verify with `gh auth status`. +- If `gh auth status` reports an invalid `GITHUB_TOKEN` or `GH_TOKEN`, clear or replace that environment variable so the stored GitHub CLI login can be used. + ## Flutter And Package Upgrades - Treat `.fvmrc` and `pubspec.yaml` as the source of truth for SDK and package versions. - When upgrading Flutter, align the Flutter version in `pubspec.yaml` with `.fvmrc`. From 839c2a63e610c4b9c7a1e81aec4ab97d3698ab6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Urb=C3=A1nek?= <michal.urbanek@strv.com> Date: Fri, 15 May 2026 12:20:15 +0200 Subject: [PATCH 8/9] fix: address PR workflow review comments --- .claude/settings.json | 1 - .claude/skills/lint-format | 2 +- README.md | 4 ++-- ai/skills/build-verify/SKILL.md | 4 ++++ ai/skills/build-verify/scripts/verify.sh | 19 +++++++++++++++++++ ai/skills/implement/SKILL.md | 2 +- .../{lint_format => lint-format}/SKILL.md | 4 ++-- .../scripts/lint-format.sh} | 14 +++++++------- ai/skills/project-setup/SKILL.md | 8 ++++---- ai/skills/review-pr-comments/SKILL.md | 17 +++++++++++------ ai/skills/tasks/SKILL.md | 4 ++-- ai/skills/techspec/SKILL.md | 4 ++-- ai/templates/task.md | 2 +- ai/templates/techspec.md | 2 +- docs/PROJECT_GUIDELINES.md | 2 +- 15 files changed, 58 insertions(+), 31 deletions(-) rename ai/skills/{lint_format => lint-format}/SKILL.md (96%) rename ai/skills/{lint_format/scripts/lint_format.sh => lint-format/scripts/lint-format.sh} (90%) diff --git a/.claude/settings.json b/.claude/settings.json index d61c709..4686e97 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -22,7 +22,6 @@ "Read(**/service-account*.json)", "Read(**/.netrc)", "Read(**/.npmrc)", - "Read(**/extras/**)", "Read(**/.gitmodules)", "Read(**/.gradle/**)", "Read(**/.idea/**)", diff --git a/.claude/skills/lint-format b/.claude/skills/lint-format index 8757067..edbc66f 120000 --- a/.claude/skills/lint-format +++ b/.claude/skills/lint-format @@ -1 +1 @@ -../../ai/skills/lint_format \ No newline at end of file +../../ai/skills/lint-format \ No newline at end of file diff --git a/README.md b/README.md index 0b3749b..a34c9cb 100644 --- a/README.md +++ b/README.md @@ -522,9 +522,9 @@ AI workflow prerequisites: - Verify GitHub CLI with `gh auth status`. If an invalid `GITHUB_TOKEN` or `GH_TOKEN` is set in your environment, clear or replace it so the stored login can be used. - Repo-local scripts should be executable and syntax-check clean: - `ai/skills/build-verify/scripts/verify.sh --help` - - `ai/skills/lint_format/scripts/lint_format.sh --help` + - `ai/skills/lint-format/scripts/lint-format.sh --help` - `bash -n ai/skills/build-verify/scripts/verify.sh` - - `bash -n ai/skills/lint_format/scripts/lint_format.sh` + - `bash -n ai/skills/lint-format/scripts/lint-format.sh` - `sh -n ai/skills/release-builds/scripts/archive_ios_ipa.sh` Recommended usage: diff --git a/ai/skills/build-verify/SKILL.md b/ai/skills/build-verify/SKILL.md index 41a5f5c..efddc6f 100644 --- a/ai/skills/build-verify/SKILL.md +++ b/ai/skills/build-verify/SKILL.md @@ -81,6 +81,10 @@ Both verify compilation on each platform; iOS skips codesigning so it doesn't ne provisioning profiles, and Android uses the debug variant so it doesn't need a release keystore. +On non-macOS hosts, the script skips the iOS native build automatically unless `--ios-only` +was explicitly requested. Explicit iOS-only verification fails fast off macOS because +`flutter build ios` requires Darwin/Xcode. + **Format** — runs after native builds pass: `fvm dart format lib test`. This auto-rewrites files; the script reports how many files changed so the user can review. diff --git a/ai/skills/build-verify/scripts/verify.sh b/ai/skills/build-verify/scripts/verify.sh index ed494d2..0d8344a 100755 --- a/ai/skills/build-verify/scripts/verify.sh +++ b/ai/skills/build-verify/scripts/verify.sh @@ -137,6 +137,14 @@ if [ ! -f "$REPO_ROOT/lib/main_$FLAVOR.dart" ]; then exit 2 fi +append_auto_msg() { + if [ -n "$AUTO_MSG" ]; then + AUTO_MSG="$AUTO_MSG; $1" + else + AUTO_MSG="$1" + fi +} + # --- Auto-scope detection ------------------------------------------------ # Runs unless --full or any explicit narrowing flag is set. EXPLICIT_SCOPE=0 @@ -218,6 +226,17 @@ if [ $FULL -eq 0 ] && [ $EXPLICIT_SCOPE -eq 0 ]; then fi fi +if [ "$(uname -s)" != "Darwin" ] && [ $SKIP_BUILDS -eq 0 ]; then + if [ $IOS_ONLY -eq 1 ]; then + echo "ERROR: iOS builds require macOS. Re-run on macOS or remove --ios-only." >&2 + exit 2 + fi + if [ $ANDROID_ONLY -eq 0 ]; then + ANDROID_ONLY=1 + append_auto_msg "non-macOS host detected; skipping iOS native build" + fi +fi + LOG_DIR="$(mktemp -d -t build-verify-XXXXXX)" DART_LOG="$LOG_DIR/dart.log" IOS_LOG="$LOG_DIR/ios.log" diff --git a/ai/skills/implement/SKILL.md b/ai/skills/implement/SKILL.md index 8dfcf31..bf5c227 100644 --- a/ai/skills/implement/SKILL.md +++ b/ai/skills/implement/SKILL.md @@ -99,7 +99,7 @@ In standalone mode, verify before considering the task complete. Use the smallest sufficient verification: - Run `make gen` when annotations, routes, DTOs, localization, or asset inputs changed. -- Run `ai/skills/lint_format/scripts/lint_format.sh` for normal Dart/Flutter code changes. +- Run `ai/skills/lint-format/scripts/lint-format.sh` for normal Dart/Flutter code changes. - Run `fvm flutter test` when behavior, state, use cases, widgets, or tests changed. - Run `ai/skills/build-verify/scripts/verify.sh` for broad, cross-platform, dependency, startup, routing, generated-code, or PR-ready tasks. - Run `make integration_test` only when Patrol integration flows changed or the user asks for it. diff --git a/ai/skills/lint_format/SKILL.md b/ai/skills/lint-format/SKILL.md similarity index 96% rename from ai/skills/lint_format/SKILL.md rename to ai/skills/lint-format/SKILL.md index 4ca9ae8..810ee93 100644 --- a/ai/skills/lint_format/SKILL.md +++ b/ai/skills/lint-format/SKILL.md @@ -24,7 +24,7 @@ Run this skill after completing Flutter/Dart code changes unless a broader verif Run the wrapper script from the repo root: ```bash -ai/skills/lint_format/scripts/lint_format.sh +ai/skills/lint-format/scripts/lint-format.sh ``` The script auto-detects whether Flutter-relevant files changed. When relevant files changed, it formats changed Dart files and runs a project-wide analyzer pass. @@ -32,7 +32,7 @@ The script auto-detects whether Flutter-relevant files changed. When relevant fi Claude-discovered path: ```bash -.claude/skills/lint-format/scripts/lint_format.sh +.claude/skills/lint-format/scripts/lint-format.sh ``` ## Flags diff --git a/ai/skills/lint_format/scripts/lint_format.sh b/ai/skills/lint-format/scripts/lint-format.sh similarity index 90% rename from ai/skills/lint_format/scripts/lint_format.sh rename to ai/skills/lint-format/scripts/lint-format.sh index 53e4a50..8a30e34 100755 --- a/ai/skills/lint_format/scripts/lint_format.sh +++ b/ai/skills/lint-format/scripts/lint-format.sh @@ -3,17 +3,17 @@ # Runs Flutter/Dart format and analyzer checks for this repository. # # Usage: -# ./lint_format.sh # Auto-detect changed Flutter-relevant files -# ./lint_format.sh all # Format standard Dart source directories, then analyze -# ./lint_format.sh --check # Check formatting without writing changes, then analyze -# ./lint_format.sh --format-only # Run only dart format -# ./lint_format.sh --analyze-only # Run only flutter analyze +# ./lint-format.sh # Auto-detect changed Flutter-relevant files +# ./lint-format.sh all # Format standard Dart source directories, then analyze +# ./lint-format.sh --check # Check formatting without writing changes, then analyze +# ./lint-format.sh --format-only # Run only dart format +# ./lint-format.sh --analyze-only # Run only flutter analyze set -euo pipefail usage() { cat <<'EOF' -Usage: lint_format.sh [auto|all|--all] [--check] [--format-only|--analyze-only] +Usage: lint-format.sh [auto|all|--all] [--check] [--format-only|--analyze-only] Default auto mode: - formats changed non-generated Dart files @@ -118,7 +118,7 @@ while IFS= read -r file; do fi done <<< "$changed_files" -if [[ "$mode" == "auto" && "$has_flutter_changes" == false ]]; then +if [[ "$mode" == "auto" && "$has_flutter_changes" == false && "$run_format" == true ]]; then echo "No Flutter/Dart-relevant changes detected. Nothing to lint or format." exit 0 fi diff --git a/ai/skills/project-setup/SKILL.md b/ai/skills/project-setup/SKILL.md index 1dfb8e1..e26ba28 100644 --- a/ai/skills/project-setup/SKILL.md +++ b/ai/skills/project-setup/SKILL.md @@ -53,18 +53,18 @@ Use this when setting up a new clone, preparing AI workflows, or debugging skill - Run `gh auth status` and fix any invalid `GITHUB_TOKEN` / `GH_TOKEN` environment variables if they override the stored login. 3. Verify repo-local script permissions and syntax: - `test -x ai/skills/build-verify/scripts/verify.sh` - - `test -x ai/skills/lint_format/scripts/lint_format.sh` + - `test -x ai/skills/lint-format/scripts/lint-format.sh` - `test -x ai/skills/release-builds/scripts/archive_ios_ipa.sh` - `bash -n ai/skills/build-verify/scripts/verify.sh` - - `bash -n ai/skills/lint_format/scripts/lint_format.sh` + - `bash -n ai/skills/lint-format/scripts/lint-format.sh` - `sh -n ai/skills/release-builds/scripts/archive_ios_ipa.sh` 4. Verify Claude discovery wiring when Claude Code support is needed: - - every `ai/skills/<name>/SKILL.md` has a matching `.claude/skills/<name>` symlink, except folder/name aliases such as `lint_format` -> `lint-format` + - every `ai/skills/<name>/SKILL.md` has a matching `.claude/skills/<name>` symlink - every skill has a matching `.claude/commands/<name>.md` - each symlink resolves to a `SKILL.md` 5. Run lightweight help checks: - `ai/skills/build-verify/scripts/verify.sh --help` - - `ai/skills/lint_format/scripts/lint_format.sh --help` + - `ai/skills/lint-format/scripts/lint-format.sh --help` - `ai/skills/release-builds/scripts/archive_ios_ipa.sh` should print usage and exit non-zero when no flavor is supplied. ## Platform Cleanup Workflow diff --git a/ai/skills/review-pr-comments/SKILL.md b/ai/skills/review-pr-comments/SKILL.md index 777ec5e..4dfca1a 100644 --- a/ai/skills/review-pr-comments/SKILL.md +++ b/ai/skills/review-pr-comments/SKILL.md @@ -38,26 +38,31 @@ If no PR is found, inform the user and stop. If `gh` is not available or not aut ## Step 2: Fetch All Review Comments -Extract the owner/repo from `gh repo view --json nameWithOwner --jq '.nameWithOwner'`. +Extract the PR number and owner/repo: + +```bash +number="$(gh pr list --head "$(git branch --show-current)" --json number --jq '.[0].number')" +repo="$(gh repo view --json nameWithOwner --jq '.nameWithOwner')" +``` Fetch all PR review comments, including inline comments on code: ```bash -gh api repos/{owner}/{repo}/pulls/{number}/comments --paginate \ +gh api "repos/$repo/pulls/$number/comments" --paginate \ --jq '.[] | {id: .id, user: .user.login, user_type: .user.type, path: .path, line: .line, original_line: .original_line, diff_hunk: .diff_hunk, body: .body}' ``` Also fetch top-level issue-style comments on the PR (some reviewers use these): ```bash -gh api repos/{owner}/{repo}/issues/{number}/comments --paginate \ +gh api "repos/$repo/issues/$number/comments" --paginate \ --jq '.[] | {id: .id, user: .user.login, user_type: .user.type, body: .body}' ``` Optionally fetch the PR review summaries if the user asks for every review artifact: ```bash -gh api repos/{owner}/{repo}/pulls/{number}/reviews --paginate \ +gh api "repos/$repo/pulls/$number/reviews" --paginate \ --jq '.[] | {id: .id, user: .user.login, user_type: .user.type, state: .state, body: .body}' ``` @@ -179,14 +184,14 @@ Do not use AI ignore commands for human comments. For inline PR review comments, reply with: ```bash -gh api repos/{owner}/{repo}/pulls/{number}/comments/{comment_id}/replies \ +gh api "repos/$repo/pulls/$number/comments/$comment_id/replies" \ -f body="<reply message>" ``` For top-level issue comments or review summaries, use a normal PR comment when a direct reply endpoint is not available: ```bash -gh pr comment {number} --body "<reply message>" +gh pr comment "$number" --body "<reply message>" ``` 7. Push changes only if the user explicitly approved a push. diff --git a/ai/skills/tasks/SKILL.md b/ai/skills/tasks/SKILL.md index fa494ef..a208d87 100644 --- a/ai/skills/tasks/SKILL.md +++ b/ai/skills/tasks/SKILL.md @@ -44,8 +44,8 @@ Read both documents and identify: Order tasks following this Flutter-stack progression (mirrors the `ai/templates/task-list.md` phases): -1. **Foundation (data layer)** — DTOs in `lib/common/data/dto/` (`@freezed` + - `@JsonSerializable`), domain entities in `lib/common/data/entity/`, repositories, and +1. **Foundation (data layer)** — DTOs in `lib/common/data/dto/` (`@freezed` with + generated `fromJson` factories), domain entities in `lib/common/data/entity/`, repositories, and use cases. Run `make gen` after annotation changes. 2. **Core implementation (state + UI)** — `@riverpod` notifiers, `*_state.dart` / `*_event.dart` (feature-scoped freezed types), and the page split: diff --git a/ai/skills/techspec/SKILL.md b/ai/skills/techspec/SKILL.md index fa0a1f4..6b5c212 100644 --- a/ai/skills/techspec/SKILL.md +++ b/ai/skills/techspec/SKILL.md @@ -62,8 +62,8 @@ Ask the user about any ambiguities: - State boundary: a single `@riverpod` notifier or multiple cooperating providers? Sync `Notifier` or `AsyncNotifier`? - Navigation: new `@RoutePage` route(s), modal vs. full-screen, deep-link entry? -- Codegen scope: which annotations are involved (`@freezed`, `@JsonSerializable`, - `@riverpod`, `@RoutePage`) — this drives when `make gen` needs to run. +- Codegen scope: which generated inputs are involved (`@freezed` models with `fromJson`, + `@riverpod`, `@RoutePage`, localization, assets) — this drives when `make gen` needs to run. - Testing strategy: which providers / use cases warrant unit tests; any widget tests required? - Any domain-specific logic that needs clarification. diff --git a/ai/templates/task.md b/ai/templates/task.md index 7caf49f..f4eaee7 100644 --- a/ai/templates/task.md +++ b/ai/templates/task.md @@ -17,7 +17,7 @@ ### Entities [Define the core entities, their fields, and relationships. -- DTOs live in `lib/common/data/dto/` (annotated with `@freezed` + `@JsonSerializable`) +- DTOs live in `lib/common/data/dto/` (using `@freezed` with generated `fromJson` factories) - Domain entities live in `lib/common/data/entity/` (mapped from DTOs) - Feature-scoped state/event types live next to the feature as `*_state.dart` / `*_event.dart`] diff --git a/ai/templates/techspec.md b/ai/templates/techspec.md index 01f0c8c..c8e8e76 100644 --- a/ai/templates/techspec.md +++ b/ai/templates/techspec.md @@ -47,7 +47,7 @@ Run `make gen` after touching `@riverpod`, `@freezed`, `@RoutePage`, or other co [Define essential data structures using project conventions: -- **DTOs** (`lib/common/data/dto/`) — wire-format models annotated with `@freezed` + `@JsonSerializable`, used by `dio` +- **DTOs** (`lib/common/data/dto/`) — wire-format models using `@freezed` with generated `fromJson` factories, used by `dio` - **Entities** (`lib/common/data/entity/`) — domain models; map from DTOs via factory or extension - **State models** — feature-scoped `@freezed` classes alongside the feature - **Events** — sealed/`@freezed` union types for user/system events feeding the state notifier diff --git a/docs/PROJECT_GUIDELINES.md b/docs/PROJECT_GUIDELINES.md index fff8ab2..d92fba6 100644 --- a/docs/PROJECT_GUIDELINES.md +++ b/docs/PROJECT_GUIDELINES.md @@ -111,7 +111,7 @@ Not every feature needs every file. Simple screens in the template only use `*_p - Repo-local skills live under `ai/skills/` and Claude Code symlinks live under `.claude/skills/`. - Skill scripts should be executable and syntax-check clean before relying on them: - `bash -n ai/skills/build-verify/scripts/verify.sh` - - `bash -n ai/skills/lint_format/scripts/lint_format.sh` + - `bash -n ai/skills/lint-format/scripts/lint-format.sh` - `sh -n ai/skills/release-builds/scripts/archive_ios_ipa.sh` - PR-related skills use GitHub CLI. Install it locally and authenticate with `gh auth login`; verify with `gh auth status`. - If `gh auth status` reports an invalid `GITHUB_TOKEN` or `GH_TOKEN`, clear or replace that environment variable so the stored GitHub CLI login can be used. From be989ebd31b9bebf495916acbff28c784076d332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Urb=C3=A1nek?= <michal.urbanek@strv.com> Date: Mon, 18 May 2026 11:11:42 +0200 Subject: [PATCH 9/9] Fix build verify format change detection --- ai/skills/build-verify/scripts/verify.sh | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/ai/skills/build-verify/scripts/verify.sh b/ai/skills/build-verify/scripts/verify.sh index 0d8344a..98c699f 100755 --- a/ai/skills/build-verify/scripts/verify.sh +++ b/ai/skills/build-verify/scripts/verify.sh @@ -242,6 +242,17 @@ DART_LOG="$LOG_DIR/dart.log" IOS_LOG="$LOG_DIR/ios.log" ANDROID_LOG="$LOG_DIR/android.log" FMT_LOG="$LOG_DIR/format.log" +FMT_BEFORE="$LOG_DIR/format-before.cksum" +FMT_AFTER="$LOG_DIR/format-after.cksum" + +snapshot_format_targets() { + for dir in lib test; do + [ -d "$dir" ] || continue + find "$dir" -type f -name '*.dart' -print + done | sort | while IFS= read -r file; do + cksum "$file" + done +} echo "=== build-verify ===" echo " flavor: $FLAVOR (entrypoint: lib/main_$FLAVOR.dart)" @@ -392,14 +403,13 @@ fi # --- Format -------------------------------------------------------------- echo "=== Format ===" -before_fmt="$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')" +snapshot_format_targets > "$FMT_BEFORE" fvm dart format lib test 2>&1 | tee "$FMT_LOG" -after_fmt="$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')" -fmt_delta=$(( after_fmt - before_fmt )) -if [ "$fmt_delta" -gt 0 ]; then - echo " [OK] Format auto-rewrote files ($fmt_delta new entries in git status). Review before committing." -else +snapshot_format_targets > "$FMT_AFTER" +if cmp -s "$FMT_BEFORE" "$FMT_AFTER"; then echo " [OK] Format produced no changes." +else + echo " [OK] Format auto-rewrote files. Review git diff/status before committing." fi total_elapsed=$(( $(date +%s) - overall_start ))