Skip to content

Case study · hero · 2026-01 to present

Nibbble

Founded a multi-tenant restaurant loyalty SaaS, set the product strategy, designed every surface, and led a small AI-assisted build with a developer collaborator to a production v1 validated by a four-restaurant customer council.

Role
Founder and product leader (strategy, design, and delivery)
Company
Nibbble.io
Dates
2026-01 to present
Bucket
current venture

Impact registry

Product status

Live in production

app.nibbble.io, launched 2026-04-22, still stable

Validation

Four-restaurant customer council

Two in active beta

Nibbble marketing homepage hero: editorial serif headline Built for the people behind the counter on a warm radial sunburst background, with a green Join the Waitlist call-to-action
Nibbble · HomepageEditorial-first homepage. One promise, one call-to-action, one mood. This is software for the operator at the register, not the chain-restaurant boardroom.

TL;DR

I founded Nibbble to give independent restaurants loyalty tools that fit how they actually operate. It is a live multi-tenant SaaS at app.nibbble.io: three role-specific portals, Square POS, Stripe billing, and a shared token layer, shipped 2026-04-22 and still running. A four-restaurant customer council validated it, two are in active beta, and it is pre-revenue by design. The strategy and design are mine end to end; Ahsan Amjed was my developer collaborator, with two others co-authoring commits.

Three surfaces, not one role-gated app

The easy version is a punch card with a login screen. Independent restaurants need a system that respects how they actually operate: the owner thinks about margin and repeat visits, staff need speed between orders, customers need a reason to return without homework.

Started with the operating model, not the feature list. Nibbble is three products sharing one spine (owner, staff, customer), each with a different job on the same architecture. The harder challenge was keeping that system coherent while building primarily with AI agents. Without the right scaffolding, agents drift the system every week.

Three users, one system

One shared layer. Three distinct surfaces.

Lane 01

Owner

Surface
Management console
Goal
Configure rewards, read the numbers.

Lane 02

Staff

Surface
Counter app
Goal
Apply and redeem between orders.

Lane 03

Customer

Surface
Wallet + scan flow
Goal
Earn points, redeem at checkout.

Shared foundation

  • Shared data model
  • Design tokens
  • Role-based access

Integrations

  • Square POS
  • Stripe billing
  • Rewards engine
Three distinct surfaces, owner, staff, and customer, on one shared data model and token layer, wired to Square, Stripe, and the rewards engine.

Three portals, one product

3 points

The Nibbble app surface: the round green N badge, the wordmark, a one-line value proposition, and three portal cards labeled Customers, Staff, and Admin.
01 · Customer: scan and go

Check points, redeem rewards, view history. The smallest scope, tuned for a few seconds at the counter.

Customers earn, staff serve, admins configure. Same data model, three discrete scopes. The shared token layer is what keeps the system coherent. Select a marker to read each scope.

What I did

  • Defined the product strategy for independent restaurants, not enterprise chains. The customer council of four restaurants validated decisions before they shipped.
  • Designed the core experience across owner, staff, and customer workflows. Three distinct surfaces with different primary actions: admin carries full configuration weight, staff is built around one high-frequency action during rush, customer is built for scan-and-go on a phone.
  • Led the production v1 build with Ahsan Amjed: Square POS integration, Stripe billing, multi-tenant Postgres with row-level security, and scheduled operational jobs. Launched 2026-04-22 at app.nibbble.io.
  • Created a shared design-token system so three portals feel like one product. Three distinct layouts, one coherent system.

The fork that organized the design: one role-gated app, or three distinct surfaces. The cheap path was a single app that hid and revealed sections by role. It ships faster and shares one codebase. I rejected it because the three users are not the same person with different permissions. They have different anxieties and different tempos: the owner reasons about margin, the server needs one action during a rush, the customer wants scan-and-go with no homework. Role-gating would have forced a shared layout to serve all three and served none of them well. I shipped three distinct surfaces on one shared data model and token layer instead. The token layer is what pays down the cost of that decision: three layouts stay coherent without three separate design systems to maintain.

Built around the people at the register

Three roles. Four questions each.

Role 01

Owner

Job
Grow repeat visits and protect margin.
Anxiety
Is this worth my time to run?
Core action
Configure rewards, read the daily numbers.
Success
Regulars coming back on their own.

Role 02

Staff

Job
Run it between orders.
Anxiety
Don't slow the line.
Core action
Apply and redeem in seconds.
Success
Fast, no friction at the counter.

Role 03

Customer

Job
Get rewarded for loyalty.
Anxiety
Not another chore.
Core action
Earn and redeem at checkout.
Success
A real reason to return.
Job, anxiety, core action, and success, mapped for every person at the register.

Three portals, one shared layer

Discrete scopes, one product surface.

Portal 01

Customer

  • Scan and go redeem.
  • View points history.

Portal 02

Staff

  • Search and check in during rush.
  • Manage orders.

Portal 03

Admin

  • Configure loyalty rules.
  • Stripe billing.
  • Multi-tenant analytics.

Shared data and tokens

  • Postgres with RLS
  • HeroUI v3 contracts
  • Square POS
  • Stripe
  • OpenClaw routing
Three discrete scopes, one shared data and tokens layer. The cheap path was one role-gated app. I shipped three distinct surfaces instead.

The AI operating model that kept the system coherent

Building primarily with AI agents drifts the system on a weekly clock. Left to the prompt alone, agents touch files they should not, let docs fall out of sync with code, and re-solve problems the codebase already solved. On a three-portal SaaS held together by a shared token layer, that drift is the difference between one coherent product and three that slowly diverge.

So I put the safety in the runner, not the prompt, where an agent cannot argue its way past it. The auto-fix loop runs behind a hard path allow-list with a one-file-per-fix limit, a pre-push hook blocks any code change that skips a docs update, and CI requires a second-model review before anything merges. A codebase-memory graph lets agents query the system's structure before editing instead of grepping blind.

That is governance with a receipt, not a slogan: the loop has landed 17 real commits against real failures, gated behind the allow-list rather than running as a demo. Speed did not become drift.

NIBBBLE · 2026

Autofix commits landed

Local Ollama loop on Nibbble, 2026.

Free per attempt. Real diffs, allow-list gated.

The runner-level rails in practice: the local auto-fix loop landing real diffs against real failures, one file at a time.

Phase 2 shipped (2026-07)

Four features that close the loop from product promise to measurable outcome, shipped via parallel worktree agents with Ahsan Amjed:

  • White-label theming: the customer portal now renders in the restaurant's brand colors and logo. Previously admin stored the brand data; Phase 2 applied it end-to-end.
  • Baseline event log: the north-star metric (repeat-visit lift) was previously unmeasurable because insights were snapshots. The event log makes it measurable for the first time. Cohort queries follow in the next phase.
  • PWA home-screen layer: diners authenticate via phone OTP and are mobile-first. The PWA manifest and service worker give the customer portal a native-feeling install path on the device they already have in their pocket.
  • Notification delivery worker: provider-pluggable (log default, Twilio env-gated). Enqueues on tier upgrade and punch-card completion with deduplication, so the notification loop is closed end-to-end rather than scaffolded and waiting.

A security fix that became a class-level fix

A punch-card bug (one restaurant could award loyalty value to another restaurant's customers) revealed a pattern across multiple staff-authenticated routes: each trusted a restaurant_id supplied in the request body rather than binding it to the caller's token. The routes were distinct but the vulnerability was the same shape.

Fixed the routes, then widened the CI guard to cover every verifyStaffAuth route, not just the admin paths the structural test already watched. The class is now enforced at the CI layer, not just at the instance that surfaced the problem.

What changed

Nibbble moved from idea to live SaaS with a business model, a customer council, a production foundation, and a system for keeping product decisions coherent as it grows.

  • Production multi-tenant SaaS running at app.nibbble.io since 2026-04-22: three portals, Square POS, Stripe billing, multi-tenant data layer.
  • A customer council of four restaurants, two in active beta. Pre-revenue by design: at this stage the asset is operator-validated product decisions and production discipline, with revenue as the next milestone.
  • Phase 2 shipped: white-label theming, baseline event log (north-star now measurable), PWA, and notification delivery, wired end-to-end.
  • A documented multi-agent development stack where design, product, and engineering choices stayed connected through the build.

Commit attribution

Commit authorship donut, 387 of 412 on mainA donut chart of commit attribution on the Nibbble main branch. The brass arc represents 387 commits authored by Mohsin Amjed. The muted arc represents the remaining 25 commits from other contributors.
387 / 412Commits on main, twelve weeks
Mohsin
387
Others
25
Authorship across the build. I authored the majority of commits, with Ahsan Amjed and two co-authors on the rest. The point is that design, product, and engineering decisions stayed connected throughout.

Reflection

Encode the guardrail where it cannot be argued away. Putting the allow-list, docs gate, and second-model review in the build system rather than the prompt is what let a small team move fast without the system fragmenting. A prompt can be forgotten or overridden; a runner cannot. That is the pattern I carry into any AI-native team I lead.

Stress-test the roadmap from the demand side, not just the engineering side. Running a three-lens review (CEO, CTO, CDO seats, each grounded in a code audit before forming an opinion) surfaced that the roadmap was complete and well-sequenced for engineering while missing its entire demand side: no pilots, no positioning, no revenue motion. Only role-forcing exposed it. The output was a new "Prove it" phase inserted before product expansion: positioning one-pager, named pilots, and the baseline event log that makes lift measurable. The roadmap now carries all three lenses with provenance, ready for Ahsan and me to ratify owners and dates.

Two things I would do differently:

1. I optimized for build discipline before I had demand proof. Nibbble is pre-revenue by design, but that framing can hide a real risk. I built runner-level rails, a docs-sync gate, and a token layer before a single restaurant paid. The next proof has to be usage, retention, revenue, or operator behavior, not more build velocity or a cleaner commit history. If I ran this again, I would spend the customer council on willingness-to-pay signals earlier, not just design validation. 2. Three surfaces was the right call, but I under-invested in the seam too long. The three-portal decision holds up. What I would change is timing: the shared token layer is the only thing keeping three layouts from becoming three design systems, and I treated it as infrastructure to harden later rather than the load-bearing decision it was. Running this with a Director of Product Design team, a design-systems lead would own that token layer from day one.

Nibbble is what it looks like to turn ambiguity into a shipped product without letting it fragment.