Imported from didisouzacosta/Formidable (
AGENTS.md). Install upstream withnpx skills add didisouzacosta/Formidable. Copyright stays with the author.
Formidable - Project Standards and Rules (Codex)
This file is the project-specific source of truth for work in Formidable. The current implementation is the source of truth for runtime behavior; when it conflicts with this document, report the discrepancy before changing public behavior.
Package Baseline
- Swift tools version: 6.2.
- Supported platforms: iOS 17+, macOS 15+, and tvOS 17+.
- Preserve source and API compatibility across every supported platform. Gate platform-specific APIs with availability checks and provide an appropriate fallback.
Formidableitself is not isolated to@MainActor. Do not describe or treat the protocol as actor-isolated unless the declaration is deliberately changed.- New observable reference types should use Observation (
@Observable).FormFieldRepresentablecurrently inherits fromObservableObject; preserve that compatibility requirement unless a dedicated migration changes the public contract.
Architecture and Behavior
Form contracts
Formidableis the form-management protocol. Its default implementation usesMirrorto discover stored properties conforming toFormFieldRepresentable.FormFieldRepresentableis the field contract and exposes value, original value, visibility, disabled state, error visibility, transformation, and validation rules.Emptablerepresents values that can be checked for emptiness.Mensurablerepresents values with a numericlengthmeasure.- Use
FormField<Value>for fields managed by aFormidableform.
FormField behavior
- Assigning through
FormField.valuesetsshowErrors = true.FormFieldContainerdecides whether and how those errors are rendered. - A
FormFieldinitialized withBinding<Value>reads from and writes to the external source. A change made directly to that external source does not pass through theFormField.valuesetter and therefore does not automatically enableshowErrors. transformnormalizes the value returned to callers and used for validation. Keep transformations deterministic and cover their interaction with initialization and reset in tests.originalValuecaptures the transformed initial value and is used byisModified.FormFieldseparately retains the raw initial value so a non-idempotent transformation is not applied twice during reset.reset()restores the raw initial value through the active binding or local storage and clearsshowErrors; reads continue to applytransformonce.
Validation
- Validation rules conform to
FormFieldRuleand are stored directly as[any FormFieldRule]inFormField.rules. AnyRuleis an internal adapter used while validating existential rules; it is not the storage type exposed byFormFieldand must not be required at call sites.- Static rules compare against a fixed value. Cross-field rules use a root object and
KeyPathand end inKeyPathRule. try form.validate()enables error display for the form fields and throws the first collected error.- Hidden or disabled fields produce no validation errors. A fully disabled form returns from validation without throwing.
SwiftUI integration
- Apply
.field($form.field, accessibilityLabel: ...)to standard SwiftUI controls to attach Formidable behavior. - The modifier wraps the control in
FormFieldContainer, applies hidden and disabled state, and renders localized error descriptions. - The error container must receive a meaningful, localizable accessibility label. Icon-only controls must also expose a meaningful accessibility label.
Skills and Precedence
Use the canonical skill name to activate the skill; the linked path is the currently installed local reference.
- Use $swiftui-expert-skill when creating, reviewing, or modernizing SwiftUI code, including state ownership, Observation, concurrency, navigation, animation, accessibility, and modern API selection.
- Use $swift-mark-organization when creating, reviewing, refactoring, or normalizing Swift files. It owns exact
// MARK: -names, member ordering, wrapper grouping, visibility, initializer layout, and modifier ordering. - Use $build-ios-apps:swiftui-view-refactor when splitting a large view, tightening data flow, stabilizing view identity, or cleaning Observation ownership.
- Use $build-ios-apps:swiftui-performance-audit only for reported performance symptoms, an explicit performance audit, or a change to a known rendering hot path. Start with code review; request Instruments evidence only when code is inconclusive or runtime proof is required.
Resolve overlapping guidance in this order:
- This file and verified Formidable behavior define project invariants.
swift-mark-organizationdefines Swift member and section organization.swiftui-expert-skilldefines modern SwiftUI, state, Observation, concurrency, and API practices.swiftui-view-refactordefines view decomposition and data flow; its member-order guidance yields toswift-mark-organization.swiftui-performance-auditdefines the performance investigation and evidence workflow.
Additional conflict-resolution rules:
- Keep a trivial action inline when that is clearest. Extract non-trivial actions, side effects, and business logic from
bodyinto methods, services, or models. - Prefer the MV pattern and vanilla SwiftUI. Do not introduce a view model merely to mirror local state or wrap environment dependencies; retain or add one only when the existing design or the requested feature genuinely requires it.
- Keep the view tree stable, pass only the inputs a subview needs, and prefer dedicated subview types for non-trivial sections over large computed
some Viewfragments. - Adopt Liquid Glass only when explicitly requested. Gate iOS 26+ APIs with
#availableand preserve suitable behavior on every supported platform. - Versioned plugin-cache paths may change after a plugin upgrade. The canonical skill names remain the activation identifiers; update stale links when upgrading plugins.
Swift Code Organization
- Apply the exact organization below to new or modified Swift declarations. Do not mass-reformat unrelated files solely to normalize their sections.
- Omit sections that do not apply, but keep the remaining sections in this order.
- Keep members in the same property-wrapper or visibility group contiguous. Preserve behavior while reorganizing.
For View types:
// MARK: - Environments// MARK: - Bindables// MARK: - Bindings// MARK: - App Storage// MARK: - Scene Storage// MARK: - Focus State// MARK: - Gesture State// MARK: - Namespaces// MARK: - States// MARK: - Public Properties// MARK: - Body// MARK: - Private Properties// MARK: - Initializer// MARK: - Public Methods// MARK: - Private Methods
For non-View types:
// MARK: - Public Properties// MARK: - Private Properties// MARK: - Initializer// MARK: - Public Methods// MARK: - Private Methods
Naming, Layout, and Documentation
- Follow the existing source layout:
Contracts/,Rules/,Modifiers/, andComponents/. - Contract protocol names must end in
Representable,able, orible. - Rule types must end in
Rule; cross-field rule types must end inKeyPathRule. - A Swift file must match its primary type name.
FieldRule.swiftis a known legacy discrepancy forFormFieldRule; do not copy that mismatch into new files. - Document every public type and public API with
///. Include a compiling usage example under a# Exampleheading for public components. - Keep view-owned
@Stateand injected@Bindableproperties private. Use@Stateto own an@Observablereference in a view and@Bindableonly when the view needs bindings to an injected observable. - Keep
bodysimple and free of business logic. Use modern SwiftUI APIs and avoid unnecessary platform assumptions or fixed screen dimensions.
Testing and Verification
- Use Swift Testing (
import Testing,@Test, and#expect). - Mark every test suite type with
@MainActor. Helper types need actor isolation only when their usage requires it. - Put rule tests in
Tests/FormidableTests/Rules/, contract tests inTests/FormidableTests/Contracts/, and shared field/form behavior tests in the corresponding top-level test file. - Every new rule or contract behavior requires focused unit tests. Every changed field or form behavior must cover the affected state transitions.
- As applicable, test initial and original values, transformations, external binding synchronization,
showErrors,reset,isModified,isHidden,isDisabled, error aggregation, and the first error thrown byvalidate(). - Run the package verification command from the repository root:
swift test
- The established baseline at the time of this document revision is 72 tests in 21 suites. Treat the count as informational rather than a substitute for a passing run.