Foundry.Manifest (foundry v0.1.2)

Copy Markdown

The project manifest resource. Validates and provides typed access to the .foundry/manifest.exs configuration file for a target project.

Storage

The manifest lives as a plain Elixir keyword list at .foundry/manifest.exs in the target project's repository (ADR-015). This Ash resource is the schema + validation layer — it does not persist to a database.

Ash.DataLayer.Simple is used here solely to leverage Ash's changeset validation, attribute type coercion, and embedded resource support. The manifest is always a single instance — it is loaded once at Studio startup and held in-process. It is never queried by ID, never paginated, and never written to a database. Ash.DataLayer.Simple is the lightest data layer that gives us Ash validations without any storage infrastructure.

Do not add :read actions that imply collection semantics (list, filter, sort). The only meaningful action is :load — construct from a keyword list.

Loading

Use Foundry.Manifest.Reader.load!/1 to read and validate the manifest file. That function parses the .exs file, constructs a Foundry.Manifest record via Ash.Changeset.for_create/3 with the :load action, and raises if validation fails. The returned record is cached in ETS for the session (ADR-015 Tier 2 — keyed on {:manifest, mix_exs_mtime}).

Validation

All fields declared in docs/manifest-schema-draft.md are validated here. Invalid manifests raise at Studio startup — Foundry will not run against a project with a broken manifest.

Calculations

Calculations on this resource use Elixir-native expr/1 forms only. SQL fragment/1 expressions are not valid with Ash.DataLayer.Simple — it evaluates expressions in Elixir, not Postgres. Any calculation that appears to need a fragment should be implemented as a module-based calculation instead.

ADR

ADR-011 (deferred — write after this resource is stable in production). Pre-ADR schema: docs/manifest-schema-draft.md.

Summary

Functions

Validates that the keys in the provided input are valid for at least one action on the resource.

Same as input/1, except restricts the keys to values accepted by the action provided.

Types

t()

@type t() :: %Foundry.Manifest{
  __lateral_join_source__: term(),
  __meta__: term(),
  __metadata__: term(),
  __order__: term(),
  aggregates: term(),
  approval_sla: term(),
  approvers: term(),
  ash_money_enabled: term(),
  auto_apply_structural: term(),
  calculations: term(),
  change_generation_enabled: term(),
  conditional_libraries: term(),
  context_exclusions: term(),
  copilot_model: term(),
  coverage_gate: term(),
  coverage_weights: term(),
  data_retention: term(),
  domain_type: term(),
  fun_with_flags_enabled: term(),
  has_notification_config: term(),
  id: term(),
  inserted_at: term(),
  mcp_enabled: term(),
  notifications: term(),
  project_name: term(),
  sensitive_resource_exemptions: term(),
  sensitive_resources: term(),
  tidewave_scaffold: term(),
  updated_at: term()
}

Functions

default_short_name()

input(opts)

@spec input(values :: map() | Keyword.t()) :: map() | no_return()

Validates that the keys in the provided input are valid for at least one action on the resource.

Raises a KeyError error at compile time if not. This exists because generally a struct should only ever be created by Ash as a result of a successful action. You should not be creating records manually in code, e.g %MyResource{value: 1, value: 2}. Generally that is fine, but often with embedded resources it is nice to be able to validate the keys that are being provided, e.g

Resource
|> Ash.Changeset.for_create(:create, %{embedded: EmbeddedResource.input(foo: 1, bar: 2)})
|> Ash.create()

input(opts, action)

@spec input(values :: map() | Keyword.t(), action :: atom()) :: map() | no_return()

Same as input/1, except restricts the keys to values accepted by the action provided.

primary_key_matches?(left, right)