13 reference apps. Each runs in one command.
Clone the one that looks like your problem; swap the entity declarations. Each app's full source is under examples/ in the repo. Run it with gofastr dev for rebuild-on-save, livereload, and the dev MCP tools; plain go run . works too. The in-site demo apps and the theme-layer showcases are in the menu.
Meridian: SaaS console
A billing & revenue console (customers, subscriptions, invoices, MRR + charts) plus its marketing site, auth, RBAC, and an admin back-office, seeded from one gofastr.yml and hand-evolved since, with writable screens (add/edit/delete).
- One app spec seeded marketing + app + auth + admin
- Server-rendered DataTable / charts / forms, island RPCs
- Writable CRUD + RBAC, with a generated end-to-end test suite
cd examples/meridian && gofastr dev# ============================================================================= # Meridian: SaaS billing & revenue console (GoFastr flagship demo) # # A believable product: a public marketing site + an authenticated billing # console (customers, subscriptions, invoices with real status workflows, MRR # metrics, live activity) + an admin back-office. Generated entirely from this # one app spec. Design: calm, light, refined (Stripe/Notion). # # NOTE: this app spec is the TARGET SPEC: some block kinds / features used # here are being built into the generator (server-rendered entity screens, # the full framework/ui block catalog, marketing layout, auth/RBAC). It is # authored first so the product is concrete; the generator is made to render it. # ============================================================================= app: name: Meridian module: github.com/DonaldMurillo/gofastr/examples/meridian api_prefix: api static_dir: static # Spanish (locales/es.json) lives under /es/, with hreflang, sitemap # and robots entries; English keeps the plain paths. locale_prefixes: true db: driver: sqlite url: file:meridian.db auth: enabled: true dev_mode: true admin: enabled: true path: /admin role: admin login_path: /login seed_email: admin@meridian.dev seed_password: change-me-now-123 # Calm, light, refined: warm paper, ink text, one confident indigo accent. theme: # Type: a distinctive editorial display face (Bricolage Grotesque) for # headings + a warm humanist grotesk (Hanken Grotesk) with true tabular # figures for body/data. The display face gives titles real character so # the hierarchy reads as designed, not default-bold. font_heading: Bricolage Grotesque font_body: Hanken Grotesk background: "#F8F7F4" surface: "#FFFFFF" surface-soft: "#F2F1EC" text: "#1B1B2A" text-muted: "#65657A" text-subtle: "#6A6A72" border: "#E7E5DF" border-strong: "#33334A" primary: "#4338CA" primary-fg: "#FFFFFF" secondary: "#0E7C86" accent: "#4338CA" success: "#166534" warning: "#854D0E" danger: "#B91C1C" info: "#1D4ED8" # Dark scheme: a calm warm-charcoal tinted toward the indigo brand hue. # The header's theme toggle flips to this; every surface that reads the # --color-* tokens (marketing, app, components) recolors from one place. dark: background: "#15141B" surface: "#1F1D27" surface-soft: "#29262F" text: "#ECEAF3" text-muted: "#A29FB0" text-subtle: "#9498AC" border: "#322E3D" border-strong: "#494457" primary: "#8B80F2" primary-fg: "#15141B" secondary: "#2DD4BF" accent: "#8B80F2" success: "#4ADE80" warning: "#FBBF24" danger: "#F87171" danger-fg: "#15141B" info: "#60A5FA" # ============================================================================= # DATA MODEL: the revenue domain: plans → subscriptions ← customers, # invoices, payments. Status enums are the real workflows the operator drives. # ============================================================================= entities: - name: plans crud: true mcp: true # Shared cross-tenant pricing catalog: owner_field is wrong (every # subscriber reads the same rows), so reads stay open for the pricing # pages and every write sits behind a permission the bootstrap admin # holds (see the rolePolicy in app.go). A plain signup session can # read the catalog and mutate none of it. access: read: create: plans:write update: plans:write delete: plans:admin properties: label: Plans display: title_fields: [name] description: What a customer can subscribe to. nav: group: catalog icon: box order: 1 fields: price: input: money fields: - name: name type: string required: true max: 80 - name: slug type: string required: true unique: true max: 80 - name: price type: decimal required: true min: 0 - name: interval type: enum values: [month, year] default: month - name: active type: bool default: true - name: customers crud: true mcp: true owner_field: user_id # per-user: each signed-in account owns its own customers search_fields: [name] properties: label: Customers # Unique per owner, never across owners: a global UNIQUE on email # would let one account's row block another account's create and turn # the 409 into an "this email exists somewhere" oracle. indices: - name: idx_customers_owner_email columns: [user_id, email] unique: true fields: - name: name type: string required: true max: 120 - name: email type: string required: true - name: company type: string max: 120 - name: status type: enum values: [trialing, active, past_due, canceled] default: trialing - name: mrr type: decimal min: 0 default: "0" - name: logo type: image display: title_fields: [name] description: Every account that pays you. nav: group: billing icon: users order: 1 columns: [name, email, company, status, mrr] views: - key: active label: Active where: 'status = "active"' - key: past_due label: Past due where: 'status = "past_due"' facets: [status] fields: email: input: email mrr: label: MRR input: money - name: subscriptions crud: true mcp: true owner_field: user_id properties: label: Subscriptions fields: - name: customer_id type: relation to: customers required: true - name: plan_id type: relation to: plans required: true - name: status type: enum values: [trialing, active, past_due, canceled] default: trialing - name: mrr type: decimal min: 0 default: "0" - name: started_on type: date - name: renews_on type: date display: title_fields: [customer_id, plan_id] description: Who is on which plan, and what they bring in. nav: group: billing icon: repeat order: 2 views: - key: active label: Active where: 'status = "active"' - key: trialing label: Trialing where: 'status = "trialing"' - key: past_due label: Past due where: 'status = "past_due"' facets: [status] fields: mrr: label: MRR input: money relations: - type: belongs_to name: customer entity: customers foreign_key: customer_id - type: belongs_to name: plan entity: plans foreign_key: plan_id # Advisory as above: the screen transitions named no From. states: field: status advisory: true transitions: - key: activate label: Activate from: [trialing, past_due] to: active variant: primary - key: cancel label: Cancel from: [trialing, active, past_due] to: canceled variant: danger - name: invoices crud: true mcp: true owner_field: user_id search_fields: [number] properties: label: Invoices indices: - name: idx_invoices_owner_number # unique per owner, as customers.email columns: [user_id, number] unique: true fields: - name: customer_id type: relation to: customers required: true - name: number type: string required: true - name: amount type: decimal required: true min: 0 - name: status type: enum values: [draft, open, paid, past_due, void] default: draft - name: issued_on type: date - name: due_on type: date - name: paid_on type: date relations: - type: belongs_to name: customer entity: customers foreign_key: customer_id # The old screen-level transitions named no From, so the moves stay # advisory until the from-lists below are confirmed; drop advisory: # to let the CRUD handler enforce them. states: field: status advisory: true transitions: - key: mark_paid label: Mark paid from: [draft, open, past_due] to: paid variant: primary stamp: paid_on - key: void label: Void from: [draft, open, past_due] to: void variant: danger display: title_fields: [number] description: Every invoice issued, paid or not. nav: group: billing icon: receipt order: 3 columns: [number, customer_id, amount, status, issued_on, due_on] views: - key: past_due label: Past due where: 'status = "past_due"' sort: due_on ASC - key: open label: Open where: 'status = "open"' sort: due_on ASC facets: [status, customer_id] fields: amount: input: money - name: payments crud: true mcp: true owner_field: user_id # A deleted payment goes to the admin's trash, where it can be # restored or deleted for good. soft_delete: true properties: label: Payments display: title_fields: [invoice_id, customer_id] description: Money in, and the attempts that failed. nav: group: billing icon: card order: 4 views: - key: failed label: Failed where: 'status = "failed"' facets: [status, method] fields: amount: input: money fields: - name: invoice_id type: relation to: invoices required: true - name: customer_id type: relation to: customers required: true - name: amount type: decimal required: true min: 0 - name: method type: enum values: [card, ach, wire] default: card - name: status type: enum values: [succeeded, failed, refunded] default: succeeded relations: - type: belongs_to name: invoice entity: invoices foreign_key: invoice_id - type: belongs_to name: customer entity: customers foreign_key: customer_id # ============================================================================= # SCREENS in three layers and two layouts: # layout: marketing → public site (own siteheader + sitefooter packages) # layout: app → authenticated console (sidebar shell), access-gated # ============================================================================= screens: # ---- Public marketing site ------------------------------------------------- - name: home route: / layout: marketing title: "Meridian: billing that runs itself" description: The revenue console for modern SaaS. body: - kind: stack props: gap: 2xl children: - kind: hero props: eyebrow: Billing & revenue title: See your revenue the moment it moves. subtitle: Meridian gives SaaS teams one calm place to manage customers, subscriptions, and invoices, with the metrics that matter, live. cta_text: Start free cta_href: /signup secondary_text: See pricing secondary_href: /pricing - kind: section props: heading: Everything you need to run revenue eyebrow: Why Meridian children: - kind: card props: heading: Live MRR & churn text: Watch monthly recurring revenue, growth, and churn update as customers sign up and pay. - kind: card props: heading: Subscriptions that flow text: "Trialing, active, past-due, canceled: drive the whole lifecycle from one screen." - kind: card props: heading: Invoices, handled text: "Open, paid, void: track every invoice and mark them paid in a click." # The app's closing CTA (an ink-band ui.Themed card in screens.go) is # hand-authored past the app spec vocabulary: generate once, then own # the Go. pack skips it, so it has no block here. - name: pricing route: /pricing layout: marketing title: Pricing description: Plans for teams of every size. body: - kind: stack props: gap: 2xl children: - kind: page_header props: title: Pricing subtitle: Start free. Upgrade when revenue does. - kind: pricing props: plans: - name: Starter price: "$29" period: /mo description: For solo founders finding their first customers. features: ["Up to 100 customers", "Core billing & invoices", "Email support"] cta_text: Start free cta_href: /signup - name: Pro price: "$99" period: /mo description: For growing teams that live in their revenue. featured: true features: ["Unlimited customers", "MRR & churn analytics", "Subscription workflows", "Priority support"] cta_text: Start free cta_href: /signup - name: Scale price: "$299" period: /mo description: For high-volume revenue and finance teams. features: ["Everything in Pro", "SSO & audit log", "Dedicated success manager", "99.9% uptime SLA"] cta_text: Contact sales cta_href: /signup # ---- About: the plain heading/paragraph content path (readable measure) ---- - name: about route: /about layout: marketing title: About Meridian description: Why we built a calmer billing console. body: - kind: stack props: gap: 2xl children: - kind: page_header props: title: We think billing should feel calm. - kind: markdown text: "Meridian is a demonstration product built entirely from a GoFastr app spec, a single declarative file that generates this marketing site, the authenticated console, auth, roles, and an admin back-office, all server-rendered.\n\nIt exists to show that a framework can generate a real, polished web application, not a CRUD scaffold." # ---- Terms + Privacy: the markdown content path (rich long-form prose) ------ - name: terms route: /terms layout: marketing title: Terms of Service body: - kind: markdown text: "# Terms of Service\n\nThis is a demonstration application. The text below is placeholder content that shows long-form, **readable** typography rendered from Markdown in the marketing layout.\n\n## Acceptance\n\nBy using Meridian you agree these terms are illustrative only: there is no real service, billing, or obligation.\n\n## Use of the service\n\n- Evaluate Meridian freely for any purpose.\n- Sample data is reset periodically without notice.\n- Don't rely on it for anything that matters.\n\n## Liability\n\nMeridian is provided *as-is*, without warranty of any kind." - name: privacy route: /privacy layout: marketing title: Privacy Policy body: - kind: markdown text: "# Privacy Policy\n\nMeridian is a demo and stores only the sample data you create while exploring it. The content below is placeholder Markdown.\n\n## What we collect\n\nNothing personal. A demo account and any records you add in the console, all reset periodically.\n\n## What we share\n\nNothing. There are no third parties, trackers, or analytics in this demonstration app." # ---- Auth ------------------------------------------------------------------ - name: login route: /login layout: marketing title: Sign in body: - kind: login_form text: Sign in to Meridian props: action: /auth/login next: /app register_href: /signup - name: signup route: /signup layout: marketing title: Create your account body: - kind: signup_form text: Create your Meridian account props: action: /auth/register next: /app login_href: /login # ---- App (authenticated, RBAC-gated) -------------------------------------- - name: dashboard route: /app layout: app access: auth: true title: Overview description: Your revenue at a glance. body: - kind: page_header props: title: Overview subtitle: Revenue at a glance - kind: stat_row children: - kind: stat_card props: label: MRR # Real MRR: summed from ACTIVE subscriptions, not a stored column. source: entity: subscriptions agg: sum field: mrr filter: status=active format: money - kind: stat_card props: label: Active customers source: entity: customers agg: count filter: status=active - kind: stat_card props: label: Past-due invoices source: entity: invoices agg: count filter: status=past_due - kind: stat_card props: label: Plans source: entity: plans agg: count - kind: bar_chart props: title: Customers by status source: entity: customers group_by: status - kind: entity_list entity: invoices text: Recent invoices fields: [number, customer_id, amount, status, due_on] limit: 8 empty_text: No invoices yet. - name: customers route: /app/customers layout: app access: auth: true title: Customers body: - kind: entity_list entity: customers text: Customers fields: [name, email, company, status, mrr] limit: 8 create: true empty_text: No customers yet. Add your first to get started. - name: customer_detail route: /app/customers/{id} layout: app access: auth: true title: Customer body: - kind: entity_detail entity: customers - name: invoices route: /app/invoices layout: app access: auth: true title: Invoices body: - kind: entity_list entity: invoices text: Invoices fields: [number, customer_id, amount, status, issued_on, due_on] limit: 25 create: true bulk: true empty_text: No invoices yet. - name: invoice_detail route: /app/invoices/{id} layout: app access: auth: true title: Invoice body: - kind: entity_detail entity: invoices - name: subscriptions route: /app/subscriptions layout: app access: auth: true title: Subscriptions body: - kind: entity_list entity: subscriptions text: Subscriptions fields: [customer_id, plan_id, status, mrr, renews_on] limit: 25 create: true empty_text: No subscriptions yet. - name: subscription_detail route: /app/subscriptions/{id} layout: app access: auth: true title: Subscription body: - kind: entity_detail entity: subscriptions # ============================================================================= # NAV: marketing header/footer + app sidebar # ============================================================================= nav: - label: Overview href: /app - label: Customers href: /app/customers - label: Subscriptions href: /app/subscriptions - label: Invoices href: /app/invoices - label: Admin href: /admin role: admin # only signed-in admins see this link # ============================================================================= # SEED: realistic sample data so a fresh boot shows a populated console. # ============================================================================= seed: - entity: plans rows: - name: Starter slug: starter price: "29" interval: month active: true - name: Pro slug: pro price: "99" interval: month active: true - name: Scale slug: scale price: "299" interval: month active: true - entity: customers rows: - name: Ada Lovelace email: ada@acme.io company: Acme Inc status: active mrr: "99" - name: Grace Hopper email: grace@globex.com company: Globex status: active mrr: "299" - name: Alan Turing email: alan@initech.io company: Initech status: past_due mrr: "29" - name: Katherine Johnson email: kj@umbrella.co company: Umbrella status: active mrr: "99" - name: Linus Torvalds email: linus@hooli.com company: Hooli status: canceled mrr: "0" - name: Margaret Hamilton email: mh@apollo.io company: Apollo status: active mrr: "299" - name: Dennis Ritchie email: dmr@belllabs.com company: Bell Labs status: trialing mrr: "0" - name: Barbara Liskov email: liskov@mit.edu company: MIT status: active mrr: "99" - name: Tim Berners-Lee email: tbl@w3.org company: W3C status: past_due mrr: "29" - name: Donald Knuth email: knuth@stanford.edu company: Stanford status: active mrr: "299" # Relational seed: customer_id / plan_id reference rows seeded above by a # natural key ("@entity.field=value"); the seed runner resolves them to the # generated ids before insert. Order matters: plans + customers first. - entity: subscriptions rows: - customer_id: "@customers.email=ada@acme.io" plan_id: "@plans.slug=pro" status: active mrr: "99" started_on: "2025-09-04" renews_on: "2026-07-04" - customer_id: "@customers.email=grace@globex.com" plan_id: "@plans.slug=scale" status: active mrr: "299" started_on: "2025-06-12" renews_on: "2026-06-12" - customer_id: "@customers.email=alan@initech.io" plan_id: "@plans.slug=starter" status: past_due mrr: "29" started_on: "2025-11-20" renews_on: "2026-05-20" - customer_id: "@customers.email=kj@umbrella.co" plan_id: "@plans.slug=pro" status: active mrr: "99" started_on: "2025-10-01" renews_on: "2026-07-01" - customer_id: "@customers.email=linus@hooli.com" plan_id: "@plans.slug=scale" status: canceled mrr: "0" started_on: "2024-12-15" renews_on: "2025-12-15" - customer_id: "@customers.email=mh@apollo.io" plan_id: "@plans.slug=scale" status: active mrr: "299" started_on: "2025-03-22" renews_on: "2026-06-22" - customer_id: "@customers.email=dmr@belllabs.com" plan_id: "@plans.slug=pro" status: trialing mrr: "0" started_on: "2026-06-01" renews_on: "2026-06-15" - customer_id: "@customers.email=liskov@mit.edu" plan_id: "@plans.slug=pro" status: active mrr: "99" started_on: "2025-08-09" renews_on: "2026-07-09" - customer_id: "@customers.email=tbl@w3.org" plan_id: "@plans.slug=starter" status: past_due mrr: "29" started_on: "2025-12-02" renews_on: "2026-06-02" - customer_id: "@customers.email=knuth@stanford.edu" plan_id: "@plans.slug=scale" status: active mrr: "299" started_on: "2025-05-18" renews_on: "2026-06-18" - entity: invoices rows: - customer_id: "@customers.email=ada@acme.io" number: INV-1001 amount: "99" status: paid issued_on: "2026-05-04" due_on: "2026-05-18" paid_on: "2026-05-06" - customer_id: "@customers.email=grace@globex.com" number: INV-1002 amount: "299" status: paid issued_on: "2026-05-12" due_on: "2026-05-26" paid_on: "2026-05-13" - customer_id: "@customers.email=alan@initech.io" number: INV-1003 amount: "29" status: past_due issued_on: "2026-04-20" due_on: "2026-05-04" - customer_id: "@customers.email=kj@umbrella.co" number: INV-1004 amount: "99" status: paid issued_on: "2026-05-01" due_on: "2026-05-15" paid_on: "2026-05-02" - customer_id: "@customers.email=mh@apollo.io" number: INV-1005 amount: "299" status: open issued_on: "2026-06-01" due_on: "2026-06-15" - customer_id: "@customers.email=liskov@mit.edu" number: INV-1006 amount: "99" status: paid issued_on: "2026-05-09" due_on: "2026-05-23" paid_on: "2026-05-11" - customer_id: "@customers.email=tbl@w3.org" number: INV-1007 amount: "29" status: past_due issued_on: "2026-04-02" due_on: "2026-04-16" - customer_id: "@customers.email=knuth@stanford.edu" number: INV-1008 amount: "299" status: paid issued_on: "2026-05-18" due_on: "2026-06-01" paid_on: "2026-05-19" - customer_id: "@customers.email=grace@globex.com" number: INV-1009 amount: "299" status: open issued_on: "2026-06-12" due_on: "2026-06-26" - customer_id: "@customers.email=ada@acme.io" number: INV-1010 amount: "99" status: open issued_on: "2026-06-04" due_on: "2026-06-18" - customer_id: "@customers.email=knuth@stanford.edu" number: INV-1011 amount: "299" status: paid issued_on: "2026-04-18" due_on: "2026-05-02" paid_on: "2026-04-20" - customer_id: "@customers.email=kj@umbrella.co" number: INV-1012 amount: "99" status: past_due issued_on: "2026-04-15" due_on: "2026-04-29" - entity: payments rows: - invoice_id: "@invoices.number=INV-1001" customer_id: "@customers.email=ada@acme.io" amount: "99" method: card status: succeeded - invoice_id: "@invoices.number=INV-1002" customer_id: "@customers.email=grace@globex.com" amount: "299" method: card status: succeeded - invoice_id: "@invoices.number=INV-1004" customer_id: "@customers.email=kj@umbrella.co" amount: "99" method: ach status: succeeded - invoice_id: "@invoices.number=INV-1006" customer_id: "@customers.email=liskov@mit.edu" amount: "99" method: card status: succeeded - invoice_id: "@invoices.number=INV-1008" customer_id: "@customers.email=knuth@stanford.edu" amount: "299" method: wire status: succeeded - invoice_id: "@invoices.number=INV-1011" customer_id: "@customers.email=knuth@stanford.edu" amount: "299" method: wire status: succeeded - invoice_id: "@invoices.number=INV-1003" customer_id: "@customers.email=alan@initech.io" amount: "29" method: card status: failed - invoice_id: "@invoices.number=INV-1012" customer_id: "@customers.email=kj@umbrella.co" amount: "99" method: card status: failed
ShopFront: storefront
A complete storefront from one gofastr.yml: five related entities (categories, products, orders, order_items, reviews), a themed eight-screen UI, custom endpoints, and seed data. Nothing under app/ is hand-written.
- Second app generator beside Meridian
- Owner-scoped orders and reviews
- Exercised by its own end-to-end test
cd examples/ecommerce && gofastr dev --dir app# 5 entities, 8 screens, auth, seeds: one YAML $ gofastr generate // emits ./app: plain Go $ go run ./app
Go-declared blog
Users, posts, comments. Three entities. Start here: it's the end-to-end story in one file.
- Three entities declared in Go
- Auto-CRUD + Swagger UI + MCP
- SQLite by default; swap for Postgres in main.go
cd examples/blog && gofastr devapp.Entity("users", …) app.Entity("posts", …) app.Entity("comments", …) app.Start(":8080")
This site (UI showcase)
Every core-ui pattern + framework/ui component, one page each, plus the docs, SEO, multi-step wizard, and print-battery demos. The site you're reading right now.
- Every core-ui pattern + framework/ui component
- Docs, philosophy, examples, Kiln pages
- SEO interfaces, sitemap/robots, wizard, print
cd examples/site && gofastr devhost := uihost.New(site, …) app := framework.NewUIHostApp(host) app.Start(":8083")
API tour
Every v2 API feature in one annotated main.go, with the curl commands to exercise each one in the file header.
- Cursor + offset pagination
- Eager loading (?include=…)
- Batch endpoints, SSE entity events, uploads
cd examples/api-tour && gofastr devapp.Entity("posts", …) // cursor + offset paging, ?include=, batch, SSE app.Start(":8080")
Local semantic search
A markdown corpus indexed locally via battery/semantic. No external API key; works offline.
- Brute-force cosine, hybrid keyword fusion
- Snapshot + WAL persistence
- Poll-watch for file changes
cd examples/semantic-demo && gofastr devidx, _ := semantic.Open(semantic.Options{…}) idx.Add(ctx, docs…) // local vectors hits, _ := idx.Query(ctx, semantic.Query{Text: "hooks", Limit: 5})
Vue + GoFastr API
For teams who already have a client app. Shows the framework is happy to just be your typed API.
- Same auto-CRUD entities
- Vue 3 + Vue Router from a CDN, no npm, no build step
- No SSR: the Go app serves JSON and the static files
cd examples/spa && gofastr devapp.Entity("articles", …) // JSON API under /api: your Vue app is the client app.Start(":3090")
Embeddable surfaces
Two servers on different ports: a GoFastr app, and a customer's website that pastes one script tag and gets a live, themed, authenticated panel from it.
- Single-use handshake nonce, exact origin allowlist
- Frame runtime with no SPA navigation
- Customer brand token applied to the app's own components
cd examples/embed-demo && gofastr devembeds, _ := embed.New(embed.Config{…}) nonce, _ := embeds.MintNonce("reports", user.ID, origin, nil) // the customer pastes: <script src=".../__gofastr/embed.js" data-token=…>
Static file server
A plain file server on the framework router: static.Mount serves the pages/ directory, with HTML and CSS straight from disk, no screens, no runtime JS.
- static.Mount with SPA mode off: only real files serve
- index.html answers /
- API routes can mount beside it on the same router
cd examples/static-site && gofastr devstatic.Mount(app.Router(), static.Config{ FS: os.DirFS(pagesDir), }) app.Start(":3070")
Entity admin
Three entities and one admin.New call: the whole back-office (list, create, edit, delete) is generated with defaults, behind a demo login. No bespoke JavaScript anywhere in the app.
- admin.New with AllEntities: true generates every screen
- DataTable island paginates without a reload
- Delete is a data-cui-confirm button; forms are server-rendered
cd examples/backoffice && gofastr devapp.Entity("products", …) app.RegisterBattery(admin.New(admin.Config{ Title: "Backoffice", AllEntities: true, }))
Process-isolated module
A third-party module as its own process, plus the host app that runs it. The module speaks moduleproto over stdio, serves four routes and one tool, and answers a reverse entity query. The host registers it as an untrusted module, so it runs only where the sandbox passes every probe.
- The module depends only on moduleproto + the standard library
- Handshake, ready, health, http, drain, tool.list, tool.call
- The host refuses the module, with the probe report, where the sandbox does not conform
go run ./examples/processmodule-demo/host -module dist/examples/processmodule-democodec, _ := moduleproto.NewCodec(os.Stdin, os.Stdout, …) peer := moduleproto.NewPeer(codec, moduleproto.RoleChild) peer.Handle(moduleproto.MethodHTTP, serveRoute) peer.Start(); <-peer.Done()
WebMCP remote assist
One binary, one origin, two roles: a support console whose in-browser agent guides an operator through a camera session. Support-only WebMCP tool discovery, one typed command behind the button and the tools, and peer-to-peer video with server-side signaling only.
- Tools scoped to /support and authorization-wrapped
- Role cookies authorize; the WebMCP header only attributes
- Sequenced realtime state over the ws runtime module
cd examples/webmcp-remote-assist && gofastr devtools := webmcp.New(webmcp.WithInstructions(…)) group.Handle(rt, sendInstruction, handler, webmcp.WithHTTPMiddleware(requireSupport)) webmcp.WithDocumentScope(supportScope)
WebRTC call rooms
Anonymous users, rooms by name: the dogfood app for the rtc signaling battery. The lobby trades a display name for a cookie; the room page runs one peer connection per peer with chat on a negotiated data channel, and the Go process relays handshakes only, never media.
- rtc.New + RegisterPlugin: zero hand-rolled signaling
- Identity server-derived through Config.Authorize
- Peer-to-peer camera and chat; the server sees neither
cd examples/rtc-call && gofastr devsig := rtc.New(rtc.Config{ … } app.RegisterPlugin(sig)
Four more app specs
Each is one gofastr.yml with no Go beside it. Generate in the directory to get a runnable app you own; every one is validated by the CLI's app spec test suite.
- lms: courses, lessons, enrollments
- portfolio: projects and case studies
- project-manager: projects, tasks, teams
- real-estate: listings, agents, inquiries
cd examples/lms && gofastr generate app gofastr.yml# entities, screens, nav, endpoints, seed: one YAML $ gofastr generate app gofastr.yml $ go run .