Sushi Kitchen
Solutions/Sushi Law
In practice

A kitchen that can hold a privilege.

A working law practice, running its own AI on its own hardware.

Moye Law, PC · Harrison, New York

The three constants
PrivacyLegal privilege
Memory floor
Rolls7 — five from the menu, two the firm’s own

The memory floor is unmeasured. The slot is held rather than filled — an em-dash would read as zero to someone sizing a machine.

Read this first

Sushi Law is not on the menu. It is one boutique law firm’s deployment, and it is here because it is the clearest answer to a fair question: does anyone actually run this? Five of the seven rolls below can be assembled in the Builder today. The other two the firm built itself, named in the Kitchen’s families but not adopted from the catalog — which is what most real deployments look like.

Figures on this page hold their slots — a dotted rule the width of the number — until each one has been verified against the running deployment. Identifiers, roles and the profile are not figures and stand as written.

The constraint

A lawyer with client documents has the same problem as anyone else with documents, and one additional constraint: the documents cannot leave the building.

Every general-purpose AI assistant resolves that constraint by asking for the documents. There is no setting that makes a third-party server privileged.

So the practice either sends the file room somewhere it should not go, or it goes without the tool. Both answers are bad, and neither is a technical problem — it is an architecture problem.

What it does

On day one.

01Ask a question across the whole file room and get an answer with citations back to the source document.
02Turn a scanned filing into searchable text on the same machine that stores it.
03Draft from precedent the practice already owns, not from a model's memory of someone else's.
04Run every one of the above with the network egress closed.
Egress

Nothing reaches in.

Four networks, two of them declared internal — no route to the internet in either direction. The queue sits on one of those. The two workers sit on an outbound-only network and accept a connection from nowhere at all. Traefik terminates TLS and is the only service in the deployment that publishes a port.

The data plane is a managed Postgres, reached outbound along that same narrow path — so this is not a claim that nothing leaves. It is a claim about what can reach in, and about how few ways out there are. Both are readable in the deployment’s compose file. Neither is a legal conclusion, and nothing here offers one.

The composition

Seven rolls, and what each one is for.

Every identifier below is resolved twice: against the catalog, and against the firm’s own compose file. The second check is the one that matters for a case study — the first only proves a roll exists, not that anyone runs it. Two are marked first-party: the firm built them, so they have no page here.

RollRole in this deployment
dragon.traefikthe TLS edge — the only service that publishes a port
gunkanmaki.dockerproxya read-only view of the docker socket, reachable by the edge and nothing else
sashimi.fastapiauthorization, and the boundary where work is handed to a queue
chirashi.worker-parsingfirst-partyparsing and OCR — the firm's own roll, outbound-only, concurrency of one
chirashi.worker-mlfirst-partyembeddings — the firm's own roll, on the same isolated pair of networks
futomaki.redisthe queue itself, on a network with no route out
temaki.docassembleguided interviews, and only when that profile is switched on

This list was rebuilt on 2026-08-28 from the firm’s docker-compose.yml. The version before it named five services the firm does not run, including a vector database it evaluated and rejected and a reverse proxy it replaced. Every id here is a container in the running stack.

The problem was never efficiency

A boutique law firm does document-heavy work: estate planning and administration, intellectual property, digital assets, elder law. The work is reading. Reading a file room, reading a precedent the firm already owns, reading a scanned filing somebody signed in 1998 and nobody has opened since.

That is exactly the work language models are good at, which put the firm in the position most professional practices are now in: the tool that would obviously help is the tool it obviously could not use.

Not because of policy, and not because of caution in the abstract. Because of what a lawyer's material is, and what happens to it when it is typed into somebody else's service.

Why a public model is a different question for a lawyer

For most businesses, putting work into a hosted AI service is a vendor-risk question: read the terms, check the retention settings, get it approved. For a lawyer it is a different question, because the material is not merely confidential. It is privileged, and privilege is a protection that can be lost by the act of sharing.

Handing material to a third party is a fact a court can be asked to weigh. Courts have begun to weigh it in this context, and the reasoning that matters is simple enough to state: information given to an outside service is harder to characterise as information the holder intended to keep private. And retention is not always in the client's hands — a preservation order in ongoing litigation required one major provider to retain output logs it had otherwise planned to delete, which is a useful reminder that a deletion policy is a promise, not a property of the system.

Whether any of that amounts to waiver in a particular matter is a question for a court, and this page does not answer it. The firm did not need it answered. It needed the question not to arise.

That is a much stricter requirement than confidentiality, and it is the requirement that determined the architecture. Not "the vendor promises not to look." There is no vendor.

What could not be bought

The market answer to this is a legal-tech product with a compliance page. Some of them are good. All of them share the property the firm was trying to eliminate: the practice's material sits on somebody else's infrastructure, under somebody else's retention policy, subject to somebody else's subpoena, and available to the practice for exactly as long as the commercial relationship lasts.

The firm wanted the opposite properties. Software it runs. Data on hardware it controls. Models that answer questions about a matter without the matter leaving the building. And a system that keeps working if the supplier disappears, because a practice cannot re-platform its file room every time a vendor is acquired.

Nothing off the shelf had that shape. Assembling it from open-source parts is possible — everything needed exists and is free — but the assembly is the hard part, and it is not the work a law firm should be doing. Choosing between fifteen retrieval strategies is not practising law.

That gap is the whole reason the Kitchen exists: the components are commodity, the arrangement is not.

What the Kitchen actually supplied

Five rolls, running as containers: the TLS edge, a read-only Docker socket proxy, the API, the queue, the guided-interview runtime. Two more the firm built itself — the parsing worker and the embedding worker — from its own application image.

Five adopted, two built. That ratio is the honest picture of what a component catalog does, and it is worth stating plainly because the temptation is to claim more. The Kitchen did not build this firm's practice management. It supplied the infrastructure spine and the vocabulary, and the firm built the practice on top.

The vocabulary is not decoration. The firm's own two components are named in the Kitchen's families, so a reader who has never seen them can still tell what each works on and what it may touch. That is the part that travels between deployments — more than any container does.

Traffic runs upstream too. The Kitchen had specified a reverse-proxy capability and shipped a hand-edited config file to satisfy it. This firm needed a real one, built it, ran it under load, and the Kitchen later adopted that work back to fix its own edge. The component the factory ships today was hardened by the practice that depended on it.

Seven containers, four networks, two with no way out

What makes this a deployment capable of holding a privilege is not any single component. It is which networks each one is allowed to sit on.

There are four. Two are declared internal, which in Docker means precisely what it sounds like: no route to the internet, in either direction, for anything on them. The queue lives on one of those. So does the proxy that reads the container list.

The edge is the only service that publishes a port. The two workers sit on an outbound-only network and accept a connection from nowhere at all — they can reach the database they need, and nothing can reach them. The read-only view of the Docker socket is reachable by the edge alone, and answers exactly one question, the container list, with writes switched off.

None of that is a policy document. It is the network section of a compose file, which is the difference between a claim about confidentiality and a thing somebody would have to rewrite in order to break.

The schema is where the confidentiality actually lives

Two hundred and twenty-two migrations. Around three hundred and fifty row-level security policies. Access is deny-by-default: a row is invisible until a policy explains why this particular person may see it.

The model is deliberately not a table of users with roles attached. It is parties, matter-parties and matter-users — because in a practice the question is never what a person may do in general. It is what they may see on this matter, and the same human being is a firm operator on one and a client on another.

Resolving that inside the database creates a trap the firm had to design around. A policy that checks access by querying an access table re-enters row-level security while evaluating row-level security, and either recurses or silently returns nothing. So membership resolves through security-definer helpers that step outside the evaluation to answer, and the policies call those.

This is the layer that would still hold if every service above it were compromised, and it is the layer nobody sees. Worth saying plainly: the confidentiality claim here is a database claim first and a network claim second.

Produce, attest, release, publish, seal

A document moves through five stages, and each is a different kind of act.

It is produced — drafted from a template package whose tokens resolve from the matter's own parties, dates and fee record rather than being typed again. The shipped example is an engagement pack: a forty-two token contract, filled per signer, merged once, rendered through a single sanctioned path so there is one place the output is defined.

It is attested — an attorney takes responsibility, and the attestation carries a hash of the document as it stood at that moment. Edit it afterwards and the attestation is revoked automatically, because it is no longer an attestation about that document.

It is released through a gate, published to a named party, and sealed into a hash chain. Generation never creates a finance row and never sets client visibility: a draft stays a draft until a person says otherwise, and saying otherwise is a specific recorded act rather than a side effect.

The gate that fails closed on the document that matters most

Before anything becomes visible to a client it is scanned for the debris of an unfinished draft: unresolved template tokens, bracketed placeholders, parenthetical confirm-this markers.

The scan reads the PDF's text — which raises the case that decides whether a gate is real. A scan of a signed page has no extractable text at all. Nothing is found in it, because nothing can be read from it.

A permissive system passes that document. This one fails it closed, because the absence of a finding is not a finding of absence. That single decision is most of the difference between a check and a formality.

Documents also carry a retention class, a legal-hold flag and a disposition state, and disposition never deletes bytes — it flips a state and records who did it. A database trigger refuses to dispose of anything under legal hold, independently of the application check that also refuses. Two locks, because the failure mode is destroying evidence.

The chain, and the part of it that goes to Bitcoin

Publishing seals a proof bundle: a hash-sealed, parent-chained record folding in the document's content hash, its lifecycle, and an append-only ledger of every client interaction with it. Each bundle names its parent, so altering an old one breaks every link after it.

For trusts-and-estates matters the seal goes further. The bundle's hash — only the hash, never the document or any fragment of it — is submitted to the Bitcoin blockchain through OpenTimestamps, and a scheduled job later upgrades the pending stamp to a confirmed attestation once it is anchored in a block.

The effect is that the firm can prove a document existed in a particular state at a particular time to somebody who does not trust the firm, without showing that person the document. An allowlist restricts anchoring to the practice areas where that proof is worth its cost — the sort of restraint usually missing from systems that discover a blockchain.

The queue is where the machine stops

A worker here may open a document, read the bytes, run optical character recognition across a scan, and compute an embedding. It may not decide who is allowed to see any of it.

That boundary is legal rather than technical. Releasing a document to a client is an act a lawyer answers for, so it stays in the application, in front of a person. No background job, no trigger and no scheduled task can perform it.

Ingestion is gated the same way. A new document stages as internal-review and is not indexed on arrival; the tasks that would index it skip anything not explicitly approved. A firm's own draft work does not become searchable context merely because somebody uploaded it.

The cost is worth stating: this means the pipeline cannot be fully automatic, and that is the design rather than a limitation. The machine does the reading. The lawyer does the deciding.

Sized from the crash, not from the estimate

The parsing worker is allowed three gigabytes and runs one job at a time. Both numbers came from a failure rather than a spreadsheet.

At one and a half gigabytes the parser was killed mid-conversion on a scanned PDF. Not a slow parse — a killed process, the kernel taking its memory back. The layout model, the table model and the OCR engine are resident together during a convert, and on exactly the kind of document a practice handles all day they peak past two gigabytes between them.

The rest is sized the same way: from what the containers were measured using, not from what anyone expected. Held against the declared ceilings, the estimates ran roughly twice high. Every container has its logs capped, because the machine is shared and a host nobody can write to is a host that has already stopped working.

The apparatus that keeps it honest

Thirteen continuous-integration workflows. Among them: a nightly proof that one client's data cannot be reached from another client's session, a weekly isolation suite run against the live system rather than a fixture, end-to-end tests of the portal and the operator console, and a monthly archive of the public marketing site — because an attorney-advertising rule requires the firm to produce what its website said on a given date.

The portal renders fail-closed. A route must be registered as client-safe or it does not render for a client at all, and unknown never means visible.

Test data has a single source of truth: one manifest declares the personas, matters, documents and threads the suite expects, and the seed scripts, canaries and reset planning all assert against it. Fixtures cannot drift from what the tests believe, which is the quiet failure that makes a green suite meaningless.

What generalises, and what does not

Almost none of the above is about law. Strip the vocabulary and the shape is: material too sensitive to hand to a third party, a professional who is personally accountable for what gets released, an audit trail that must survive a hostile reading, and a small organisation without a platform team.

That describes a medical practice, an accountancy, a family office, a defence subcontractor, a journalism desk protecting sources, a bank's internal counsel. The specifics differ — HIPAA is not privilege, and a source is not a client — but the architecture answering them is the same architecture, and the reason it is hard to buy is the same reason.

What the firm needed was not legal software. It was a way to run capable models against sensitive material without the material leaving, plus the discipline that makes the result defensible: a release that a person performs, a record that cannot be quietly edited, limits that were measured rather than guessed.

That is what the Kitchen produces. The catalog is components; the value is the arrangement — which components, at which versions, on which networks, with which limits, and what was found when somebody read the licences. Sushi Legal is that arrangement for law. The same factory produces the arrangement for the next industry, and the industry after that, without any of them having to discover for themselves that an image-only PDF passes a naive content scan.

What this page is not claiming

The data plane is a managed Postgres. Documents and their metadata live there, reached outbound along the restricted path described above. So this is not a stack where nothing leaves — it is a stack where very little can reach in, and where the ways out are few enough to name.

The models are not on this machine. The deployment points at an inference endpoint, and where that endpoint runs is a separate decision. The guardrail doing the work is the one refusing external inference on matter content unless somebody explicitly turns it on. When the firm's research tools query public case law, only the citation string leaves — never a matter fact — and a failed lookup degrades to an empty result rather than blocking the work.

Nothing here is legal advice, and nothing here is a legal conclusion about privilege, waiver or discovery. Those are questions for a court on particular facts. What is described is an architecture and the reasoning a firm applied when choosing it.

One more thing, because it was true of this page for weeks. An earlier version described five services the firm does not run, including a vector database it had evaluated and rejected and a reverse proxy it had replaced. Every identifier here is now a container in the running deployment, and the standard is written into the source file so the next version has to meet it too.

Where to go from here

Five of the seven are on the menu.

Open the Builder with the five catalog rolls selected and the requirements resolve as you go, or read them one at a time on the menu first. The firm’s own two are not in the Builder — they are its application, not a component anyone else can deploy.

Moye Law, PC is named here as the operator of this deployment. Nothing on this page is legal advice, an offer of representation, or a claim about legal outcomes, and no attorney–client relationship arises from reading it.