Skip to content

Proposal: Add action-level filter_fields for read actions #2589

@nallwhy

Description

@nallwhy

Code of Conduct

  • I agree to follow this project's Code of Conduct

AI Policy

  • I agree to follow this project's AI Policy, or I agree that AI was not used while creating this issue.

Is your feature request related to a problem? Please describe.

Different interface libraries (ash_graphql, ash_ai, ...) each need to control which fields are filterable when exposing read actions. Currently there's no standard way to do this at the Ash core level, which forces each interface to implement its own solution independently.

For example:

  • ash_graphql has filterable_fields at the GraphQL type level to control which attributes are exposed as filter arguments
  • ash_ai exposes read actions as MCP/LLM tools and needs the same kind of control — certain fields shouldn't be offered as filter options to an LLM

The core problem is that filter field control is fundamentally about "how should this action expose its data" — which is an action-level concern, not an interface-level concern. Having each interface reinvent this leads to duplicated configuration, inconsistency between interfaces, and the risk of accidentally exposing fields in one interface that were intentionally hidden in another.

Describe the solution you'd like

A filter_fields option on read actions that declares which fields are available for filtering:

read :list_public do
  filter_fields [:name, :bio, genre: [:eq, :in]]
end

read :list_admin do
  # all fields filterable (default behavior, no restriction)
end

Interface libraries would respect this as the baseline — a field not in filter_fields cannot be filtered through any interface. Interfaces could then optionally restrict further (e.g. hiding a field from GraphQL but keeping it available in MCP), but could never expand beyond what the action allows.

This gives action authors a single place to declare the filtering contract, and every interface inherits it automatically.

Describe alternatives you've considered

  1. Attribute-level filterable?: false — Already exists in Ash for some contexts. Too coarse: it's global across all actions and interfaces. "This field should never be filterable anywhere" is a valid but narrow use case. Doesn't help when you want different filter sets for :list_public vs :list_admin.

  2. Interface-level configuration (current state) — Each interface defines its own filter control (e.g. ash_graphql's filterable_fields). Works but leads to scattered configuration, duplication, and potential inconsistency. If you add a new interface, you have to remember to configure filtering there too.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions