From c940c863f15a46b362bb623af73fa11afecbdde4 Mon Sep 17 00:00:00 2001 From: Matt de Courcelle Date: Mon, 22 Jun 2026 21:59:17 -0500 Subject: [PATCH 1/2] docs: standardized CLAUDE.md + AGENTS.md (org guide refresh) Per the locked org templates: durable conventions + pointers, no volatile state; mandatory Dependencies and boundaries section; CLAUDE.md for Claude Code, AGENTS.md command-first for Codex. Co-Authored-By: Claude Opus 4.8 (1M context) --- AGENTS.md | 174 ++++++++++++++++++++++-------------------------------- CLAUDE.md | 84 ++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 104 deletions(-) create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md index 5eab542c..d85b42de 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,104 +1,70 @@ -# Ash UI Agent Guide - -Use this guide for repository-wide work. The package-local Spec Led Development -workspace in `.spec/` is the current-truth source for intent, requirements, and -verification targets. - -## First Read - -1. Read `.spec/README.md`. -2. Read `.spec/AGENTS.md` before editing `.spec/`. -3. Read the subject specs under `.spec/specs/` that match the files you are - changing. -4. Read `README.md` for the public package shape. -5. For example-suite work, also read `examples/README.md`, - `examples/scaffold_contract.md`, and `examples/ash_hq_theme_baseline.md`. - -## Project Shape - -- Ash UI is resource-first. Screen and element Ash resources using - `AshUI.Resource.DSL.Screen` and `AshUI.Resource.DSL.Element` are the - authoritative authoring units. -- `AshUI.Resource.Authority` derives and persists the `Screen.unified_dsl` - snapshot from the resource graph. Do not ask applications to hand-author - runtime snapshots when resource authority can produce them. -- Relationships define UI composition. Preserve relationship order, kind, slot, - placement, inline fragments, and screen-scoped bindings. -- `AshUI.Compiler` compiles persisted screens and resource-authority payloads to - `AshUI.Compilation.IUR`; `AshUI.Rendering.IURAdapter` converts internal IUR to - `%UnifiedIUR.Element{}` canonical renderer-facing IUR. -- Navigation intent is semantic and host-independent. Resource-authored - `navigation` declarations may use symbolic screens, destinations, modals, - params, metadata, payload mappings, and binding refs, but must not include - route/path/URL/helper/module/runtime stack fields. -- Styling intent is semantic. Resources may declare class hooks, variants, - renderer-read props, and dynamic inline style values; host apps own concrete - theme tokens, CSS, shell treatment, and responsive layout. -- Runtime work is actor-aware. Binding evaluation, LiveView events, screen - mounts, actions, and resource access must pass through the authorization and - policy surfaces when applicable. -- Legacy builder/document support is migration-only. Do not reopen builder-first - or document-first payloads as supported runtime compiler inputs. - -## Spec Led Workflow - -- At session start, try `mix spec.prime --base HEAD`. -- After code, docs, or tests change, try `mix spec.next`; use - `mix spec.next --bugfix` for bug fixes. -- If `mix spec.next` reports subject updates, update the named - `.spec/specs/*.spec.md` file before finishing. -- When the spec loop says ready, run `mix spec.check --base HEAD` or the base - requested by the task. -- In this checkout, the `spec.*` Mix tasks may not be wired into `mix.exs`. If a - spec task is unavailable, record that fact in your handoff and run the - closest targeted verification from the relevant spec instead. -- Keep `.spec` files as current-state documents. Use Git history and PRs for the - change log. - -## Implementation Rules - -- Prefer existing `AshUI.Resource.DSL.*`, `AshUI.Resource.Info`, - `AshUI.Resource.Authority`, `AshUI.Config`, runtime, compiler, rendering, and - telemetry modules over new parallel abstractions. -- Keep storage boundaries configurable through `AshUI.Config`; do not hard-code - the default domain, resources, repo, or runtime domain into shared logic. -- Keep bindings typed as value, list, or action flows with structured source - maps and explicit targets. Preserve transform, bidirectional write, list - paging/update, and action execution semantics. -- Preserve renderer selection semantics: registry availability is not the same - as adapter fallback renderability. -- Preserve canonical navigation transport. Use `AshUI.Navigation.Intent`, - `AshUI.Rendering.CanonicalIUR`, and `AshUI.Runtime.Navigation` instead of - adding route-specific or renderer-specific navigation fields to resources. -- Emit or preserve canonical `ash_ui` telemetry events for authoring, screen, - binding, compilation, rendering, authorization, and migration flows when those - paths change. -- Return structured errors for authorization, compilation, binding, rendering, - and LiveView runtime failures rather than crashing sessions. - -## Example Suite Rules - -- Every checked-in example under `examples//` is a standalone Mix - project. -- Preserve sibling `unified_ui/examples` directory names as stable review - handles, even when Ash UI normalizes the canonical subject type. -- Author examples as one screen resource plus related element resources, with - app-local UI storage resources and persistence through - `AshUI.Resource.Authority.create/2`. -- Keep the shared Ash HQ baseline in sync across `examples/ash_hq_theme_*` and - app-local shell hooks. -- Every example must expose a reviewer-visible Meaningful Interaction Story and - Canonical Signal Preview. - -## Verification - -- Use the exact targeted `mix test ...` commands listed in the relevant - `.spec/specs/*.spec.md` verification block when behavior changes. -- Useful root commands include `mix test`, `mix format --check-formatted`, - `mix ash_ui.examples.validate`, `mix ash_ui.examples.report`, and - `bash ./scripts/validate_specs_governance.sh`. -- For example review workflows, use `mix ash_ui.examples.list`, - `mix ash_ui.examples.preview `, and - `mix ash_ui.examples.start --dry-run`. -- Treat generated `_build/`, `deps/`, tutorial dependency, and report artifacts - as unrelated unless the task explicitly targets them. +# ash_ui + +> Resource-backed UI framework on Ash: Screen/Element/Binding Ash resources (via `AshUI.Resource.DSL.*`) are the authoritative authoring units, compiled to a canonical IUR that renders across LiveView / Elm / desktop. Co-maintained with Pascal (jallum). Plan/spec: [`.spec/specs/package.spec.md`](.spec/specs/package.spec.md). + + + +## Stack + +Elixir 1.19.5-otp-28 / Erlang 28.3.1 (`.tool-versions`). Ash `~> 3.0`, AshPostgres `~> 2.0`, Phoenix LiveView `~> 1.0`, telemetry. Vendored path-dep packages: `packages/{unified_ui,unified_iur,live_ui,elm_ui,desktop_ui}`. + +## Setup + +```bash +mix deps.get # resolves vendored packages/ path-deps +mix compile +``` + +## Build / test / lint + +```bash +mix compile +mix test # full suite +mix test test/foo_test.exs # single file +mix test test/foo_test.exs:42 # single test by line +mix format --check-formatted +mix credo --strict +mix dialyzer # uses .dialyzer_ignore.exs + +# Done = run this gate: +mix format --check-formatted && mix credo --strict && mix dialyzer && mix test +``` + +Example suite: `mix ash_ui.examples.{list,validate,report}`, `mix ash_ui.examples.preview `, `mix ash_ui.examples.start --dry-run`. Governance: `bash ./scripts/validate_specs_governance.sh`. Coverage threshold 90%. + +## Layout + +- `lib/ash_ui/{resource,compiler,rendering,navigation,authorization,runtime,telemetry}` — core pipeline. +- `lib/ash_ui/authoring/` — legacy builder/document, migration-only. +- `packages/` — vendored unified_ui sibling packages (renderer + widget grammar). +- `examples//` — standalone Mix apps; names mirror `unified_ui/examples`. +- `.spec/` — current-truth spec workspace; read `.spec/AGENTS.md` before editing it. + +## Dependencies & boundaries (MANDATORY) + +- **Upstream:** Ash / AshPostgres / Phoenix LiveView + its own vendored `packages/` path-deps. No Metagraph-engine dependency. +- **Downstream:** `ariston-ui` path-deps `:ash_ui` (renderer packages come transitively). Contract = the `AshUI.Resource.DSL.*` authoring API + canonical `%UnifiedIUR.Element{}` IUR. +- **Renderer seam:** internal `AshUI.Compilation.IUR` is private; public contract is canonical `%UnifiedIUR.Element{}` via `AshUI.Rendering.IURAdapter`. +- **Navigation = semantic only:** symbolic screens/destinations/modals/params/payload-maps/binding-refs. NEVER route/path/URL/helper/module/runtime-stack fields — host owns routes. +- **Styling = semantic only:** class hooks, variants, renderer-read props, dynamic inline values. Host owns theme tokens/CSS/shell/layout. + +## Conventions / boundaries + +- Resource-first authoring is authoritative; do NOT hand-author runtime `unified_dsl` snapshots when `AshUI.Resource.Authority` can derive them. +- Legacy builder/document payloads are migration-only — do NOT reopen as runtime compiler inputs. +- Keep storage boundaries configurable via `AshUI.Config`; do NOT hard-code default domain/resources/repo. +- Return structured errors (auth/compilation/binding/rendering/LiveView); do NOT crash sessions. +- Spec-led: update the matching `.spec/specs/*.spec.md` when behavior changes; `.spec` is current-state, not a changelog. +- Branch `codex/`; commit body = WHY; trailer `Co-Authored-By: Codex`. One reviewable arc per PR. + +## Codex + +- Review/self-check with `codex exec --profile deep-review`; sandbox + approval per `~/.codex/config.toml`. +- Never touch or echo secrets. +- `spec.*` tasks (from `spec_led_ex`) may not be wired in every checkout (only `format` is in `mix.exs` aliases). If unavailable, note it and run the targeted `mix test ...` from the relevant spec's verification block. + +## Pointers + +- Spec/ADRs: `.spec/specs/package.spec.md`, `.spec/decisions/`; public shape: `README.md`; examples: `examples/README.md`. +- Open work: `gh pr list --repo The-Metagraph/ash_ui`. +- Workspace core: `~/.codex/AGENTS.md`. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..0ff217da --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,84 @@ +# ash_ui + +Ash UI is a resource-backed UI framework for Elixir built on Ash: Screen, Element, and Binding Ash resources (via `AshUI.Resource.DSL.*`) are the authoritative authoring units, compiled to a canonical IUR that renders across LiveView / Elm / desktop targets. Canonical spec: [`.spec/specs/package.spec.md`](.spec/specs/package.spec.md); public shape: [`README.md`](README.md). + + + +## Quick start + +```bash +mix deps.get # resolves path-dep packages under packages/ +mix compile + +mix test # full suite +mix test test/path/to/some_test.exs # one file +mix test test/path/to/some_test.exs:42 # one test by line + +# quality gate (what mix.exs actually wires) +mix format --check-formatted +mix credo --strict +mix dialyzer # uses .dialyzer_ignore.exs +mix test +``` + +Coverage threshold is 90% (`MIX_TEST_COVERAGE_THRESHOLD` overrides). Example-suite tasks: `mix ash_ui.examples.list`, `mix ash_ui.examples.preview `, `mix ash_ui.examples.start --dry-run`, `mix ash_ui.examples.validate`, `mix ash_ui.examples.report`. Governance check: `bash ./scripts/validate_specs_governance.sh`. + +## Architecture + +ash_ui is the **declarative UI layer** in the Metagraph dependency tree. It has no upstream Metagraph dependency — it stands on Ash 3.x / AshPostgres / Phoenix LiveView. It **vendors `unified_ui` packages internally** as path-deps (`packages/{unified_ui,unified_iur,live_ui,elm_ui,desktop_ui}`) which own the shared widget/layout grammar and multi-target renderers. Downstream, `ariston-ui` path-deps `:ash_ui` (only `:ash_ui` is declared in its `mix.exs`; the renderer packages come transitively). + +Authoring → runtime pipeline: + +- Ash resources using `AshUI.Resource.DSL.Screen` / `.Element` are the authoring surface; relationships + `ui_relationships` define composition; `ui_bindings` / `ui_actions` define runtime behavior. +- `AshUI.Resource.Authority` derives and persists the `Screen.unified_dsl` snapshot from the resource graph. +- `AshUI.Compiler` compiles persisted screens + authority payloads to `AshUI.Compilation.IUR`. +- `AshUI.Rendering.IURAdapter` converts internal IUR to `%UnifiedIUR.Element{}` canonical renderer-facing IUR. +- LiveView mount/event/update helpers + runtime authorization policies drive the live surface. + +Non-obvious dirs: `packages/` (vendored unified_ui sibling packages — own grammar, do not duplicate in `lib/`); `examples/` (standalone Mix apps, directory names mirror `unified_ui/examples` for catalog-stable review); `lib/ash_ui/{compiler,rendering,navigation,authorization,telemetry}`; `lib/ash_ui/authoring/` (legacy builder/document — migration-only). + +## Dependencies & boundaries (MANDATORY) + +- **Consumes (upstream):** Ash `~> 3.0`, AshPostgres `~> 2.0`, Phoenix LiveView `~> 1.0`, plus its own vendored path-dep packages `packages/{unified_ui,unified_iur,live_ui,elm_ui,desktop_ui}`. No Metagraph-engine dependency. +- **Consumed by (downstream):** `ariston-ui` path-deps `:ash_ui` as its canonical UI layer. The contract is the **Ash `AshUI.Resource.DSL.*` authoring API + the canonical `%UnifiedIUR.Element{}` IUR** produced by the compiler/adapter. Breaking either ripples into ariston-ui. +- **Contract at the renderer seam:** internal `AshUI.Compilation.IUR` is private; the **public renderer-facing contract is canonical `%UnifiedIUR.Element{}`** via `AshUI.Rendering.IURAdapter`. Renderer packages consume canonical IUR, not internal IUR. +- **Navigation is semantic/host-independent:** resource `navigation` may use symbolic screens, destinations, modals, params, payload mappings, binding refs — but **never route/path/URL/helper/module/runtime-stack fields**. Host apps own concrete routes. +- **Styling is semantic:** resources declare class hooks, variants, renderer-read props, dynamic inline style values; host apps own concrete theme tokens, CSS, shell, responsive layout. + +## Hard rules (reverted if violated) + +- **Resource-first authoring.** Screen/element Ash resources are authoritative; do not ask apps to hand-author runtime `unified_dsl` snapshots when `AshUI.Resource.Authority` can derive them. +- **Legacy builder/document support is migration-only.** Do not reopen builder-first or document-first payloads as supported runtime compiler inputs (`lib/ash_ui/authoring/`). +- **No route/path/renderer-specific fields on resources.** Navigation transport goes through `AshUI.Navigation.Intent`, `AshUI.Rendering.CanonicalIUR`, `AshUI.Runtime.Navigation`. +- **Storage boundaries stay configurable** through `AshUI.Config` — do not hard-code the default domain, resources, repo, or runtime domain into shared logic. +- **Runtime is actor-aware.** Binding evaluation, LiveView events, screen mounts, and resource access pass through authorization/policy surfaces; return structured errors rather than crashing sessions. +- **Co-maintained repo.** This is jointly maintained with Pascal (jallum) as architect. Breaking-change discipline, release notes, and issue-triage obligations apply; respect existing `.spec/` and README conventions. + +## Conventions + +- Branch `claude/` (Claude) or `codex/` (Codex). One reviewable arc per PR. +- Commit subject is descriptive; the body explains WHY, not WHAT. +- **Spec-led.** `.spec/` is current-truth. Update the matching `.spec/specs/*.spec.md` subject when behavior changes. `.spec` files are current-state documents — use git history/PRs for the change log. +- Emit/preserve canonical `ash_ui` telemetry events for authoring, screen, binding, compilation, rendering, authorization, and migration flows when those paths change. +- Prefer existing `AshUI.Resource.DSL.*`, `AshUI.Resource.Info`, `AshUI.Resource.Authority`, `AshUI.Config`, compiler/rendering/runtime/telemetry modules over new parallel abstractions. + +## Claude Code specifics + +- **Spec-led loop:** `mix spec.prime --base HEAD` at session start, `mix spec.next` after changes, `mix spec.check --base HEAD` when ready. NOTE: the `spec.*` tasks come from `spec_led_ex` and may not be wired in every checkout (only `format` is in `mix.exs` aliases). If a spec task is unavailable, record that in the handoff and run the closest targeted `mix test ...` from the relevant spec's verification block instead. +- **`widget` skill** applies when adding/reviewing widgets for AshUI / Unified UI / Live UI / Elm UI / Desktop UI, and when deciding canonical-widget vs `custom:*` application extension. Load it for any widget work. +- **Orchestration:** in cross-repo waves, the umbrella session runs orchestrator-conductor; sub-agents implement. For ariston-ui-adjacent ash_ui work the default split is Codex implements / Opus reviews. +- First read: `.spec/README.md`, then `.spec/AGENTS.md` before editing `.spec/`, then the subject specs matching your files, then `README.md`. For example work: `examples/README.md`, `examples/scaffold_contract.md`, `examples/ash_hq_theme_baseline.md`. + +## Gotchas + +- `packages/` are real path-deps vendored in-repo; `mix deps.get` resolves them locally. Changes there are renderer/grammar changes — review the seam contract. +- Example apps under `examples//` are **standalone Mix projects**; treat their `_build/`, `deps/`, and reports as unrelated unless the task targets them. +- Canonical type normalization in the example suite intentionally diverges from upstream authoring (`text_input -> input`, `radio_group -> radio`, `toggle -> switch`, `separator -> divider`); directory parity with `unified_ui/examples` is stable even when the canonical subject is normalized. +- Worktree + Phoenix `priv/` build-time path resolution: a worktree's rebuilt assets can be served stale by a server running from the main checkout (`_build/` symlink). Rebuild against the merged checkout to preview. + +## Pointers (live, NOT inlined) + +- Canonical spec: [`.spec/specs/package.spec.md`](.spec/specs/package.spec.md); ADRs: [`.spec/decisions/`](.spec/decisions/); public shape: [`README.md`](README.md). +- Example suite: [`examples/README.md`](examples/README.md). +- Open work: `gh pr list --repo The-Metagraph/ash_ui`. +- Workspace conventions and the full dependency tree: [`../CLAUDE.md`](../CLAUDE.md). From a1d61c8f77d35337de9c2e2e694c876da8283a94 Mon Sep 17 00:00:00 2001 From: Matt de Courcelle Date: Mon, 22 Jun 2026 22:12:38 -0500 Subject: [PATCH 2/2] docs: fix CLAUDE.md + AGENTS.md per review (re-grounded in real code) Co-Authored-By: Claude Opus 4.8 (1M context) --- AGENTS.md | 27 ++++++--------------------- CLAUDE.md | 3 ++- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index d85b42de..e1048ab3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # ash_ui -> Resource-backed UI framework on Ash: Screen/Element/Binding Ash resources (via `AshUI.Resource.DSL.*`) are the authoritative authoring units, compiled to a canonical IUR that renders across LiveView / Elm / desktop. Co-maintained with Pascal (jallum). Plan/spec: [`.spec/specs/package.spec.md`](.spec/specs/package.spec.md). +> Resource-backed UI framework on Ash: Screen/Element/Binding Ash resources (via `AshUI.Resource.DSL.*`) are the authoritative authoring units, compiled to a canonical IUR that renders across LiveView / Elm / desktop. Co-maintained with Pascal (pcharbon70). Plan/spec: [`.spec/specs/package.spec.md`](.spec/specs/package.spec.md). @@ -40,28 +40,13 @@ Example suite: `mix ash_ui.examples.{list,validate,report}`, `mix ash_ui.example - `examples//` — standalone Mix apps; names mirror `unified_ui/examples`. - `.spec/` — current-truth spec workspace; read `.spec/AGENTS.md` before editing it. -## Dependencies & boundaries (MANDATORY) +## Boundaries (MANDATORY) -- **Upstream:** Ash / AshPostgres / Phoenix LiveView + its own vendored `packages/` path-deps. No Metagraph-engine dependency. -- **Downstream:** `ariston-ui` path-deps `:ash_ui` (renderer packages come transitively). Contract = the `AshUI.Resource.DSL.*` authoring API + canonical `%UnifiedIUR.Element{}` IUR. +- **Upstream:** Ash / AshPostgres / Phoenix LiveView + vendored `packages/` path-deps. No Metagraph-engine dependency. **Downstream:** `ariston-ui` path-deps `:ash_ui` (renderer packages transitive); contract = `AshUI.Resource.DSL.*` authoring API + canonical `%UnifiedIUR.Element{}` IUR. - **Renderer seam:** internal `AshUI.Compilation.IUR` is private; public contract is canonical `%UnifiedIUR.Element{}` via `AshUI.Rendering.IURAdapter`. -- **Navigation = semantic only:** symbolic screens/destinations/modals/params/payload-maps/binding-refs. NEVER route/path/URL/helper/module/runtime-stack fields — host owns routes. -- **Styling = semantic only:** class hooks, variants, renderer-read props, dynamic inline values. Host owns theme tokens/CSS/shell/layout. - -## Conventions / boundaries - -- Resource-first authoring is authoritative; do NOT hand-author runtime `unified_dsl` snapshots when `AshUI.Resource.Authority` can derive them. -- Legacy builder/document payloads are migration-only — do NOT reopen as runtime compiler inputs. -- Keep storage boundaries configurable via `AshUI.Config`; do NOT hard-code default domain/resources/repo. -- Return structured errors (auth/compilation/binding/rendering/LiveView); do NOT crash sessions. -- Spec-led: update the matching `.spec/specs/*.spec.md` when behavior changes; `.spec` is current-state, not a changelog. -- Branch `codex/`; commit body = WHY; trailer `Co-Authored-By: Codex`. One reviewable arc per PR. - -## Codex - -- Review/self-check with `codex exec --profile deep-review`; sandbox + approval per `~/.codex/config.toml`. -- Never touch or echo secrets. -- `spec.*` tasks (from `spec_led_ex`) may not be wired in every checkout (only `format` is in `mix.exs` aliases). If unavailable, note it and run the targeted `mix test ...` from the relevant spec's verification block. +- **Renderer selection:** registry (package) availability != adapter-fallback renderability — preserve the distinction (`AshUI.Rendering.{Selector,Registry}`). +- **Semantic only:** navigation uses symbolic screens/destinations/params/binding-refs (NEVER route/path/URL/module fields); styling uses class hooks/variants/inline values. Host owns routes + theme/CSS/layout. +- Resource-first authoring authoritative; legacy builder/document payloads are migration-only. Keep storage boundaries configurable via `AshUI.Config`. Return structured errors; do NOT crash sessions. Spec-led: update matching `.spec/specs/*.spec.md` when behavior changes (`.spec` is current-state, not a changelog). Branch `codex/`; commit body = WHY; one reviewable arc per PR. `spec.*` tasks (from `spec_led_ex`) may be unwired (only `format` is a `mix.exs` alias) — if so, run the targeted `mix test ...` from the spec's verification block. Never echo secrets. ## Pointers diff --git a/CLAUDE.md b/CLAUDE.md index 0ff217da..73da42e3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -52,7 +52,8 @@ Non-obvious dirs: `packages/` (vendored unified_ui sibling packages — own gram - **No route/path/renderer-specific fields on resources.** Navigation transport goes through `AshUI.Navigation.Intent`, `AshUI.Rendering.CanonicalIUR`, `AshUI.Runtime.Navigation`. - **Storage boundaries stay configurable** through `AshUI.Config` — do not hard-code the default domain, resources, repo, or runtime domain into shared logic. - **Runtime is actor-aware.** Binding evaluation, LiveView events, screen mounts, and resource access pass through authorization/policy surfaces; return structured errors rather than crashing sessions. -- **Co-maintained repo.** This is jointly maintained with Pascal (jallum) as architect. Breaking-change discipline, release notes, and issue-triage obligations apply; respect existing `.spec/` and README conventions. +- **Co-maintained repo.** This is jointly maintained with Pascal (pcharbon70) as architect. Breaking-change discipline, release notes, and issue-triage obligations apply; respect existing `.spec/` and README conventions. +- **Renderer selection: package availability != fallback renderability.** The registry distinguishes external package availability from adapter-fallback renderability and exposes the resolved module + mode per renderer type — preserve that distinction (`AshUI.Rendering.{Selector,Registry}`). ## Conventions