This file is reference context, not a task. Composition recipes — how to build applications from TokenBase models. The recipe book that agents consume.
Each recipe has:
- Name — what you're building
- Pattern — taco (standard, high validity) or choco taco (unexpected composition, lower validity)
- Ingredients — models used
- Traits in play — which trait interfaces matter
- Steps — how to assemble
- Gotchas — what goes wrong
Certainty follows the Bandwidth model: most compositions have high confidence and flow with the stream. Outliers that deviate are valid but carry higher risk — the system doesn't block them, it makes the deviation visible. Every recipe carries an implicit Certainty score:
- High certainty (taco) —
likelihood: 0.85+, confidence: 0.9+. Standard pattern, well-tested, most models follow this. Default assumption. - Medium certainty —
likelihood: 0.5-0.85, confidence: 0.6-0.9. Works but stretches the pattern. Document why you deviated. - Low certainty (choco taco) —
likelihood: <0.5, confidence: <0.6. Unusual composition. Still valid, but the system should surface this as a deviation. Log it, flag it, let a reviewer decide.
When composing models, attach a Certainty record to the composition itself — not just the data flowing through it. This makes pattern deviation visible at the recipe level, not just at runtime. The sourceType field on Certainty tracks whether the score is empirical (observed from usage), theoretical (estimated by an agent), or inherited (propagated from a parent recipe).
Stamped vs Assembled: Models can be classified two ways. Stamped = Typeable trait applied directly (intrinsic identity). Assembled = classification derived through Context (contextual identity that may differ by where the entity appears). Both can coexist on the same entity.
Pattern: Taco Ingredients: Product, Context, Style, Image, Identifier, Unifier, Interaction Traits: Nameable, Describable, Imageable, Taggable, Identifiable
Steps:
- Load
Productby ID - Load its
Context(determines presentation lens — retail vs wholesale, dine-in vs takeout) - Load
StylefromContext.styleId(or from associated View) — this maps fields to output format - Load
Unifierrecords wheregroupIdsincludes the product's group — these are variants (color, size) - Load
Identifierrecords for barcode/QR display - Load
Interactionrecords scoped to this View — these define what gestures do (tap → add to cart, long press → details) - Render using Style field mappings
Gotchas:
- Product has no price field — price lives on
Unit.amount. A Product is what something IS; a Unit is what you sell. Don't confuse them. - Images come from both Product.images and Unifier.images — variant images override product images when present.
- Context's
filterandsortfields can change which Units are visible for the same Product.
Pattern: Taco Ingredients: View, ViewGroup, Filter, Sort, Style, Product, Context, Navigation Traits: Searchable (via Filter), Filterable, Describable
Steps:
- Load
Navigationfor the current screen — determines how user got here and what's adjacent - Load
ViewGroup— this is the tab/section layout (e.g., "All Products" | "By Category" | "Low Stock") - Load each
Viewin the ViewGroup - For each View: load its
Filterrecords (applied selection criteria) andSortrecords (ordering) - Query
Productcollection with Filter + Sort applied - Load
Stylefor the View — determines card/list/grid rendering - Load
Contextfor scope-specific presentation (language, region, access level) - Attach
Interactionrecords to each rendered item
Gotchas:
- View.limit caps the result set — pagination needs ViewState.scrollPosition to track where the user is
- ViewGroup.layout determines the container: tabs, sections, grid, or stack. Don't hardcode tab bars.
- Filter uses operators like
between,in,regex— not just simple equality. Check the operator.
Pattern: Taco Ingredients: ViewGroup, View, Function, Style, Filter, Sort, Navigation Traits: Statusable, Describable, Taggable
Steps:
- Load
Navigation(type: tab) — this is the main nav structure - Load
ViewGroup(layout: sections) — dashboard panels - For each View in the group: load Filters, Sorts, and execute queries
- For computed metrics: load
Functionrecords — each defines an operation (count, sum, average) with inputs/outputs - Apply
Styleper section — some panels are cards, some are tables, some are summary numbers - Load badge counts via
NavigationNode.badgeFunctionId— these Functions compute tab badges
Gotchas:
- Don't compute metrics client-side. Use Function records — they define the computation and the agent executes them server-side.
- Dashboard views change by Context — a manager's dashboard shows different panels than a cashier's.
Pattern: Taco Ingredients: View, Prompt, Interaction, Protocol, Context, Scope Traits: Accessible, Describable, Metadatable
Steps:
- Load
Viewfor settings — entityType targets the configurable model (Business, User, etc.) - Load
Promptrecords — each setting is a structured question (select, input, confirm) - Load
Protocol— validation rules that constrain what settings are valid - Load
Interactionrecords — map gestures to save/cancel/reset actions - Load
Scope— determines which settings this user can see and modify - Render Prompts as form fields, validate against Protocol rules
Gotchas:
- Protocol.strict means ALL rules must pass before saving. Don't allow partial saves on strict protocols.
- Scope controls visibility — a franchise location may have settings that corporate can see but they can't modify.
Pattern: Taco Ingredients: Function, Filter, Sort, Scope, Protocol, Log, Handshake Traits: Validatable, Sourceable, Accessible
Steps:
- Define
Function— operation type (create, read, update, delete), inputs, outputs - On read: apply
Filter+Sortfrom request, scoped byScope - On write: validate against
Protocolrules before persisting - On write: create
Logentry (action, actor, field changes, timestamp) - On destructive write: check for
Handshakerequirement — some mutations need multi-party approval - Return shaped by
Styleif output formatting is needed
Gotchas:
- Every write MUST create a Log. No silent mutations. This is non-negotiable for the audit trail.
- Handshake check happens BEFORE the write, not after. If a Handshake is required and status isn't
approved, reject. - Scope filtering happens at query time, not post-query. Don't fetch everything and filter client-side.
Pattern: Taco Ingredients: Order, OrderItem, FinancialTerm, Handshake, Log, Function, Till Traits: Chargeable, Saleable
Steps:
- Build
Order— addOrderItementries (each snapshots the Product at point of sale) - Load
FinancialTermchain for the business — these define tax, discount, fee, commission in order - Walk the chain: each term references others via
references[]. Direction (up/down) and magnitudeType (percentage/absolute) determine computation - Apply: pretotal → taxes (FinancialTerm where term='tax') → discounts → fees → subtotal → total → due
- Process payment — create
OrderPaymententries - If cash: update
Tillwith a credit correction - Log the entire transaction
- If order requires approval (high value, unusual discount): create
Handshake
Gotchas:
- FinancialTerm chains can be circular if references are misconfigured. Walk with a visited set.
- Order has computed getters (total, due, taxTotal, etc.) — don't recalculate manually, use the model's getters.
- OrderItem snapshots product data at time of sale. Don't reference the live Product — prices change.
- Till balance is computed from corrections, not stored directly. The most recent
auditcorrection is the baseline.
Pattern: Taco Ingredients: Handshake, Async, Prompt, Log, Protocol, Function Traits: Expirable, Statusable
Steps:
- Action triggers approval need (detected by Protocol rule)
- Create
Handshake— list parties, set unanimous flag, attach proposed changes - Create
Asyncrecord — status: pending, timeout set from Protocol or TimeTerm - Notify each party via
Prompt(method: confirm, options: approve/reject) - As responses come in: update
Handshake.agreedBy/rejectedBy - When threshold met (unanimous or majority): update Handshake status
- If approved: execute the pending
Function, create Log entry - If rejected or expired: log rejection, update Async status to rejected/timeout
Gotchas:
- Handshake.unanimous means ALL parties must agree. One rejection = rejected.
- Async.timeout of 0 means no timeout — the Handshake waits forever. Probably not what you want.
- Don't execute the action optimistically. Wait for Handshake resolution.
Pattern: Taco Ingredients: AgentFlow, FlowAgent, Improvement, Queue, Log, Filter Traits: Sourceable, Validatable, Taggable
Steps:
- Define
AgentFlow— pipeline ofFlowAgentstages - Typical pipeline: collector (raw) → categorizer → summarizer → analyzer → rulemaker
- Each stage reads from
Queue(previous stage's output) and writesImprovementrecords at the next stage - Improvement.stage tracks position: raw → categorized → summarized → analyzed → rule
- Gate conditions on FlowAgent control flow: pass (continue), loop (retry), conditional (branch)
- Final stage produces rules that feed back into system behavior (Protocol rules, Function definitions)
- Every stage creates Log entries
Gotchas:
- AgentFlow.refreshInterval controls automatic re-runs. 0 = manual trigger only.
- FlowAgent.gate = 'loop' without a termination condition creates an infinite loop. Always pair with a conditional or max iterations.
- Improvement.sourceIds creates the lineage chain — every output traces back to its raw input.
Pattern: Taco Ingredients: Navigation, NavigationNode, ViewGroup, View, Function Traits: Nameable, Describable
Steps:
- Create
Navigation(type: tab) — the root nav - Add
NavigationNodeentries — each points to a View or ViewGroup - Set icons, labels, positions on each node
- For badge counts: set
badgeFunctionId— the Function computes the count (e.g., unread orders) - Set
defaultNodeId— where the app lands on open - Each node's target View/ViewGroup handles its own content
Gotchas:
- NavigationNode.targetType can be 'view', 'viewGroup', or 'screen'. A screen is a custom destination not backed by a View.
- Transition ('slide', 'fade', 'none') applies to the whole Navigation, not per-node.
Pattern: Taco Ingredients: Navigation, View, Prompt, Interaction, Function Traits: Statusable
Steps:
- Create
Navigation(type: modal) — this is a self-contained flow that overlays the current screen - Add NavigationNodes for each step (e.g., enter details → confirm → success)
- Each step is a View with Prompt records for input collection
- Interaction records handle forward/back/dismiss gestures
- Final step executes a Function (the actual action)
- Transition: 'slide' for card-style, 'fade' for overlay
Gotchas:
- Modal navigations should be short (2-4 steps). If it's more, use a stack navigation.
- Don't forget the dismiss interaction — users need to exit without completing.
Pattern: Taco Ingredients: Product, Unit, Container, Grid, Set, View, Filter, Sort, Identifier, Log Traits: Statusable, Identifiable, Taggable
Steps:
Productdefines what things are — title, description, SKU, dimensionsUnittracks individual instances — each has a status lifecycle (active → sold → returned → damaged)Containerdefines where Units physically are — bins, shelves, palletsGriddefines spatial layouts — planograms, bin maps, warehouse sectionsSetdefines bounded collections — "all units in store #5", "complete size run for SKU X"View+Filter+Sortcreates the lens — "show active units sorted by container"Identifierenables scanning — barcode on each Unit, QR code on each Container- Every move, status change, and count creates a
Logentry
Gotchas:
- Product vs Unit: Product is the blueprint. Unit is the thing in your hand. One Product, many Units.
- Unit.statuses is an array — it's a lifecycle history, not a single status. The last entry is current.
- Container.statuses tracks vacancy — a Container can be 'noVacancy' but still have an active status.
- Set.complete=true means this IS all of them. Use for audit — if the count doesn't match, something is wrong.
Pattern: Taco Ingredients: Identifier, Unit, Product, Function, Interaction, View, Log Traits: Identifiable
Steps:
- User triggers scan via
Interaction(gesture: tap on scan button) - Camera/scanner captures code → look up
Identifierby value + symbology - Identifier.referenceType tells you what was scanned (Unit, Product, Container)
- Load the referenced entity by Identifier.referenceId
- Execute appropriate
Functionbased on context (add to order, update count, move container) - Log the scan event
Gotchas:
- Identifier.detectable=false means this code exists but shouldn't trigger scan actions (e.g., internal-only reference).
- Symbology matters — a UPC_A code and a CODE128 code with the same digits are different identifiers.
- Always check referenceType before assuming what was scanned.
Pattern: Taco Ingredients: Thread, Note, Prompt, Interaction, Async, Scope Traits: Statusable, Polymorphic
Steps:
- Create
Thread— set participants, participantTypes (person, agent, cli, system) - Messages are
Noterecords with noteableType='thread', noteableId=thread.id - Load messages sorted by createdAt
- For agent responses: use
Async— create pending, wait for agent, resolve with response - For decision points: inject
Promptinto the thread (select, confirm) - Track read state via Thread.unreadCounts
- Thread.state lifecycle: active → archived → closed
Gotchas:
- Thread.participantTypes allows mixed human/agent/system threads. The UI should render differently based on participantType.
- Note is polymorphic — it can attach to any entity, not just threads. Always check noteableType.
- unreadCounts is per-participant — each person has their own count.
Pattern: Taco Ingredients: TimeTerm, Timecard, Queue, Protocol, Async, Log Traits: Expirable, Statusable
Steps:
- Define scheduling rules as
TimeTermchains — shift duration (term: duration), break windows (term: window), overtime thresholds (term: cap) Timecardrecords actual work — startedAt, endedAt, correctionsProtocoldefines scheduling constraints — max hours, required breaks, minimum gap between shiftsQueuemanages shift assignments — workers queue for open slotsAsynchandles pending approvals — correction requests, swap requests- TimeTerm.references chains related terms — overtime kicks in after the cap, which references the base duration
Gotchas:
- Timecard.effectiveStart and effectiveEnd use corrections when present. Don't use raw startedAt/endedAt for payroll.
- TimeTerm direction matters: 'extend' adds time, 'reduce' shortens it. An overtime term extends; a break reduces.
- TimeTerm.magnitudeType: 'absolute' is milliseconds, 'relative' is a multiplier on the base term.
Pattern: Taco Ingredients: AgentFlow, FlowAgent, Instruction, Protocol, Handshake, Log, Async Traits: Statusable, Validatable
Steps:
- Define
AgentFlowwith orderedFlowAgentstages - Each FlowAgent has a role (collector, categorizer, summarizer, analyzer, rulemaker, planner, writer, reviewer, deployer)
- Define
Instructionfor each stage — ordered steps with conditions - Set
Protocolfor the flow — rules that gate progression (e.g., "reviewer must approve before deployer runs") - Use
Handshakeat human-in-the-loop checkpoints — agent proposes, human approves - Track async operations via
Async— some stages call external services - Every stage transition creates a
Logentry
Gotchas:
- FlowAgent.gate controls flow: 'pass' continues, 'loop' retries (check loopTo), 'conditional' branches on gateCondition.
- Instruction.sequential=true means steps MUST execute in order. Don't parallelize sequential instructions.
- Instruction.exhaustive=true means ALL steps must complete. Don't skip optional steps in exhaustive instructions — they're not optional here.
Pattern: Taco Ingredients: AgentFlow, Improvement, Filter, Protocol, Handshake, Queue, Log Traits: Sourceable, Validatable, Taggable
Steps:
- Content enters as raw
Improvement(stage: raw, category: conversation/output) - First FlowAgent (collector) captures and queues
- Second FlowAgent (categorizer) classifies — safe/flagged/escalate, updates Improvement.stage to categorized
- Filter rules determine routing: safe → pass, flagged → analyzer, escalate → human review
- Analyzer stage runs Protocol checks — content policies as ProtocolRules
- Escalated content creates a Handshake — human must approve/reject
- Terminal stage: published, removed, or modified
Gotchas:
- Don't skip the categorizer stage. Even obvious content should be classified — it feeds the rulemaker for future automation.
- Improvement.sourceIds maintains chain of custody. Every modification creates a new Improvement referencing the previous one.
Don't use Group when you mean Scope. Group is a loose bucket. Scope is a boundary with regional, linguistic, and access constraints. "All products in the Pacific Northwest" is a Scope, not a Group. "Products that go well together" is a Group.
Don't use Context when you mean Style. Context is the lens (what you see). Style is the template (how it renders). Changing Context changes WHAT data appears. Changing Style changes HOW the same data looks. A wholesale context shows different products. A receipt style shows the same products differently.
Don't store price on Product. Product is what something IS. Unit is what you sell. Price (amount) lives on Unit, not Product. A Product can have Units at different prices (wholesale vs retail, by region, by condition).
Don't use Note for structured data. Note is free-text annotation — comments, memos, observations. If the data has a defined shape, it's a model field or a MetadataEntry, not a Note.
Don't use Metadata for core fields. MetadataEntry is for extensions — things that don't fit the model's core schema. If you're storing the same key on every record, it should be a model field. Metadata is classified (primary/meta/extended/derived/system) for a reason — most things are 'extended'.
Don't chain FinancialTerms without a base. The first term in a chain must have an absolute magnitude — a real number, not a percentage. You can't take 8% of nothing. The chain walks from the base amount through percentage and absolute modifications.
Don't use Handshake for single-party actions. Handshake is multi-party consensus. If only one person needs to approve, use Protocol validation instead. Handshake with one party is just a confirmation dialog with extra overhead.
Don't use Queue for static collections. Queue is ordered, temporary, and processing-oriented. Items enter and leave. If items just sit there, use Set or Group. Queue items have enqueuedAt/dequeuedAt — if nothing ever dequeues, it's not a queue.
Don't put business logic in Style. Style maps fields to output formats — it's a template, not a transformer. If you need computation, use Function. Style.format handles display formatting ($%.2f, uppercase, date:short), not business logic.
Don't ignore View when filtering data. Always go through View + Filter + Sort for data queries. Don't query models directly with ad-hoc filter logic. Views are the saved, reusable, scope-aware lenses. Ad-hoc filtering leads to inconsistent results across the app.
Do the items have a defined type and schema?
├── Yes → Does the user need to filter/sort?
│ ├── Yes → View + Filter + Sort + Style
│ └── No → View + Style (no filters)
└── No → Is it free-form content?
├── Yes → Thread + Note
└── No → Improvement (raw stage, categorize later)
Is it about WHAT data to show?
├── Yes → Context (lens — scope, filter, sort, params)
└── No → Is it about HOW to render data?
├── Yes → Style (field mappings, target format, template)
└── No → Is it about WHERE to show it?
├── Yes → View (ties Context + Style + data type)
└── No → Grid (spatial layout of slots)
Is it a single charge?
├── Yes → FinancialTerm (term: charge, direction: up, magnitudeType: absolute)
└── No → Is it a percentage modifier?
├── Yes → FinancialTerm (magnitudeType: percentage, references: [base term])
└── No → Is it a full transaction?
├── Yes → Order + OrderItem + OrderPayment
└── No → Is it a cash flow?
├── Yes → Till + TillCorrection
└── No → FinancialTerm chain (define the calculation path)
Is it a strict boundary with regional/access constraints?
├── Yes → Scope
└── No → Is it an exhaustive, complete list?
├── Yes → Set (complete: true)
└── No → Is it a loose grouping?
├── Yes → Group
└── No → Is it spatial/positional?
├── Yes → Grid
└── No → Is it a graph of relationships?
├── Yes → Map + Relationship
└── No → Group (default)
Is it a field-level change to an entity?
├── Yes → Log (level: field, action: update, fromValue/toValue)
└── No → Is it a status transition?
├── Yes → Log (level: status, action: transition)
└── No → Is it an access event?
├── Yes → Log (level: access, action: read/export/share)
└── No → Is it a system event?
├── Yes → Log (level: system)
└── No → Note (free-form annotation)
Is it multi-party consensus?
├── Yes → Handshake (parties, unanimous flag, proposed changes)
│ Does it need a timeout?
│ ├── Yes → Async (timeout from TimeTerm or Protocol)
│ └── No → Handshake alone (waits indefinitely — are you sure?)
└── No → Is it rule-based validation?
├── Yes → Protocol (rules, enforcement, strict flag)
└── No → Is it a simple confirmation?
├── Yes → Prompt (method: confirm)
└── No → Function (just execute, no approval needed)
Is it a multi-stage pipeline?
├── Yes → AgentFlow + FlowAgent stages
│ Does it refine data progressively?
│ ├── Yes → Improvement records (raw → categorized → summarized → analyzed → rule)
│ └── No → Function per stage (each FlowAgent executes a Function)
└── No → Is it a single operation?
├── Yes → Function (define inputs, outputs, operation)
└── No → Is it a set of ordered steps?
├── Yes → Instruction (steps with conditions, sequential/exhaustive flags)
└── No → Prompt (ask the agent a question, get a structured response)
Quick reference: which models appear in which recipe patterns.
| Model | Appears In |
|---|---|
| Product | Product Detail, Catalog, Inventory, Barcode Scan, Financial Transaction |
| Unit | Inventory, Barcode Scan, Financial Transaction |
| Order | Financial Transaction |
| View | Catalog, Dashboard, Settings, Inventory, all screen patterns |
| ViewGroup | Catalog, Dashboard, all multi-panel screens |
| Filter | Catalog, Dashboard, Inventory, CRUD API, Data Ingestion |
| Sort | Catalog, Dashboard, Inventory, CRUD API |
| Style | Product Detail, Catalog, Dashboard, CRUD API |
| Context | Product Detail, Catalog, Dashboard, Settings, all scope-dependent patterns |
| Scope | Settings, CRUD API, Messaging, Scheduling, all access-controlled patterns |
| Navigation | Catalog, Dashboard, Tab App, Modal Flow |
| Interaction | Product Detail, Catalog, Settings, Modal, Barcode Scan |
| Function | Dashboard, CRUD API, Financial Transaction, Approval, Agent Workflow |
| Prompt | Settings, Approval, Modal Flow, Messaging |
| Protocol | Settings, CRUD API, Approval, Scheduling, Agent Workflow, Moderation |
| Handshake | Financial Transaction, Approval, Agent Workflow, Moderation |
| Log | CRUD API, Financial Transaction, Approval, Inventory, Scheduling, all state-changing patterns |
| Async | Approval, Messaging, Scheduling, Agent Workflow |
| AgentFlow | Data Ingestion, Agent Workflow, Moderation |
| Improvement | Data Ingestion, Moderation |
| Queue | Data Ingestion, Scheduling, Moderation |
| FinancialTerm | Financial Transaction |
| TimeTerm | Scheduling |
| Thread | Messaging |
| Identifier | Product Detail, Inventory, Barcode Scan |
| Grid | Inventory (planograms, spatial layouts) |
| Set | Inventory (bounded collections) |
| Map | Relationship visualization (not in standard recipes — choco taco territory) |
| Unifier | Product Detail (variants) |
| Container | Inventory |
| Till | Financial Transaction |
| Timecard | Scheduling |
The Instruction Set IS the MCP generation source. When generating a scoped MCP instance:
- Determine role — what recipes does this role need?
- Collect ingredients — union of all models referenced by those recipes
- Generate operations — CRUD + compose + validate + transform per included model
- Scope by field — some roles see all fields, others see a subset (Style controls this)
- Stamp and auth — the generated instance IS the guardrail. Nothing outside scope exists.
A cashier's MCP gets: Financial Transaction, Product Detail, Barcode Scan, Tab App. That means their instance contains: Order, Product, Unit, Identifier, View, Style, Context, Function, Interaction, Navigation, Log, FinancialTerm, Till. It does NOT contain: AgentFlow, Improvement, Protocol (admin), Handshake (manager), Container (warehouse), Scope (admin).
The recipes define what's in. Everything else is out. Not locked — absent.