con un clic
grain-schema
Define Malli schemas for commands, events, and queries using defschemas
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
Define Malli schemas for commands, events, and queries using defschemas
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
Create scheduled background jobs that run on cron schedules
Build an ORC behavior tree workflow using the DSL
Set up LLM-as-judge evaluation for ORC workflows
Implement event-driven side effects that react to domain events
Implement command handlers that validate state and emit events using the Grain framework
Create a complete Grain domain service with schemas, read models, commands, queries, and tests
| name | grain-schema |
| description | Define Malli schemas for commands, events, and queries using defschemas |
(ns my.service.interface.schemas
(:require [ai.obney.grain.schema-util.interface :refer [defschemas]]))
Use defschemas to register named Malli schemas:
(defschemas schema-group-name
{:schema-key schema-definition
:another-key another-definition})
Naming: :namespace/action (verb form)
(defschemas commands
{;; Create command
:crm/create-contact
[:map
[:type-slug :string]
[:field-values [:map-of :keyword :any]]
[:contact-id {:optional true} :uuid]
[:tags {:optional true} [:set :string]]]
;; Update command
:crm/update-contact
[:map
[:contact-id :uuid]
[:changes [:map-of :keyword :any]]]
;; Action command
:advisor/start-meeting
[:map
[:student-id :uuid]
[:meeting-type [:enum :intake-interview :freeform]]]})
Naming: :namespace/entity-past-tense (what happened)
(defschemas events
{;; Created event
:crm/contact-created
[:map
[:contact-id :uuid]
[:type-id :uuid]
[:type-slug :string]
[:display-name :string]
[:field-values [:map-of :keyword :any]]
[:tags [:set :string]]]
;; Updated event
:crm/contact-updated
[:map
[:contact-id :uuid]
[:changes [:map-of :keyword :any]]]
;; Action completed event
:advisor/meeting-started
[:map
[:meeting-id :uuid]
[:student-id :uuid]
[:meeting-type [:enum :intake-interview :freeform]]
[:started-at :string]]})
Naming: :namespace/query-name (what to get)
(defschemas queries
{:crm/get-contact
[:map
[:contact-id :uuid]]
:crm/list-contacts
[:map
[:type-slug {:optional true} :string]
[:status {:optional true} [:enum :active :inactive :archived]]
[:limit {:optional true} :int]
[:offset {:optional true} :int]]
:advisor/meetings-screen
[:map
[:student-id :uuid]]})
:string ;; String
:int ;; Integer
:double ;; Float
:boolean ;; Boolean
:uuid ;; UUID
:keyword ;; Keyword
:any ;; Any value
[:enum :a :b :c] ;; Enum
[:set :string] ;; Set of strings
[:vector :uuid] ;; Vector of UUIDs
[:map-of :keyword :any] ;; Map with keyword keys
[:map ;; Map with specific keys
[:required-key :string]
[:optional-key {:optional true} :int]]
[:re #"^[a-z]+$"] ;; Regex pattern
(defschemas custom-types
{:email [:re #"^[^@\s]+@[^@\s]+\.[^@\s]+$"]
:phone [:re #"^\d{10,15}$"]
:encrypted [:map
[:ciphertext :string]
[:encrypted-key :string]
[:iv :string]]})
(def attribution-source
[:enum :application_form :intake_form :referral :manual_entry])
(def attribution
[:map
[:source attribution-source]
[:source-details {:optional true} :any]
[:referring-contact-id {:optional true} :uuid]
[:recorded-at :string]])
(defschemas events
{:crm/attribution-recorded
[:map
[:contact-id :uuid]
[:attribution attribution]]})
:namespace/verb (create, update, delete, start, etc.):namespace/entity-past-tense (created, updated, started):namespace/get-entity or :namespace/list-entities{:optional true} for optional fields->event producescomponents/user-service/src/ai/obney/workshop/user_service/interface/schemas.clj - User schemascomponents/crm-service/src/ai/obney/workshop/crm_service/interface/schemas.clj - CRM schemas with custom types