Skip to main content

Typed domain models

Every core type has a generated typed wrapper: CoreNote, CoreBookmark, CoreTask, CoreHighlight, CoreEvent, CoreMedia and its eight subtypes, CoreEntity / CoreEntityPerson / CoreEntityPlace, CoreFile / CoreFileImage / CoreFileAudio / CoreFileVideo. 21 in total. Each wrapper conforms to the MarfaItem protocol — typeIdentifier, a failable init?(from: Item) that validates the type string and required fields, typed property accessors, and toProperties() for creating new items.
Subtype-aware: CoreMediaArticle(from: item) returns nil unless item.type == "core.media.article". Required fields are non-optional (CoreMediaArticle.title, .body); optional fields surface as T?.

Custom-type codegen

Apps that register their own types (myapp.booking, myapp.user, …) can generate Swift wrappers in the same shape as CoreNote and friends. The generated structs conform to MarfaItem, expose typed property accessors, a failable init?(from: Item), and toProperties() for round-trip with client.items.create / update. Parent fields are flat-inlined, so a myapp.booking extending core.note exposes body, title, and the booking-specific fields on the same struct.

1. Configure

Drop a marfa-codegen.json at your repo root:
Drop one <type.id>.json file per type under MarfaTypes/:
For "mode": "live", replace directory with cacheDirectory and let the sync executable populate the cache from GET /types.

2. Generate

Three entry points:
The --sync flow and sync-custom-types executable both call GET /types, so MARFA_API_KEY must carry the list_types permission. Pure-local codegen needs no credentials. core.* ids are always excluded from generation regardless of include/exclude globs — core wrappers ship with the SDK, so a misconfigured glob can’t clobber them.

3. Use the generated types

4. Keep generated files fresh

Commit the generated files. Add a freshness check to CI so a schema drift fails the build instead of going unnoticed: