The front end is the part of Opbox that people actually see and touch: the screens in the browser, the chat box, the document editor, the client portal. This page explains how that web app is built and, more importantly, why it is built the way it is. You do not need to be an engineer to follow it. The short version is this: the web app is “just a verb client”. It draws the screens; the kernel holds the rules. That one design choice explains almost everything else.
The web app is “just a verb client”
The Opbox web app is built with Next.js (the React framework, in TypeScript), and it is the site root: the marketing landing, the sign-in, and the whole signed-in application all live behind it. The framework is a tooling detail. The important idea is what the app is allowed to do.
The web app holds no business rules of its own. When you click “Advance” on a matter, the screen does not decide whether you are allowed to advance it, whether the current step is complete, or what happens next. It simply calls a kernel verb (a single named action, like matter.advance) and shows you whatever comes back. Every rule that matters lives in one place: the kernel. Validation, permissions, the audit trail, the workflow logic, all of it.
A useful way to picture it: the web app is the counter at a bank, not the vault. The teller takes your request, passes it through the slot, and shows you the result. The teller never decides on their own whether your account allows the withdrawal. The vault does. Move the teller to a different branch and the rules do not change, because the rules were never in the teller.
Why this matters so much:
- The screens can never drift out of step with the rules. If a permission tightens or a workflow changes, it changes in the kernel, and every screen immediately reflects it, because the screens were only ever asking the kernel. There is no second copy of the logic in the browser to forget to update.
- There is no hidden back door. Every change the web app makes goes through a kernel verb (
POST /v/<verb>), and the data it reads is fenced by row-level security at the shared Postgres, scoped to the caller’s workspace. It cannot mutate anything a verb does not already allow, and it cannot read across the workspace wall. The client portal screen, for example, has no logic the verbs do not give it: it gathers what you type, calls a verb, and renders the typed result. Nothing more. - Trust lives in one place. When you want to know whether a rule is enforced, you look at the kernel, not at a scatter of buttons across dozens of screens.
This is the single invariant the whole front end is held to: it is a thin verb-caller, never a second backend.
The render-schema: one verb output, two projections
This is the key idea on this page, so it is worth slowing down for.
Opbox shows the same information in two very different places. There is the chat, where the agent might mention a matter and show you a small inline card about it. And there is the GUI, the full-screen panel you open to study that same matter in depth. The naive way to build this would be to have the back end return one shape of data for the chat and a different shape for the GUI: two formats, two renderers, two things to keep in sync. That is exactly the kind of split that drifts apart over time.
Opbox does something cleaner. Each verb returns its data plus a small “render descriptor”: a compact instruction sheet that says how to display that data. One verb output, one descriptor, and from that single contract the app produces two views.
Take matter.get, the verb that fetches one matter. Its output carries a descriptor, and from the exact same bytes:
- the chat renders a compact matter card: a title, the current status, and an “Advance” button, small enough to sit inline in a conversation; and
- the GUI renders a full matter panel: the step spine down the left (the chain of steps that make up the matter), the detail in the centre, and the activity feed on the right.
Same data. Same instruction sheet. Two projections of it: a compact one for chat and a full one for the panel. The descriptor even marks which fields are “primary” (important enough to survive into the small chat card) and which are panel-only chrome (the extra detail you only want on the big screen). And it can carry an action like “Advance” that, when clicked, simply calls an existing verb. It never invents a new way to change data; it only points the button at a verb that already exists.
The analogy: think of a single recipe card that a print shop can run two ways. From the one recipe it prints a big wall poster for the kitchen and a pocket card for the cook’s apron. The recipe is written once. The poster and the pocket card always agree, because they came from the same source. If the recipe changes, both change together. You never get a poster that says one thing and a pocket card that says another.
That is the render-schema. One verb output, two projections, one contract. It is the reason the chat and the GUI can never tell you different stories about the same matter, and the reason Opbox did not have to build (and keep in sync) two separate display systems.
Under the hood there is a small, fixed menu of shapes a descriptor can ask for, so the renderer always knows what it is looking at: a record (a single thing’s detail), a table (rows, like a matter list or a review queue), a timeline (the step chain of a matter), a doc (an editable document), a form (an intake step), and cards (a board). Six shapes, no more. Anything new is a deliberate decision, not an accident, which keeps the whole surface legible.
The three ways in are equal
People reach Opbox three ways: through the web screens, through the chat box, and through the command line. The important thing is that none of these is the “real” one with the others bolted on. All three call the same verbs. A button on a screen, a sentence to the agent, and a typed command all arrive at the kernel as the same named action.
Because of the render-schema, the chat can be just as rich as the GUI. When the agent mentions a matter, it does not have to dump a wall of text: it can show the same matter card the GUI would show, because both are driven by the same descriptor. These rich inline cards are sometimes called object widgets: a small, live view of a real object (a matter, a party, a document) embedded right in the conversation. Click one and it deep-links you straight into the full panel for that object.
So the chat is not a lesser, text-only cousin of the GUI. It is a co-equal way in that happens to render the same objects in their compact form. The GUI and the chat are two doors into one building, not a building and a brochure about it.
Key surfaces a user sees
In plain terms, here is what is actually on screen.
The matter list. The collection view: all your matters as rows you can scan, sort, and open. It is a “table” render over a list verb, so the columns and how each cell paints come straight from the descriptor, not from logic baked into the screen.
The matter detail (the step workbench). Open one matter and you get the panel described above: the step spine on the left (each step showing where it is in its lifecycle, with the current step marked), the detail in the centre, and an activity area on the right that also lets you see related work. This is the surface you open to grasp a whole matter in one glance, including a regulator who needs to understand it without working it. It is not the main way you do the work (that stays in chat); it is the legibility view.
The document editor. A rich-text editor for drafting the documents a matter produces. You type and format as you would expect; when you save, the editor does not quietly write to some private store. Saving calls a verb, the same as every other action, so a saved document goes through the same rules and audit as everything else.
The agent chat. The conversational surface where you talk to the agent and it talks back, complete with the inline object widgets described above. This is the spine of how you actually work a matter: advancing it, querying it, drafting in it.
The client Portal. A separate, hardened screen for clients. A client arrives with a link that carries a scoped token, and that token is what every request rides on. The crucial property: clients see only what has been shared with them, and nothing more. When the portal loads, it pulls the client’s whole view in one external read and shows exactly the shared items, the tasks they can complete, and the message thread with the firm. If they try to reach something not shared, they get the same flat “no” every time, with no hint about what exists behind it. The portal is the clearest example of “the screen has no rules of its own”: the kernel decides what an external client may see, and the portal merely renders the answer.
Owned, not rented
A last point about strategy, because it explains why the front end gets this much care.
Opbox treats the product face as something it deliberately owns: the single-page app, the design, and the conversation surface are all built and controlled in-house. These are the parts a client actually feels. They are how Opbox is experienced, so they are not something to hand to a generic third-party shell.
The layers underneath that are commodities are happily rented: the database driver, the web server, the raw reasoning engine that powers the agent. These are interchangeable plumbing. There is no advantage in building your own, and real cost in maintaining one, so Opbox uses solid off-the-shelf pieces and moves on.
The line between the two is simple. Own the part the client feels; rent the part the client never sees. The front end sits squarely on the “owned” side, and the thin-verb-client design is what lets Opbox own the experience without owning a tangle of duplicated rules: the face is bespoke, the rules live once in the kernel, and the commodity plumbing stays swappable underneath.
In one sentence
The front end is a thin, owned verb client: it holds no rules, it calls kernel verbs, and the render-schema lets one verb output drive both a compact chat card and a full GUI panel from a single contract, so the screens, the chat, and the command line can never tell you different stories.
For the rules these screens call into, see the kernel. For how the agent uses the same verbs and cards, see agents. For who is allowed to do what, see security & permissions.