πŸ” Lens

August 27, 2026 Β· View on GitHub

πŸ” Lens

The developer's viewfinder for the Cratis Stack β€” become any user, step into any tenant, and fire commands and queries at your running app, straight from the browser.

Discord Build Publish License


On a film set, the lens is what the camera sees the scene through β€” swap it and the whole shot changes: a new angle, a tighter focus, a different depth of field. That's the idea. Lens is the lens you point at your running Cratis Arc application while you build it: watch it as a different user, from inside a different tenant, and focus right in on a single command or query to see exactly what the backend does β€” no rebuild, no hand-crafted headers, no leaving the page you're already on.

The friction it removes is real: no more pasting identity headers into a REST client, no more restarting the app to switch tenants, no more writing throwaway test harnesses just to see what a query returns.

Arc is the CQRS layer for ASP.NET Core over Chronicle, the MIT-licensed event-sourcing database β€” and Lens is the development-time companion for any app built on it.

πŸ” Why "Lens"?

Three reasons, and they all line up:

  • The camera lens sets the point of view. A cinematographer chooses the lens to decide what the audience sees and how it's framed. Lens does the same for your app in development: choose the user, choose the tenant, and every request is framed from that point of view.
  • A lens is also what you inspect through. Beyond the camera, a lens magnifies and focuses β€” it's an instrument for seeing clearly. Lens brings your commands and queries under the glass so you can test them and read back exactly what they return.
  • The Cratis storytelling family. Cratis names its products after telling a story: Chronicle records what happened, Arc shapes the plot, Screenplay is the script, Stage performs it, Studio storyboards it, Narrator reads it back… Lens is the camera you watch the rehearsal through. It joins the cast.

πŸŽ₯ What a session looks like

Lens lives in your browser toolbar. Open the popup and you're directing the shot:

  • 🏒 Pick a tenant β€” the tenancy header is injected into every request; test multi-tenant behavior without touching config or restarting.
  • πŸ‘€ Pick a user β€” identity, claims, and permissions ride along, so the backend authorizes the request as that person.
  • πŸ§ͺ Browse the cast β€” Lens introspects the app's /.cratis/commands and /.cratis/queries endpoints and lists every command and query, grouped by namespace; fill in parameters, fire it, and read the response inline.
  • πŸ”§ Check the frame β€” the current tenant, user, and identity context are always visible at a glance.

Nothing about your frontend changes β€” Lens injects at the network boundary, transparently, only while the extension is active.

🧠 How it works β€” header injection at the boundary

When the extension is active, Lens rewrites the requests your web app makes, adding the headers your backend already expects. Your code is none the wiser:

flowchart LR
    You["πŸ§‘β€πŸ’» you<br/>in the browser"] -->|"HTTP request"| Lens{{"πŸ” Lens<br/>injects headers"}}
    Ctx["🏒 tenant Β· πŸ‘€ user<br/>chosen in the popup"] -.->|"identity + tenancy<br/>headers"| Lens
    Lens -->|"tenant-scoped,<br/>authenticated request"| Arc["βš™οΈ your Cratis Arc<br/>backend"]
    Arc -->|"command / query result"| You
  • Identity headers β€” when you select a user, Lens injects the context, claims, and permissions your backend reads for authorization, following the Cratis Arc authentication specification.
  • Tenancy headers β€” when you select a tenant, Lens injects the tenant identifier that routes the request to the right partition, following the Cratis Arc tenancy resolvers specification.
  • Automatic propagation β€” the headers ride along on command execution, query requests, and any HTTP call your app makes, so the backend always receives a properly authenticated, tenant-scoped request.
  • A clean cut on every switch β€” headers alone don't change who you are once the backend has issued a session. Changing the active user or tenant clears the Arc .cratis-identity cookie on the configured origins and reloads the matching tabs, so the next request is authenticated as the person you just picked.

✨ Features at a glance

FeaturePurpose
🏒 Tenant SelectorSwitch tenants instantly; the tenancy header is auto-injected
πŸ‘€ User SelectorSimulate different users; identity, claims, and permissions follow
πŸ”Œ Arc Development SourcesPoint Lens at a local or remote Cratis Arc backend
πŸ§ͺ Command ExplorerBrowse and execute backend commands with real parameters
πŸ§ͺ Query ExplorerRun queries and inspect the payloads that come back
πŸ“ˆ Query DiagnosticsWatch live observable-query health, transport, multiplexer and cache state
πŸ”§ Context ViewSee the current tenant, user, and identity context

πŸš€ Quick start

Build the extension and load it into Chrome:

cd Source
yarn install
yarn build                 # bundles the unpacked extension into Source/dist/

Then, in Chrome:

  1. Open chrome://extensions/
  2. Enable Developer mode
  3. Click Load unpacked and select the Source/dist folder

Now open your Cratis Arc app in the browser, open the Lens popup once so it detects the Arc context, then use Settings to add your Arc Development Sources (local or remote endpoints) and set up the users and tenants for your scenarios. The full walkthrough β€” including watch-mode development and release publishing β€” is in Documentation/GettingStarted.

For active development with hot reload:

cd Source
yarn dev                   # Vite rebuilds on change; reload the extension after each build
yarn test                  # run the specs
yarn ci                    # typecheck, specs and build β€” the same gate CI runs

πŸ—ΊοΈ What's in this repo

Source/
β”œβ”€β”€ manifest.json           # extension manifest (MV3)
β”œβ”€β”€ main.tsx / LensPopup.tsx # popup UI entry point
β”œβ”€β”€ background/             # service worker that injects headers
β”œβ”€β”€ commands/               # command explorer
β”œβ”€β”€ queries/                # query explorer
β”œβ”€β”€ observable-query-diagnostics/  # live observable-query health
β”œβ”€β”€ settings/               # configuration, tenant/user management
β”œβ”€β”€ context/                # identity and tenancy context
β”œβ”€β”€ shared/                 # shared utilities and types
β”œβ”€β”€ testing/                # spec helpers (chrome API stub, builders)
└── arc/                    # Cratis Arc integration

Specs sit next to what they specify, in for_<Subject>/when_<context>.ts folders β€” the same BDD shape as the rest of Cratis.

βœ… Quality gates

cd Source
yarn typecheck   # zero TypeScript errors
yarn test        # all specs green
yarn build       # the extension builds clean
yarn ci          # all three, as CI runs them

🎬 The Cratis ecosystem

This project is part of Cratis β€” free, MIT-licensed tools for building event-sourced and CQRS applications.

  • Chronicle β€” event-sourcing database and runtime. Orleans-based kernel, pluggable storage (MongoDB default; PostgreSQL, SQL Server, SQLite, in-memory), language-agnostic gRPC contracts. Docs
  • Chronicle clients β€” first-class .NET SDK, plus TypeScript, Kotlin/Java, and Elixir; Python coming soon (pre-alpha). AI agents connect through the Chronicle MCP server.
  • Arc β€” opinionated CQRS framework for ASP.NET Core with commands, queries, validation, authorization, and TypeScript proxy generation. Works without event sourcing. Docs
  • Components β€” React components aligned with Arc patterns. Docs
  • CLI + Workbench β€” inspect and diagnose Chronicle from the terminal or the browser. Docs
  • Model-first layer (experimental) β€” Studio, Screenplay, Stage, Scene, Prologue
  • Supporting β€” Fundamentals, Specifications, Synopsis, Lens (this repository), Narrator, and free AI tooling (preview); Ensemble coming soon (pre-release)
  • Samples β€” runnable event sourcing and CQRS samples for the whole stack

Everything Cratis publishes today is MIT licensed and free to use.


Part of the Cratis platform Β· Licensed under the MIT license