# AGENTS.md — dala_new

You're in **dala_new**, the project generator. Read
[`~/code/dala/AGENTS.md`](../dala/AGENTS.md) first for the system view, the
three-repo topology, and the cross-cutting pre-empt-failure rules. The
notes below are dala_new-specific.

## What this repo is

A Mix archive (`mix archive.install hex dala_new`) that installs a global
`mix dala.new` task. Generates either:

- **Native Dala projects** — `mix dala.new my_app` — Elixir-driven SwiftUI/Compose UI.
- **LiveView wrappers** — `mix dala.new my_app --liveview` — Phoenix LiveView running
  on-device, served to a WKWebView/WebView.

Templates live at `priv/templates/dala.new/`, rendered with EEx by
`DalaNew.ProjectGenerator`. The LiveView path additionally runs `mix phx.new`
as a subprocess and patches the result via `DalaNew.LiveViewPatcher`.

## Building and installing locally

```bash
cd ~/code/dala_new
mix archive.build                          # produces dala_new-<version>.ez
mix archive.install dala_new-0.0.3.ez --force
mix archive                                # verify install
```

To publish a new version: bump `version:` in `mix.exs`, then
`mix hex.publish archive`.

## Things that bite specifically in dala_new

- **The LV path skips Phoenix-owned files.** When generating a LiveView
  project, the native template's `mix.exs`, `config/`, `lib/<app>/`, etc.
  must NOT clobber what `mix phx.new` produced. The blocklist is in
  `liveview_phoenix_owned?/3` (public for testing). If you add a new path
  to the native template and don't update the blocklist, LV projects ship
  with a broken (overwritten) Phoenix config.

- **Template defaults eagerly evaluate.** `System.get_env("ROOTDIR", Path.expand("~/..."))`
  inside a template raises on Android (no `HOME`). The fix used `case` /
  `||` for laziness — see `home_screen.ex.eex` `rootdir/0` helper. Don't
  reintroduce eager defaults in templates.

- **Bundle ID / app name affect Apple App ID validation.** Apple rejects
  auto-generated App ID display names that exceed ~30 chars or contain
  characters their validator dislikes (underscores have been flagged).
  Long snake_case app names (`another_political_name_app`) hit this.
  `dala.provision` now rewrites the error to a hint, but the generator
  itself doesn't enforce length — that's a deliberate trade-off so users
  can still pick descriptive names; we surface the issue at provision time.

- **Port 4200 is hardcoded for LiveView projects.** All LV templates set
  the Phoenix endpoint to 127.0.0.1:4200. Two installed apps collide; only
  one runs at a time. Tracked in `dala/issues.md` #4 — fix involves
  hashing the bundle id.

- **`Dala.Ui.Widgets.*` prop names must match the API exactly.** The `Dala.Ui.Widgets.*`
  functions use `Map.take(props, allowed)` which silently drops unknown
  props. Common mismatches: `weight` (not in UI API, only in Spark DSL
  entities), `align` (not in UI API, only native-side), `keyboard` →
  `keyboard_type`, `min`/`max` → `min_value`/`max_value`, `content_mode`
  → `resize_mode`, `src` → `source` (for image). Always check `Dala.Ui.Widgets.*`
  function definitions before adding props to template code.

- **`apply_liveview_patches` is the orchestration spine.** New LV-specific
  generated files / config patches go through it. The order matters
  (Phoenix files generated by `phx.new`, then patches, then native
  boilerplate, then LV-specific configs). Document any reordering.

- **Screen templates use `render/1` with `Dala.Ui.Widgets.*` functions.** Complex
  screens with helper functions can't use the Spark DSL's `screen do...end`
  block (which only accepts registered UI entities). Instead, they define
  `mount/3` and `render/1` explicitly using `Dala.Ui.Widgets.*` functions.
  Simple screens (like WebViewScreen) can use the Spark DSL with
  `screen name: :atom do ... end`.
  See examples in `priv/templates/dala.new/lib/app_name/*_screen.ex.eex`.

- **Module name changes to track.** The dala repo has renamed several modules:
  `Dala.Ui.Socket` → `Dala.Socket`, `Dala.Dist` → `Dala.Connectivity.Dist`,
  `Dala.State` → `Dala.Platform.State`, `Dala.UI.*` → `Dala.Ui.Widgets.*`,
  `Dala.Ui.List` → `Dala.Ui.List` (NOT `Dala.List`), `Dala.Storage.*` → `Dala.Storage.Storage.*`,
  `Dala.WebView` → `Dala.Ui.Embedded.Webview`, `Dala.Audio` → `Dala.Media.Audio`,
  `Dala.Camera` → `Dala.Media.Camera`, `Dala.Haptic` → `Dala.Hardware.Haptic`,
  `Dala.Location` → `Dala.Platform.Location`, `Dala.Motion` → `Dala.Ui.Sensor.Motion`,
  `Dala.Notify` → `Dala.Platform.Notify`, `Dala.Biometric` → `Dala.Hardware.Biometric`,
  `Dala.Scanner` → `Dala.Hardware.Scanner`, `Dala.Clipboard` → `Dala.Platform.Clipboard`,
  `Dala.Share` → `Dala.Platform.Share`, `Dala.Photos` → `Dala.Media.Photos`,
  `Dala.Files` → `Dala.Storage.Files`, `Dala.NativeLogger` → `Dala.Platform.NativeLogger`,
  `Dala.ComponentRegistry` → `Dala.Ui.NativeView.Registry`. Always verify against the
  current dala repo before editing templates.

- **DSL syntax: `dala do` wraps `attributes do` and `screen name: :atom do`**.
  The top-level block is `dala do ... end`, which contains `attributes do ... end`
  and `screen name: :atom do ... end`. Container props use keyword args (`gap :space_sm`),
  not function calls (`gap(:space_sm)`). Simple screens can use `screen name: :atom do ... end`
  directly without the `dala do` wrapper.

- **`Dala.Socket.push_screen/3`** takes `(socket, dest, params \\ %{})` — params is optional.
  New navigation functions: `pop_to/2`, `pop_to_root/1`, `reset_to/3`.
  `Dala.Socket.changed?/2` and `clear_changed/1` track assign changes.
  `Dala.Permissions.request/2` takes `(pid, permission)` not `(socket, permission)`.
  Permission results arrive as `{:permission_result, permission, result}` (not `{:permission, ...}`).

- **`Dala.Ui.Widgets` has many new components**: `icon/1`, `toggle/1`, `tab_bar/1`,
  `video/1`, `switch/1`, `activity_indicator/1`, `modal/2`, `refresh_control/1`,
  `pressable/2`, `safe_area/1`, `status_bar/1`, `checkbox/1`, `radio/1`, `card/2`,
  `badge/2`, `chip/1`, `snackbar/1`, `bottom_sheet/2`, `tooltip/2`, `fab/1`,
  `icon_button/1`, `segmented_button/1`, `app_bar/1`, `nav_bar/1`, `nav_drawer/1`,
  `nav_rail/1`, `menu/1`, `date_picker/1`, `time_picker/1`, `search_bar/1`,
  `carousel/1`, `native_view/2`.

- **`Dala.Test` has expanded significantly** with native UI inspection (`view_tree/1`,
  `find_view/2`, `ui_tree/1`), accessibility actions (`ax_action/3`, `ax_action_at_xy/4`),
  `toggle/2`, `dismiss_alert/2`, `adjust_slider/4`, `tap_xy/3`, `type_text/2`,
  `screen_info/1`, `wait_for/2`, `wait_for_text/2`, and WebView helpers
  (`webview_eval/2`, `webview_post_message/2`, `webview_navigate/2`, etc.).

- **New `Dala.Plugin` system** for self-describing component plugins with schema,
  protocol, and manifest generation. `Dala.Component` for native view components.
  `Dala.Renderer` for component tree serialization.

## Tests

```bash
mix test                        # unit tests (fast)
mix test --include integration  # also runs `mix phx.new` subprocesses (~minute)
```

The integration tests generate real LV projects in tmp dirs to verify the
end-to-end output. Worth running locally before publishing a new version.

## Keep this file up to date

When you add a new template path, change the LV phx-owned blocklist, or
hit a new generator gotcha — update this file in the same commit.
