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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ systems like Buck and Bazel.
11. [Bazel adapter design](docs/BAZEL-ADAPTER.md) — target types to rules, restriction graph to visibility (F-040 design)
12. [Bazel adapter spike](bazel-adapter/README.md) — generate/check BUILD from Forma model (F-041; JVM-first)
13. [Bazel sample (experimental)](bazel-sample/) — minimal `kt_jvm_*` workspace exercising forma-core matrix + `impl` ↛ `impl` (F-042)
14. [**Progressive examples + agent skills**](docs/PROGRESSIVE-EXAMPLES.md) — feature-by-feature ladders (`examples/`) + coding-agent skills (F-050)

Configuration made easy:

Expand Down Expand Up @@ -212,6 +213,7 @@ JVM getting-started tutorial: **F-032** done ([`docs/JVM-GETTING-STARTED.md`](do
Bazel adapter mapping design (targets ↔ rules, visibility ↔ deps): **F-040** done (see [`docs/BAZEL-ADAPTER.md`](docs/BAZEL-ADAPTER.md)).
Bazel adapter spike (generate/check BUILD from portable model, JVM matrix): **F-041** done ([`bazel-adapter/`](bazel-adapter/), spike results in BAZEL-ADAPTER.md).
Minimal Bazel sample workspace (two features + library/util + binary, real `bazelisk build` + `run`): **F-042** done (see [`bazel-sample/`](bazel-sample/) + BAZEL-ADAPTER.md).
Progressive examples + agent skills (all supported features): **F-050** done ([`docs/PROGRESSIVE-EXAMPLES.md`](docs/PROGRESSIVE-EXAMPLES.md), [`examples/`](examples/)).

Icons made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a>
from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
6 changes: 6 additions & 0 deletions TICKETS.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ Update this file when picking or finishing work. Cron workers must pick the **hi
| F-041 | done | Spike: generate or check Bazel BUILD from forma declarations | `bazel-adapter/` generate+check via core RestrictionGraph; examples + tests green |
| F-042 | done | Minimal Bazel sample using forma-core concepts | `bazel-sample/` + real `bazelisk build`/`run` + docs; see PROGRESS |

## P5 — Progressive examples + agent skills

| ID | Status | Title | Notes |
|----|--------|-------|-------|
| F-050 | done | Progressive examples + agent skills for all supported features | `examples/{jvm,android}/*` + `examples/agent-skills/` + `docs/PROGRESSIVE-EXAMPLES.md`; JVM build+run and Android assembleDebug verified |

## Backlog (lower priority / historical GitHub)

Keep for reference; do not start unless higher tickets done or user prioritizes:
Expand Down
1 change: 1 addition & 0 deletions docs/GETTING-STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ Details: [COMPOSE.md](COMPOSE.md). Sample:
| [ARCHITECTURE.md](ARCHITECTURE.md) | Monorepo + plugin module graph |
| [VISION.md](VISION.md) | forma-core → JVM → Bazel roadmap |
| [JVM-GETTING-STARTED.md](JVM-GETTING-STARTED.md) | Pure JVM parallel tutorial (F-032) |
| [PROGRESSIVE-EXAMPLES.md](PROGRESSIVE-EXAMPLES.md) | Feature-by-feature ladders + agent skills (F-050) |

---

Expand Down
1 change: 1 addition & 0 deletions docs/JVM-GETTING-STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ See the Android parallel: [GETTING-STARTED.md](GETTING-STARTED.md).
| [JVM-SAMPLE.md](JVM-SAMPLE.md) | Multi-feature pure-JVM gold standard layout + run |
| [JVM-TARGETS.md](JVM-TARGETS.md) | All JVM target types + full dependency matrix |
| [GETTING-STARTED.md](GETTING-STARTED.md) | Android parallel tutorial |
| [PROGRESSIVE-EXAMPLES.md](PROGRESSIVE-EXAMPLES.md) | Feature-by-feature ladders + agent skills (F-050) |
| [DEPENDENCY-MATRIX.md](DEPENDENCY-MATRIX.md) | Full matrix (includes JVM rows) |
| [DEPS-CATALOG.md](DEPS-CATALOG.md) | External catalogs (`library`, `bundle`, `plugin`) |
| [ENV.md](ENV.md) | JDK bootstrap |
Expand Down
19 changes: 19 additions & 0 deletions docs/PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

Newest entries first.

## 2026-07-15 — F-050 Progressive examples + agent skills

- **Ticket:** F-050 → `done`
- **Branch:** `forma/F-050-progressive-examples-skills` (from `origin/v2`)
- **Skills/modes:** Grok Build `--mode full` (design + partial implement, max-turns); Hermes finish path completed Android ladder, skills, docs, verify, PR
- **Deliverable:**
- `examples/jvm/01-hello-binary` … `05-test-util` — full JVM target set progressive ladder
- `examples/android/01-hello-apk` … `09-test-utils` — full Android target set + catalogs + compose + test utils
- `examples/agent-skills/` — overview, android/jvm targets, matrix, catalogs, compose, includer, layout, bazel
- `docs/PROGRESSIVE-EXAMPLES.md` + `examples/README.md` curriculum + feature coverage matrix
- Cross-links: README, GETTING-STARTED, JVM-GETTING-STARTED
- **Verify (real host, OpenJDK 17 + `scripts/env-mac.sh`):**
- All JVM steps: `./gradlew build` + `:binary:run` → **OK**
- All Android steps: `:binary:assembleDebug` → **OK**
- Android 09: `:feature-hello-impl:testDebugUnitTest` → **OK**
- **Notes:** `deps()` is non-transitive — Compose/JUnit examples use `transitiveDeps(...)`. Teaching apps use framework `Activity` (not AppCompat) to keep transitive surface small.
- **Blockers:** none
- **Next step:** backlog / new tickets as prioritized

## 2026-07-15 — Ticket queue empty; close done GitHub issues

- **Ticket:** none open in P0–P4 (`TICKETS.md` all `done` through F-042)
Expand Down
43 changes: 43 additions & 0 deletions docs/PROGRESSIVE-EXAMPLES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Progressive examples (F-050)

Forma’s **feature-by-feature teaching ladder**. Start here after (or instead of) the
narrative tutorials when you want a **minimal buildable project per concept**.

| Audience | Start |
|----------|-------|
| Humans learning Android Forma | [examples/android/01-hello-apk](../examples/android/01-hello-apk) then climb |
| Humans learning JVM Forma | [examples/jvm/01-hello-binary](../examples/jvm/01-hello-binary) |
| Coding agents | [examples/agent-skills/](../examples/agent-skills/) |
| Full product reference | [SAMPLE-APP.md](SAMPLE-APP.md) / [JVM-SAMPLE.md](JVM-SAMPLE.md) |
| Narrative tutorials | [GETTING-STARTED.md](GETTING-STARTED.md) / [JVM-GETTING-STARTED.md](JVM-GETTING-STARTED.md) |

## Feature coverage matrix

| Feature | Android step | JVM step | Agent skill |
|---------|--------------|----------|-------------|
| Includer + composite plugins | 01 | 01 | forma-includer-settings |
| `androidProjectConfiguration` | 01 | — | forma-android-targets |
| `androidBinary` / `androidApp` | 01 | — | forma-android-targets |
| `androidRes` | 01, 03 | — | forma-android-targets |
| `binary` (JVM) | — | 01 | forma-jvm-targets |
| `api` / `impl` | 02 | 02 | platform skills + matrix |
| `viewBinding` | 03 | — | forma-android-targets |
| `library` / `util` | 04 | 03 | platform skills |
| `androidUtil` / `androidLibrary` | 04 | — | forma-android-targets |
| `widget` / `uiLibrary` | 05 | — | forma-android-targets |
| Compose + `composeWidget` | 06 | — | forma-compose |
| Multi-feature composition | 07 | 04 | forma-project-layout |
| `projectDependencies` catalogs | 08 | — | forma-deps-catalog |
| `testUtil` | 09 | 05 | platform skills |
| `androidTestUtil` | 09 | — | forma-android-targets |
| `androidNative` | skill/docs | — | forma-android-targets |
| Bazel adapter / sample | skill | skill | forma-bazel |

## Verify

See [examples/README.md](../examples/README.md).

## Relationship to gold standards

Progressive examples are **minimal**. Patterns for real apps (navigation, Dagger,
network) live in `application/` and are documented in SAMPLE-APP / GETTING-STARTED.
5 changes: 5 additions & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
**/local.properties
**/.gradle/
**/build/
**/.cxx/
**/captures/
58 changes: 58 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Forma progressive examples (F-050)

Hands-on ladders that introduce **every supported Forma feature** one step at a time.
Gold-standard product apps remain [`application/`](../application/) (Android) and
[`jvm-application/`](../jvm-application/) (JVM). These examples are **teaching-focused**.

## Curriculum

| Track | Path | Steps |
|-------|------|-------|
| JVM | [`jvm/`](jvm/) | 01 hello-binary → 05 test-util |
| Android | [`android/`](android/) | 01 hello-apk → 09 test-utils |
| Agent skills | [`agent-skills/`](agent-skills/) | SKILL docs for coding agents |
| User index | [`docs/PROGRESSIVE-EXAMPLES.md`](../docs/PROGRESSIVE-EXAMPLES.md) | narrative + feature coverage matrix |

### JVM (`tools.forma.jvm`)

| Step | Directory | Features |
|------|-----------|----------|
| 01 | `jvm/01-hello-binary` | `binary`, includer, composite plugins |
| 02 | `jvm/02-api-impl` | `api`, `impl`, composition-root listing |
| 03 | `jvm/03-library-util` | `library`, `util` |
| 04 | `jvm/04-multi-feature` | multi-feature; **impl ↛ impl** |
| 05 | `jvm/05-test-util` | `testUtil` + unit tests |

### Android (`tools.forma.android`)

| Step | Directory | Features |
|------|-----------|----------|
| 01 | `android/01-hello-apk` | `androidProjectConfiguration`, `androidBinary`, `androidApp`, `androidRes` |
| 02 | `android/02-feature-api-impl` | `api`, `impl` |
| 03 | `android/03-res-viewbinding` | feature `androidRes`, `viewBinding` |
| 04 | `android/04-shared-libs` | `library`, `util`, `androidUtil`, `androidLibrary` |
| 05 | `android/05-widget-ui` | `widget`, `uiLibrary` |
| 06 | `android/06-compose` | `compose` flags, `composeWidget` |
| 07 | `android/07-multi-feature` | two features at composition root |
| 08 | `android/08-deps-catalog` | `projectDependencies` / `library` / `bundle` / `plugin` |
| 09 | `android/09-test-utils` | `testUtil`, `androidTestUtil` (+ `androidNative` docs) |

Bazel is covered by agent skill + existing [`bazel-adapter/`](../bazel-adapter/) and [`bazel-sample/`](../bazel-sample/) (not duplicated here).

## Verify

```bash
source scripts/env-mac.sh

for d in examples/jvm/*/; do
(cd "$d" && ./gradlew build --quiet && ./gradlew :binary:run --quiet)
done

printf 'sdk.dir=%s\n' "$ANDROID_HOME" > /tmp/forma-ex-local.properties
for d in examples/android/*/; do
cp /tmp/forma-ex-local.properties "$d/local.properties"
(cd "$d" && ./gradlew :binary:assembleDebug --quiet)
done
```

Each step has its own `README.md` with the delta vs the previous step.
24 changes: 24 additions & 0 deletions examples/agent-skills/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Forma agent skills

Load these when scaffolding or reviewing Forma targets. They encode DSL, suffixes,
matrix rules, and progressive example pointers.

| Skill | When to load |
|-------|----------------|
| [forma-overview](forma-overview.md) | Any Forma work; entry map |
| [forma-android-targets](forma-android-targets.md) | Creating/editing Android targets |
| [forma-jvm-targets](forma-jvm-targets.md) | Pure JVM targets |
| [forma-dependency-matrix](forma-dependency-matrix.md) | Dependency / visibility errors |
| [forma-deps-catalog](forma-deps-catalog.md) | External deps / catalogs |
| [forma-compose](forma-compose.md) | Jetpack Compose |
| [forma-includer-settings](forma-includer-settings.md) | settings.gradle / includer / composite |
| [forma-project-layout](forma-project-layout.md) | Feature folders, packages, composition roots |
| [forma-bazel](forma-bazel.md) | Bazel adapter / sample |

**Hard rules agents must never violate**

1. `impl` must not depend on another `impl`
2. Composition roots list feature `api` **and** `impl` explicitly
3. Suffix of project name must match DSL (`…/impl` → `impl { }`)
4. `packageName` must match source root path
5. Do not weaken validators to “make it build”
55 changes: 55 additions & 0 deletions examples/agent-skills/forma-android-targets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
name: forma-android-targets
description: All Android Forma DSL targets, suffixes, content rules, and example steps.
---

# Android targets (agent skill)

Plugin: `tools.forma.android`. Register happens on first DSL use via `AndroidTargetRegistry`.

| DSL | Suffix | Content rules | Progressive step |
|-----|--------|---------------|------------------|
| `androidBinary` | `binary` | no `res/`; composition root | 01+ |
| `androidApp` | `app` | no `res/`; composition root | 01+ |
| `api` | `api` | no `res/` | 02+ |
| `impl` | `impl` | Android feature impl | 02+ |
| `androidRes` | `res` | **only** `res/` under src/main | 01, 03 |
| `viewBinding` | `viewbinding` | **only** `layout*` under res | 03 |
| `library` | `library` | pure JVM library | 04 |
| `util` | `util` | no res/ | 04 |
| `androidUtil` | `android-util` | no res/ | 04 |
| `androidLibrary` | `library` | Android lib; **no** `impl` deps | 04 |
| `widget` | `widget` | Custom View | 05 |
| `uiLibrary` | `ui-library` | shared UI blocks | 05 |
| `composeWidget` | `compose-widget` | always Compose | 06 |
| `testUtil` | `test-util` | no res/ | 09 |
| `androidTestUtil` | `android-test-util` | Android test helpers | 09 |
| `androidNative` | `native` | no res/; **no project-dep validation yet** | docs only |

## Minimal skeletons

```kotlin
androidBinary(packageName = "…", versionCode = 1, versionName = "0.1.0", dependencies = deps(target(":root-app")))
androidApp(packageName = "…", dependencies = deps("androidx.appcompat:appcompat:1.6.1") + deps(target(":root-res")))
androidRes(packageName = "…")
api(packageName = "…")
impl(packageName = "…", dependencies = deps(target(":feature:x:api")))
viewBinding(packageName = "…", dependencies = deps(target(":feature:x:res")))
widget(packageName = "…")
composeWidget(packageName = "…", dependencies = deps(/* compose GAVs */))
androidLibrary(packageName = "…")
androidUtil(packageName = "…")
util(packageName = "…")
library(packageName = "…")
testUtil(packageName = "…")
androidTestUtil(packageName = "…")
// androidNative(packageName = "…") // NDK; validators incomplete
```

## Forbidden

- `impl` → `impl`
- `api` shipping `res/`
- `androidLibrary` → `impl`
- Wrong suffix for DSL
- Relying on transitive feature wiring instead of listing api+impl on roots
16 changes: 16 additions & 0 deletions examples/agent-skills/forma-bazel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
name: forma-bazel
description: Bazel adapter generate/check and sample workspace pointers.
---

# Bazel (agent skill)

Not part of the progressive Gradle ladders. Use:

| Artifact | Path |
|----------|------|
| Design | `docs/BAZEL-ADAPTER.md` |
| Generate/check spike | `bazel-adapter/` (`./gradlew test`, `runSample`) |
| Runnable sample | `bazel-sample/` (`bazelisk build //...`, `run //binary:binary`) |

Concepts: target types → `kt_jvm_*`, restriction graph → visibility, tags `forma:type=…`, **impl ↛ impl**.
22 changes: 22 additions & 0 deletions examples/agent-skills/forma-compose.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: forma-compose
description: Compose flags and composeWidget target.
---

# Compose (agent skill)

Doc: `docs/COMPOSE.md`. Example: `examples/android/06-compose`.

```kotlin
// root
androidProjectConfiguration(..., compose = true, composeCompilerVersion = "1.5.3")

impl(..., compose = true, dependencies = transitiveDeps("androidx.compose.ui:ui:…", /* … */))
composeWidget(packageName = "…", dependencies = transitiveDeps(/* compose libs */))
androidBinary(..., compose = true, ...)
```

- Forma enables `buildFeatures.compose` + compiler extension version
- **You** still add Compose Maven artifacts
- Align compiler version with Kotlin (sample: 1.5.3 ↔ 1.9.10)
- **`deps("gav")` is non-transitive** — use `transitiveDeps(...)` for Compose (same as `androidx.compose` in `build-dependencies/`)
28 changes: 28 additions & 0 deletions examples/agent-skills/forma-dependency-matrix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: forma-dependency-matrix
description: Project-dep allowlists and how to fix validator failures.
---

# Dependency matrix (agent skill)

**Source of truth:** `docs/DEPENDENCY-MATRIX.md` (Android), `docs/JVM-TARGETS.md` (JVM).

## Dagger-friendly rules

| Consumer | May depend on (project suffixes) |
|----------|-----------------------------------|
| `api` | `api`, `library` |
| `impl` | api, utils, library, ui-library, res, viewbinding, widget, compose-widget — **not** other `impl` |
| `androidApp` / `androidBinary` | api, impl, shared UI/libs (composition roots) |
| `androidLibrary` | library, utils, res, api — **not** impl |

## Fixing failures

1. Read error: consumer suffix, illegal dep, allowed set
2. Prefer re-slice (move types to `api` / shared lib) over disabling validation
3. Composition roots must list feature entrypoints explicitly

## Progressive demos of illegal vs legal

- Legal multi-feature: `examples/android/07-multi-feature`, `examples/jvm/04-multi-feature`
- Shared libs without impl edges: `examples/android/04-shared-libs`
29 changes: 29 additions & 0 deletions examples/agent-skills/forma-deps-catalog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
name: forma-deps-catalog
description: projectDependencies catalogs — library, bundle, plugin, bare GAV.
---

# Deps catalog (agent skill)

Doc: `docs/DEPS-CATALOG.md`. Example: `examples/android/08-deps-catalog`.

```kotlin
// settings.gradle.kts
projectDependencies(
"libs",
"com.jakewharton.timber:timber:5.0.1",
library("androidx.appcompat:appcompat:1.6.1", name = "appcompat"),
bundle(name = "uiBasics", "com.google.android.material:material:1.10.0"),
plugin("androidx.navigation:navigation-safe-args-gradle-plugin", "2.7.4"),
)

// module
dependencies = deps(libs.appcompat, libs.jakewhartonTimber, libs.bundles.uiBasics)
```

External GAV strings also work in `deps("group:artifact:version")` for tiny examples.
Prefer catalogs in real apps.

## Transitivity

`deps("g:a:v")` is **non-transitive**. Use `transitiveDeps(...)` when Maven transitively is required (Compose UI, JUnit/hamcrest, AppCompat clusters).
28 changes: 28 additions & 0 deletions examples/agent-skills/forma-includer-settings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: forma-includer-settings
description: settings.gradle.kts, includer, composite includeBuild patterns.
---

# Includer & settings (agent skill)

## Composite monorepo (examples / samples)

```kotlin
pluginManagement {
repositories { google(); gradlePluginPortal(); mavenCentral() }
includeBuild("../../../plugins") // depth depends on location
includeBuild("../../../includer")
}
plugins {
id("tools.forma.includer")
id("tools.forma.android") // or tools.forma.jvm
}
includer { arbitraryBuildScriptNames = true }
```

## Rules

- Drop `build.gradle.kts` in a folder → project discovered (no manual `include`)
- Nested `settings.gradle.kts` skips that tree
- Path `feature/home/impl` → Gradle `:feature-home-impl`; Forma `target(":feature:home:impl")`
- Android root needs `androidProjectConfiguration` in root `build.gradle.kts`
Loading
Loading