For each entity:
- What fields are INPUT (human provides)?
- What fields are GENERATED (AI creates)?
- What fields are SYNCED (from external)?
- What fields are COMPUTED (derived)?
- What fields are AGGREGATED (from relationships)?
- What ACTIONS can affect external systems?
- What EVENTS should trigger behavior?
This is an EXTERNAL entity - we observe it, don't own it.
Stripe.Customer = {
// Identity (from Stripe)
id: 'cus_xxx', // Stripe assigns
// Fields (all synced from Stripe API)
email: @stripe.email,
name: @stripe.name,
phone: @stripe.phone,
currency: @stripe.currency,
balance: @stripe.balance, // cents
created: @stripe.created, // timestamp
delinquent: @stripe.delinquent, // boolean
metadata: @stripe.metadata, // object
// These are Stripe's data - we just observe
}Observation: All fields come from Stripe. We need to express "this whole entity is external".
Syntax idea:
Stripe.Customer = @Stripe('/customers/{id}') {
// Fields are auto-mapped from API response
// Or explicit mapping:
email,
name,
balance: $.balance, // JSONPath if different
}This is OUR entity - we own it, but it links to Stripe.
Customer = {
// Our identity
id: 'generated-uuid',
// Input fields (we collect)
email: 'Customer email', // input, required
name: 'Customer name', // input
company: 'Company name', // input
// Link to external (Stripe)
stripe: -> Stripe.Customer, // reference, may be null
// Computed from Stripe (when linked)
balance: => stripe?.balance ?? 0,
isDelinquent: => stripe?.delinquent ?? false,
// Aggregated from relationships
totalSpend: #sum(orders.total),
orderCount: #count(orders),
// Generated (AI enrichment)
segment: '{company} customer segment analysis',
// Relationships
orders: <- Order.customer,
subscriptions: <- Subscription.customer,
}Observations:
- Mix of input, computed, aggregated, generated
- Links to external entity (Stripe.Customer)
- Computed fields depend on external data
- Aggregates from related entities
Exists in BOTH systems - we have our version, Stripe has theirs.
Subscription = {
// Our identity
id: 'generated-uuid',
// Link to Stripe (source of truth for billing)
stripe: -> Stripe.Subscription,
// Synced from Stripe (readonly, from stripe link)
status: => stripe.status, // active|past_due|canceled|...
currentPeriodStart: => stripe.current_period_start,
currentPeriodEnd: => stripe.current_period_end,
cancelAtPeriodEnd: => stripe.cancel_at_period_end,
// Our input (what plan they're on in our system)
plan: -> Plan,
// Computed
isActive: => status == 'active',
daysRemaining: => daysBetween(now, currentPeriodEnd),
// Relationships
customer: -> Customer,
invoices: <- Invoice.subscription,
// Actions (affect Stripe)
$actions: {
cancel: -> Stripe.DELETE('/subscriptions/{stripe.id}'),
pause: -> Stripe.POST('/subscriptions/{stripe.id}/pause'),
resume: -> Stripe.POST('/subscriptions/{stripe.id}/resume'),
changePlan: (newPlan) -> Stripe.POST('/subscriptions/{stripe.id}', { price: newPlan.stripePriceId }),
}
}Observations:
- We have an entity that WRAPS an external entity
- Some fields are "passthrough" from external
- Some fields are our own
- Actions affect the external system
Syntax challenge: How to express "this field comes from linked external entity"?
Options:
status: => stripe.status(compute from relationship)status: @stripe.status(sync marker)status: stripe->status(path through relationship)
Internal, but may be linked to GitHub for code metrics.
Product = {
// Identity
id: 'generated-uuid',
// Input (we define)
name: 'Product name',
description: 'Product description',
type: 'SaaS | API | Mobile | Desktop',
// Link to code (optional)
repo: -> Github.Repo?,
// Synced from GitHub (when repo linked)
stars: => repo?.stars ?? 0,
forks: => repo?.forks ?? 0,
lastCommit: => repo?.pushed_at,
// Input (pricing)
plans: [-> Plan],
// Aggregated
activeSubscriptions: #count(subscriptions[status='active']),
mrr: #sum(subscriptions[status='active'].plan.price),
// Generated
tagline: 'One-line tagline for {name}: {description}',
// Relationships
subscriptions: <- Subscription.plan.product,
}Pure external observation.
Github.Repo = @Github('/repos/{owner}/{name}') {
// Identity (input - which repo to track)
owner: 'input:Repository owner',
name: 'input:Repository name',
// Synced fields (all readonly)
description,
stars: $.stargazers_count,
forks: $.forks_count,
openIssues: $.open_issues_count,
language,
topics,
license: $.license.spdx_id,
defaultBranch: $.default_branch,
createdAt: $.created_at,
updatedAt: $.updated_at,
pushedAt: $.pushed_at,
// Actions
$actions: {
star: -> Github.PUT('/user/starred/{owner}/{name}'),
unstar: -> Github.DELETE('/user/starred/{owner}/{name}'),
fork: -> Github.POST('/repos/{owner}/{name}/forks'),
}
}Observation: The owner and name are INPUT (we choose what to track), but everything else is SYNCED.
Primarily AI-generated, grounded against reference data.
IdealCustomerProfile = {
// Grounding (fuzzy match to reference data)
occupation: <~ Occupation, // O*NET
industry: <~ Industry, // NAICS
// Generated (AI creates from context)
as: 'What role? {occupation}',
at: 'What company type? {industry}',
doing: 'What activity?',
using: 'What tools?',
toAchieve: 'What goal?',
// Generated analysis
painPoints: ['Top pain points for {as} at {at}'],
motivations: ['Key motivations'],
objections: ['Common objections'],
// Computed
sentence: => `${as} at ${at} are ${doing} using ${using} to ${toAchieve}`,
// Relationships
problem: <- Problem.icps, // What problem they have
market: 'Size the market -> Market', // Generates Market
}Generated by AI, but then exists somewhere external (Vercel, etc.)
LandingPage = {
// Identity
id: 'generated-uuid',
slug: 'URL slug', // input
// Generated content
hero: {
headline: 'Headline for {offer.headline}',
subheadline: 'Subhead for {offer.subheadline}',
cta: 'CTA text for {offer.ctaText}',
},
sections: ['Generate sections for {offer}'],
// Deployment state (synced from hosting)
deployment: -> Vercel.Deployment?,
url: => deployment?.url,
status: => deployment?.status ?? 'draft',
// Metrics (synced from analytics)
analytics: -> Analytics.Page?,
visitors: => analytics?.visitors ?? 0,
conversions: => analytics?.conversions ?? 0,
conversionRate: => visitors > 0 ? conversions / visitors : 0,
// Relationships
offer: -> Offer,
experiment: -> Experiment,
// Actions
$actions: {
deploy: -> Vercel.POST('/deployments', { content: this.render() }),
unpublish: -> Vercel.DELETE('/deployments/{deployment.id}'),
}
}Observation: Entity starts as generated content, becomes deployed (external), then has metrics (also external).
External, but we can modify settings.
Google.Campaign = @GoogleAds('/customers/{customerId}/campaigns/{id}') {
// Identity
customerId: 'input:Google Ads customer ID',
id: 'input:Campaign ID',
// Controllable settings (we can change these)
name: 'editable:Campaign name',
status: 'editable:ENABLED | PAUSED | REMOVED',
budget: 'editable:Daily budget',
// Metrics (readonly, from Google)
impressions,
clicks,
conversions,
cost: $.cost_micros,
// Computed
ctr: => clicks / impressions,
cpc: => cost / clicks,
cpa: => cost / conversions,
// Actions
$actions: {
pause: { status: 'PAUSED' },
enable: { status: 'ENABLED' },
setBudget: (amount) => { budget: amount },
}
}Key insight: Some external fields are "editable" - we can push changes back. This is different from pure readonly sync.
Source.Type = @Source('/path/{params}') {
// input params (we provide)
param: 'input:description',
// synced fields (from API)
field: $.json.path, // or just fieldName if matches
// editable fields (can push back)
setting: 'editable:description',
// actions
$actions: { ... }
}Type = {
// our fields
field: 'description',
// link to external
external: -> Source.Type,
// passthrough from external
value: => external.field,
}(none) = input (user provides, editable)
{var} = generate (AI creates, editable)
=> = compute (derived, readonly)
@ = sync (external, readonly)
# = aggregate (collection, readonly)
editable: = sync but pushable
-> = link to (outgoing)
<- = link from (incoming)
<~ = fuzzy match (grounding)
~> = fuzzy search (finding)
-
Namespace syntax:
Github.RepovsGithub_RepovsGithubRepo? -
Mixed source fields: What if a field can be input OR synced?
email: 'input OR @stripe.email' // Use Stripe if linked, else input -
Conditional fields: Fields that only exist based on state?
canceledAt: @stripe.canceled_at if status == 'canceled' -
Versioning: How to handle schema changes in external APIs?
-
Refresh timing: When does @sync actually refresh?
stars: @Github.Repo.stars [refresh: 1h] -
Error handling: What if external source fails?
stars: @Github.Repo.stars ?? 0 // Default on error