Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
globs: |
**/*.md
!CHANGELOG.md
!references/ffca_architecture.md
!references/ffca/**
config: 'config/custom.markdownlint.jsonc'

spelling:
Expand Down
24 changes: 24 additions & 0 deletions .github/workflows/reference_drift.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: reference drift

# The FFCA reference under references/ffca/ is a byte mirror of the canonical
# docs on engineering.verygood.ventures. This job re-fetches them and fails when
# the committed mirror has fallen behind.
#
# It runs on a schedule rather than on pull requests on purpose: upstream can
# change at any time, and that should not fail an unrelated contributor's PR.

on:
schedule:
# Mondays at 07:00 UTC.
- cron: '0 7 * * 1'
workflow_dispatch:

jobs:
drift:
name: 📚 Reference Drift
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dart-lang/setup-dart@v1
- name: Check the mirror against upstream
run: dart run scripts/sync_reference.dart --check
31 changes: 19 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

VGV FFCA Plugin teaches Claude Code the Feature-First Clean Architecture (FFCA) for Flutter monorepos. It ships skills, one read-only auditor agent, and a PostToolUse hook that blocks pubspec edits breaking the layer rules.

The skills and the agent carry workflows only. The architecture itself lives in `references/ffca_architecture.md`, which is the single source of truth. It mirrors the canonical Notion page and is meant to be regenerated by `scripts/sync_reference.dart`. That script is still a stub, so the mirror is updated by hand from Notion for now. Never edit its content to match a skill. Change Notion, re-sync, then fix the skills that drifted.
The skills and the agent carry workflows only. The architecture itself lives in `references/ffca/`, which is the single source of truth. It is a byte mirror of the FFCA section of VGV Engineering, one file per page, regenerated by `scripts/sync_reference.dart`. Never edit its content to match a skill. Change the upstream page, re-sync, then fix the skills that drifted.

The only code is the Dart layer validator under `scripts/` and the bash hook wrapper that calls it.

Expand All @@ -23,14 +23,22 @@ hooks/
hooks.json # Hook definitions (PostToolUse)
validate_layers.sh # Runs the validator on edited pubspec.yaml files
references/
ffca_architecture.md # Mirror of the Notion FFCA page, single source of truth
ffca/ # Byte mirror of the VGV Engineering FFCA pages, single source of truth
README.md # Manifest: which upstream page each file mirrors
overview.md # Goals, three-part structure, feature archetypes, layer model
domain.md # Models, Commands and Queries, repository interfaces, Summary pattern
data.md # Data sources, DTOs, converters and mappers
presentation.md # Modules, localizations, widget slots, subfeature barrels
navigation.md # Callback injection, typed routes, splitting the routing table
project_structure.md # Dependency rules, naming, folder layout, tooling
faq.md # Frequently asked questions
code_templates/
data_templates.md # DTO, data source, mapper, repository implementation shapes
domain_templates.md # Model, repository interface, use case shapes
domain_templates.md # Model, repository interface, Command and Query shapes
presentation_templates.md # Cubit, Module, route shapes
scripts/
pubspec.yaml # Dev dependency on package:test for the validator tests
sync_reference.dart # Regenerates references/ffca_architecture.md from Notion (stub)
sync_reference.dart # Regenerates references/ffca/ from VGV Engineering, --check for drift
validate_layers.dart # FFCA layer, naming, and cycle validator
test/
validate_layers_test.dart # Validator tests
Expand All @@ -41,7 +49,7 @@ scripts/
skills/
ffca-architecture/SKILL.md # Orientation, layer rules, naming
ffca-audit/SKILL.md # Dispatches ffca-layer-auditor
ffca-cross-feature/SKILL.md # Summary pattern, use cases, composing features
ffca-cross-feature/SKILL.md # Summary pattern, Queries, widget slots, composing features
ffca-feature/SKILL.md # Scaffold and extend a feature
ffca-routing/SKILL.md # Callback injection, typed routes
```
Expand All @@ -52,17 +60,16 @@ Every `SKILL.md` follows this structure:

1. **YAML frontmatter** with these fields:
- `name`: required. Must match the skill's folder name exactly, lowercase letters, numbers, and hyphens only, prefixed `ffca-`.
- `description`: required. One line on what the skill covers.
- `when_to_use`: required here. The trigger phrases and situations that should activate the skill.
- `description`: required. What the skill covers, when to use it, the trigger phrases that should activate it, and the deferral to `layered-architecture` for non-FFCA repos.
- `allowed-tools`: space-separated list of tools the skill may use, for example `Read Glob Grep`. Read-only skills stop there. Skills that write code add `Write Edit`, and MCP tools use their full name, for example `mcp__very_good_cli__create`.
- `effort`: reasoning effort while the skill is active. Every skill here sets `high`.
2. **H1 title**, the human-readable skill name.
3. **A short purpose paragraph**, then numbered workflow steps.
4. **Citations** into `references/ffca_architecture.md` by section name, and into `references/code_templates/` for code shapes.
4. **Citations** into `references/ffca/` by file and section name, and into `references/code_templates/` for code shapes.

## Writing Conventions

- Do not restate architecture rules inside a skill. Cite the section of `references/ffca_architecture.md` by its heading so the reference stays the only place a rule is written.
- Do not restate architecture rules inside a skill. Cite the file and section of `references/ffca/` by its heading so the reference stays the only place a rule is written.
- Frame standards as clear directives. No soft language like "consider" or "prefer".
- Use fenced code blocks with language identifiers for all examples.
- Reference packages by full name, for example `package:go_router_builder`.
Expand Down Expand Up @@ -94,15 +101,15 @@ Agents live in `agents/<name>.md` and are auto-discovered. No `plugin.json` chan

Documentation drifts when an asset changes and the docs describing it do not. Update the matching docs in the same change:

- **The FFCA architecture changes.** Update Notion first, then re-sync `references/ffca_architecture.md`. Check every skill, the agent, and the code templates for section names that moved or rules that changed. If a dependency rule changed, update the rules table at the top of `scripts/validate_layers.dart` and its tests.
- **A skill's scope or triggers change.** Update `description` and `when_to_use`, and the matching row in the `README.md` Skills table.
- **The FFCA architecture changes.** Update the VGV Engineering page first, then run `dart run scripts/sync_reference.dart` to re-sync `references/ffca/`. Check every skill, the agent, and the code templates for section names that moved or rules that changed. If a dependency rule changed, update the rules table at the top of `scripts/validate_layers.dart` and its tests.
- **A skill's scope or triggers change.** Update `description` and the matching row in the `README.md` Skills table.
- **The validator's rules or flags change.** Update `scripts/test/validate_layers_test.dart` and its fixtures, the **Hook** section of `README.md`, and the `## Hooks` section of `CLAUDE.md` if the hook's behavior changes.
- **A hook changes in `hooks/hooks.json`.** Update the **Hook** section of `README.md` and the `## Hooks` section of `CLAUDE.md`.
- **An MCP tool is added, renamed, or removed.** Check every skill's `allowed-tools`. Nothing validates those names.

## Checks

CI runs markdownlint with `config/custom.markdownlint.jsonc`, cspell with `config/cspell.json`, the validator's analyze, format, and tests from `scripts/`, skills lint on `skills/`, and `claude plugin validate .`. `CHANGELOG.md` and `references/ffca_architecture.md` are excluded from markdownlint.
CI runs markdownlint with `config/custom.markdownlint.jsonc`, cspell with `config/cspell.json`, the validator's analyze, format, and tests from `scripts/`, skills lint on `skills/`, and `claude plugin validate .`. `CHANGELOG.md` and `references/ffca/` are excluded from markdownlint. A weekly `reference_drift` workflow runs `sync_reference.dart --check` and fails when the mirror is stale.

## Commits

Expand Down
15 changes: 7 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ First of all, thank you for taking the time to contribute! 🎉👍 Before you d
| ------------ | ----- |
| **New skill** | `skills/<skill-name>/SKILL.md` |
| **Improve an existing skill** | Edit the relevant `skills/*/SKILL.md` |
| **Architecture conventions** | `references/ffca_architecture.md` |
| **Architecture conventions** | Upstream on VGV Engineering, then `dart run scripts/sync_reference.dart` to refresh `references/ffca/` |
| **Layer validator** | `scripts/validate_layers.dart` and `scripts/test/` |
| **Hook** | `hooks/` directory |
| **Agent** | `agents/` directory |
Expand All @@ -29,17 +29,16 @@ Create `skills/<skill-name>/SKILL.md`. The file must begin with YAML frontmatter
```yaml
---
name: <skill-name>
description: What the skill does, in one sentence.
when_to_use: When this skill should be triggered. Be specific.
description: >
What the skill covers, then when to use it and the trigger phrases, scoped to FFCA repos.
allowed-tools: Read Glob Grep
---
```

| Field | Required | Rules |
| ----- | -------- | ----- |
| `name` | Yes | Lowercase letters, numbers, and hyphens only. Must match the skill's directory name. Prefix FFCA skills with `ffca-` |
| `description` | Yes | What the skill covers |
| `when_to_use` | Yes | The trigger phrases and scope. Self-scope to FFCA repos so the skill does not fire in a layered repo |
| `description` | Yes | What the skill covers, when to use it, and the trigger phrases. Self-scope to FFCA repos so the skill does not fire in a layered repo, and defer to `layered-architecture` otherwise |
| `allowed-tools` | No | Space-separated list of tools the skill may use |
| `effort` | No | Reasoning effort hint, for example `high` for the audit skill |

Expand All @@ -59,7 +58,7 @@ Add a row to the skills table in `README.md` and to the list of slash commands b

## Skill Writing Guidelines

- **Point into the reference, do not restate it.** The conventions live in `references/ffca_architecture.md`. Link to the section by name so the architecture keeps one source of truth.
- **Point into the reference, do not restate it.** The conventions live in `references/ffca/`. Link to the file and section by name so the architecture keeps one source of truth.
- **Use clear directives.** No soft language like "consider" or "prefer". Say "Use X" or "Do not use Y".
- **Fence all code blocks** with language identifiers, for example ` ```dart `.
- **Reference packages by full name**, for example `package:go_router_builder`.
Expand Down Expand Up @@ -127,8 +126,8 @@ Every pull request runs the following checks from `.github/workflows/ci.yaml`:

| Check | What it does | Config |
| ----- | ------------ | ------ |
| Markdown Quality | Lints all `*.md` files with markdownlint-cli2, except `CHANGELOG.md` and `references/ffca_architecture.md` | `config/custom.markdownlint.jsonc` |
| Spelling Check | Runs cspell on all `*.md` files except `CHANGELOG.md` | `config/cspell.json` |
| Markdown Quality | Lints all `*.md` files with markdownlint-cli2, except `CHANGELOG.md` and `references/ffca/` | `config/custom.markdownlint.jsonc` |
| Spelling Check | Runs cspell on all `*.md`, `*.yml`, and `*.yaml` files except `CHANGELOG.md` | `config/cspell.json` |
| Layer Validator | Runs `dart analyze --fatal-infos`, `dart format --set-exit-if-changed`, and `dart test` in `scripts/` | `scripts/pubspec.yaml` |
| Skills Lint | Validates every `SKILL.md` in `skills/` | Very Good Workflows `skills_lint` |
| Plugin Validation | Validates the plugin | `claude plugin validate .` |
Expand Down
37 changes: 30 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# VGV FFCA Plugin

A [Claude Code](https://claude.com/claude-code) plugin that operationalizes Feature-First Clean Architecture (FFCA) for Flutter monorepos.
A [Claude Code](https://claude.com/claude-code) plugin that operationalizes [Feature-First Clean Architecture (FFCA)](https://engineering.verygood.ventures/architecture/ffca/overview/) for Flutter monorepos.

Developed with 💙 by [Very Good Ventures](https://verygood.ventures) 🦄

Expand All @@ -12,7 +12,30 @@ VGV FFCA Plugin teaches Claude the Feature-First Clean Architecture conventions
- **A blocking validation hook** that runs on every `pubspec.yaml` edit and stops the edit when it breaks a layer dependency rule, with the rule and the fix in the message so Claude self-corrects.
- **An MCP configuration** that wires the Very Good CLI server for project and package operations.

The conventions themselves live in a single reference, `references/ffca_architecture.md`, mirrored from the canonical Notion page. The skills never restate the conventions: they point into the reference by section name, so the architecture has exactly one source of truth.
The conventions themselves live in `references/ffca/`, a byte mirror of the canonical FFCA documentation on [VGV Engineering](https://engineering.verygood.ventures/architecture/ffca/overview/), regenerated by `scripts/sync_reference.dart`. The skills never restate the conventions: they point into the mirror by file and section, so the architecture has exactly one source of truth.

## The architecture reference

`references/ffca/` holds one file per page of the canonical documentation, fetched verbatim from the [FFCA section of VGV Engineering](https://engineering.verygood.ventures/architecture/ffca/overview/):

| File | Covers |
| --- | --- |
| `overview.md` | Goals, the three-part structure, feature archetypes, shared libraries, the layer model |
| `domain.md` | Models, Commands and Queries, repository interfaces, composing features, the Summary pattern |
| `data.md` | Data sources, DTOs, converters and mappers |
| `presentation.md` | Modules, localizations, widgets that own state, widget slots, subfeature barrels |
| `navigation.md` | Callback injection, typed routes, splitting the routing table, deep links |
| `project_structure.md` | Dependency rules, deferred loading, naming, folder layout, tooling, add-to-app |
| `faq.md` | Callable classes, auth and user profiles, one big OpenAPI spec, nested objects |

Do not edit these by hand. Fix the architecture at the source, then sync:

```bash
dart run scripts/sync_reference.dart # rewrite the mirror
dart run scripts/sync_reference.dart --check # fail if it is stale
```

A scheduled [workflow](.github/workflows/reference_drift.yaml) runs `--check` weekly, so the mirror cannot quietly fall behind upstream.

## The stack

Expand Down Expand Up @@ -74,9 +97,9 @@ cd scripts && dart test
| Skill | Description |
| --- | --- |
| [**FFCA Architecture**](skills/ffca-architecture/SKILL.md) | Orientation: where code lives across `apps/`, `features/`, `shared/`, the naming conventions, the layer dependency rules, and the anti-patterns to reject |
| [**FFCA Feature**](skills/ffca-feature/SKILL.md) | Scaffold and extend a feature: the three-package domain, data, and presentation structure, models, repositories, use cases, DTOs, mappers, Cubits, and Modules |
| [**FFCA Routing**](skills/ffca-routing/SKILL.md) | Navigation: callback injection, `go_router_builder` typed routes, the `$extra` hydration pattern, and the feature-isolation constraints |
| [**FFCA Cross-Feature**](skills/ffca-cross-feature/SKILL.md) | Coupling features: domain-to-domain dependencies, the Summary pattern, use cases that combine repositories, and composing features |
| [**FFCA Feature**](skills/ffca-feature/SKILL.md) | Scaffold and extend a feature: the three-package domain, data, and presentation structure, headless and presentation-only features, models, repositories, Commands and Queries, DTOs, mappers, Cubits, and Modules |
| [**FFCA Routing**](skills/ffca-routing/SKILL.md) | Navigation: callback injection, `go_router_builder` typed routes, splitting the routing table, deferred imports, the `$extra` hydration pattern, and the feature-isolation constraints |
| [**FFCA Cross-Feature**](skills/ffca-cross-feature/SKILL.md) | Coupling features: domain-to-domain dependencies, the Summary pattern, Queries that combine repositories, sharing widgets, widget slots, and composing features |
| [**FFCA Audit**](skills/ffca-audit/SKILL.md) | Whole-repo health check: dispatches the `ffca-layer-auditor` agent, which runs the mechanical layer, naming, and cycle checks plus a qualitative review and returns a per-package verdict table |

Skills activate automatically when Claude detects an FFCA repo or an FFCA-shaped question. You can also invoke them directly:
Expand Down Expand Up @@ -112,10 +135,10 @@ dart run scripts/validate_layers.dart --all

| Agent | Behavior |
| --- | --- |
| [**ffca-layer-auditor**](agents/ffca-layer-auditor.md) | Read-only architecture auditor. Runs the validator in `--all` mode, then adds source-level checks (declared-but-unused dependencies, barrel hygiene, DTO leakage, use-case necessity, module entry, misplaced packages, high fan-in) and returns a per-package verdict table. Reports violations, never auto-fixes |
| [**ffca-layer-auditor**](agents/ffca-layer-auditor.md) | Read-only architecture auditor. Runs the validator in `--all` mode, then adds source-level checks (declared-but-unused dependencies, barrel hygiene, DTO leakage, Command/Query necessity, module entry, split routing tables, deferred-loading reachability, misplaced packages, high fan-in) and returns a per-package verdict table. Reports violations, never auto-fixes |

The auditor runs in its own context, so the same architecture review can be dispatched from the `ffca-audit` skill, a refactor, or a pre-PR flow without crowding the main conversation. The per-edit hook prevents bad pubspec dependencies as they are written; the agent answers whether the whole repo is healthy on demand.

## How it fits together

The hook keeps individual pubspec edits compliant. The skills teach the conventions and workflows. The `ffca-layer-auditor` agent answers whether the whole repo is healthy, on demand and reusable across flows. All of them read from the same `references/ffca_architecture.md`, so when the architecture evolves, the reference is the only file that changes.
The hook keeps individual pubspec edits compliant. The skills teach the conventions and workflows. The `ffca-layer-auditor` agent answers whether the whole repo is healthy, on demand and reusable across flows. All of them read from the same `references/ffca/` mirror, so when the architecture evolves, a sync is the only change.
Loading
Loading