Neon Law
  • Notations
  • Nimbus
  • Workshops
  • Show-and-tell
  • Sign in
← Rust in Peace

Rust in Peace

0 / 51 viewed

Open any slide to read it — each one earns a green check, kept only in this browser and never sent anywhere. View them all to unlock your certificate.

1

Chapter 1

Intro

✓

Agenda

An agenda, not a lecture outline — you are here to argue back. By the end of the half hour you will be able to:

  • Recount how a two-person team crossed from software to law without dropping the toolchain. Trace our process from the law, to a Cucumber feature, to a reusable template, to the signed notation it produces for one client. Dissect one workflow, forming a Nevada LLC, into attorney-gated steps with the shipped code. Map the Rust ecosystem we rely on and the seams that let us change it. Defend the claim that a reviewed, repeatable workflow beats a prompt. See how a grounded issue becomes a reviewable change, with automation carrying evidence forward and a person retaining the decision.
1. Agenda
✓

Las Vegas, 2011 — where I learned to program

Before the law, before Rust, there was a Ruby on Rails meetup in Las Vegas. That room is where I learned to program — and where I first watched a group of strangers agree, on purpose, about how software should be built.

2. Las Vegas, 2011 — where I learned to program
2

Chapter 2

The Rails Lesson

✓

Convention over configuration

Rails' core idea was radical to a beginner: stop configuring, start agreeing. If everyone follows the same convention, the framework fills in the rest — and a stranger can read your code.

3. Convention over configuration
✓

The database was a shared design

The first convention I learned was the schema. Migrations turned the database into something a team designed together — versioned in the repository, applied the same way on every machine.

4. The database was a shared design
✓

Controllers — where a request becomes a decision

The next thing we agreed on was the controller: the one place a request turns into an action. Same file, same shape, in every app — so anyone could find the logic.

5. Controllers — where a request becomes a decision
✓

Parameter handling — the shape of what comes in

Then we learned to distrust the input. Parameter handling was the convention for taking what a user sent and making it safe before it touched anything that mattered.

6. Parameter handling — the shape of what comes in
✓

Middleware — the layer I didn't know I needed

The last convention floored me: middleware. A stack of small, composable layers every request passes through — logging, auth, sessions — each one modular, each one reusable.

7. Middleware — the layer I didn't know I needed
✓

"It works on my machine"

And then there was the phrase every one of us said, half-joking, in that Rails room: "It works on my machine." It was a promise and a curse — the first bug we could never reproduce.

8. "It works on my machine"
✓

How new all of this still was

What stunned me most was how young it all was. These were not settled laws handed down — they were conventions a small community was inventing, out loud, in real time. And I got to be in the room.

9. How new all of this still was
✓

From Rails conventions to Navigator

Fifteen years later I am a lawyer, and I kept every one of those lessons. Schema, controllers, parameters, middleware, convention over configuration — Navigator is those Rails ideas, applied to the practice of law in Rust.

10. From Rails conventions to Navigator
✓

A eulogy for my programming career

I thought becoming a full-time lawyer meant leaving production software behind. Rust changed the obituary: I can let the old career rest because its best habits now run the law practice.

11. A eulogy for my programming career
3

Chapter 3

Shared craft compounds

✓

Keep domain seams in Rust, where interest compounds

The bet is not "write a service in Rust." Rust owns reusable domain systems: libraries, command-line tools, workers, editor integrations, tests, and — through Dioxus — the browser pages. The payoff is that each good decision reinforces the next one.

12. Keep domain seams in Rust, where interest compounds
✓

Widely available — governed in the open

Rust is stewarded by the Rust Foundation, an independent non-profit whose members include AWS, Google, Microsoft, and Meta — none of whom own the language. Wide availability is the access-to-justice argument: the toolchain costs a clinic exactly what it costs us — nothing.

13. Widely available — governed in the open
✓

A cautionary tale — Java, Oracle, and the price of a single owner

Java was created at Sun; Oracle acquired Sun in 2010 and sued Google that same year over Android's reuse of 37 Java SE API packages. Google v. Oracle ran more than a decade, until the Supreme Court ruled in 2021 it was fair use.

14. A cautionary tale — Java, Oracle, and the price of a single owner
✓

Say it with your whole chest

And when someone asks why it is written in Rust: because we are doing it in motherfucking Rust.

15. Say it with your whole chest
4

Chapter 4

Six ways to know a change holds

✓

One giant change deserves more than one glance

When two numbers are too large to hold side by side, you can compare several well-chosen positions instead of trusting one glance. AI-assisted code is similar: no one review sees the whole change, so we ask the same question six different ways.

16. One giant change deserves more than one glance
✓

The compiler asks whether the program can be true

Rust compiler: do the types, ownership, lifetimes, and exhaustive cases still compose into a program the machine can run?

17. The compiler asks whether the program can be true
✓

Clippy and rustfmt ask whether the code speaks our dialect

Clippy finds suspicious choices. rustfmt removes accidental visual difference. Together they make the code easier for the next reader — and the next agent — to recognize.

18. Clippy and rustfmt ask whether the code speaks our dialect
✓

Tests ask whether the promise still holds at the boundary

Tests are the behavioral measurement: given this input, state, or failure, does the system still keep the promise it made before the refactor?

19. Tests ask whether the promise still holds at the boundary
✓

Bloom turns verification into a learning loop

The Bloom taxonomy gives the same work six human verbs: remember, understand, apply, analyze, evaluate, create.

20. Bloom turns verification into a learning loop
✓

Marketing copy must explain the way, not only the claim

“AI helps us move faster” is not an explanation. The useful promise is: we move faster because every change meets several explicit checks before it earns trust.

21. Marketing copy must explain the way, not only the claim
✓

Three workshops, three people, one method

The same explanation changes with the person doing the work:

  • Using the Navigator — the licensed lawyer checks a matter and signs the result.
  • Operating Navigator — the admin operator checks the environment before it goes live.
  • Contributing to Navigator — the contributor checks that an improvement protects the shared corpus.
22. Three workshops, three people, one method
✓

Fast generation, slow enough verification

Vibe code quickly. Then keep it DRY, refactorable, covered, formatted, and explainable — six perspectives make the feedback loop faster, not heavier.

23. Fast generation, slow enough verification
5

Chapter 5

From Law to Workflow

✓

The goal — deterministic workflows from law

The whole method on one slide: a prompt is a wish; a workflow is a contract. Read the law → a Cucumber feature → a template (the reusable blueprint) → a notation (one client's reviewed, signed result).

24. The goal — deterministic workflows from law
✓

Step 1 — read the law

A Nevada LLC is a creature of statute: NRS Chapter 86 says what the Articles of Organization must contain. We do not paraphrase from memory — we read the chapter at its official source and cite it.

25. Step 1 — read the law
✓

Step 2 — write the behavior before the code

The first artifact is not Rust — it is a Cucumber feature describing the whole arc in plain language, runnable as a test: a founder intakes, an attorney reviews, signatures land, and the state stamps a filing.

From features/tests/features/nest_formation.feature:


  Scenario: From intake to a stamped Secretary-of-State filing
    When the firm opens the "nv__llc_formation" matter for the client
    And the founder answers the formation questionnaire:
      | value                  |
      | Libra                  |
      | Bright Star Ventures   |
      | Neon Law Registered Agent |
      | members                |
      | Libra; 1 Main St; Las Vegas; NV; 89101; USA |
      | 2026-07-01             |
    And the attorney approves and sends the document
    Then the formation reaches the signature wait
    And the persisted packet is the official SoS form carrying the founder's answers
    And the generated packet is filed as a document in the matter
    When the attorney files the Articles with the Nevada Secretary of State
    Then the formation workflow reaches END
    And a filing was recorded with the "Nevada Secretary of State"
    And the founder's six onboarding answers are on file
26. Step 2 — write the behavior before the code
✓

"It works on my machine" — so we stopped trusting my machine

Callback. The fix for that old curse is not a better machine — it is to stop trusting any machine. The scenario above runs against a real, throwaway Postgres, so the environment is pinned in code, not remembered on a box.

27. "It works on my machine" — so we stopped trusting my machine
✓

Step 3 — the template: a questionnaire and a workflow

The template is one markdown file with two machine-readable graphs: a questionnaire graph (what we ask) and a workflow graph (what we do). The Nest questionnaire is six answers, in order.

From templates/forms/united_states/nevada/state/nv__llc_formation.md:


questionnaire:
  BEGIN:
    _: person__client
  person__client:
    _: entity__company
  entity__company:
    _: person__registered_agent
  person__registered_agent:
    _: custom_single_choice__management_structure
  custom_single_choice__management_structure:
    _: people__managing_members
  people__managing_members:
    _: custom_datetime__formation_date
  custom_datetime__formation_date:
    _: END
  END: {}

And here is the workflow — the LLC formation dissected into small, named, modular steps. Each state is a noun in our glossary; each transition is a signal some handler fires. This graph is the product.

From templates/forms/united_states/nevada/state/nv__llc_formation.md:


workflow:
  BEGIN:
    intake_submitted: intake_persisted__organizer
  intake_persisted__organizer:
    articles_rendered: staff_review
  staff_review:
    approved: generate_pdf__articles_pdf
    rejected: END
  generate_pdf__articles_pdf:
    pdf_persisted: sent_for_signature__pending
  sent_for_signature__pending:
    signature_received: filing__nv_sos
    signature_declined: END
  filing__nv_sos:
    filed: END
  END: {}
28. Step 3 — the template: a questionnaire and a workflow
✓

Step 4 — the attorney gate is a graph invariant

Every workflow must pass through staff_review before anything is signed or filed — not as a policy memo, but as a property checked over the state-machine graph itself with a breadth-first search from BEGIN.

From workflows/src/guardrail.rs:


pub fn staff_review_precedes_signature(spec: &WorkflowSpec) -> Result<(), GateViolation> {
    let begin = StateName::begin();
    if let Some(signature) = reaches_target_without_review(spec, &begin, is_signature_state) {
        return Err(GateViolation {
            fill_state: begin.as_str().to_string(),
            submission_state: signature,
        });
    }
    Ok(())
}
29. Step 4 — the attorney gate is a graph invariant
✓

Step 5 — signature is a modular step

sent_for_signature__pending is one state in the graph, and the thing that fires it is a small trait — not a vendor. DocuSign is the shipped implementation; dev and tests run a recording stub, so the step stays testable without an account.

From portal/src/signature.rs:


pub trait SignatureProvider: Send + Sync {
    /// Submit the rendered retainer PDF for the given notation, placing
    /// the fields described by `manifest`. Returns a provider-issued id
    /// correlating future events.
    async fn send_for_signature(
        &self,
        notation_id: Uuid,
        pdf: &[u8],
        manifest: &SignatureManifest,
    ) -> Result<SignatureRequestId, SignatureError>;

Because the step is modular it can also be careful. Dispatch is idempotent — a notation that already has an envelope out reuses it, fires nothing, and sends nothing — so a retry can never double-send a client's contract.

From portal/src/retainer_walk.rs:


    // Idempotency: this notation already has an envelope out. Reuse the
    // recorded id, fire nothing, send nothing — the post-state is
    // whatever the notation already records.
    if let Some(existing) =
        store::signatures::request_id_for_notation(deps.surreal, notation_id).await?
    {
        return Ok((
            StateName::from(notation_row.state.as_str()),
            crate::signature::SignatureRequestId(existing),
        ));
    }
30. Step 5 — signature is a modular step
✓

Step 6 — the filing, run durably

The last state, filing__nv_sos, records the filing with the Nevada Secretary of State — and like every long-running step it executes as a journaled, resumable Restate workflow through the restate-sdk crate.

31. Step 6 — the filing, run durably
✓

"It works on my machine" — even when my machine dies

Restate takes the phrase somewhere new. The durable filing does not live on the machine at all — it is journaled, so it survives the pod that ran it and replays exactly where it left off.

32. "It works on my machine" — even when my machine dies
✓

Why a workflow beats a prompt

You could ask a frontier model to "form me a Nevada LLC" and get something plausible. We built the harness instead, because plausible is not the bar — repeatable is. A prompt's steps are neither repeatable nor modular.

33. Why a workflow beats a prompt
✓

Privacy-preserving operations are part of the product

Legal tech cannot treat observability as a copy of production. Navigator emits OpenTelemetry traces, metrics, and logs through one Rust crate, and the rule is structural: identifiers and counts, never client content.

34. Privacy-preserving operations are part of the product
6

Chapter 6

Rust All the Way Down

✓

We did not start all Rust

Navigator did not begin as a pure-Rust stack. We have moved the boundary a seam at a time: server-rendered Maud with HTMX/Alpine/Bootstrap gave way to Dioxus; React and TipTap were evaluated and declined; the browser now shares the Cargo workspace with the rules and the server.

35. We did not start all Rust
✓

From Postgres to Rust — with a bridge

Postgres and SeaORM still hold the production record today. SurrealDB is the chosen destination: document, graph, and key-value work can meet in one Rust engine, while each port slice proves its reads and writes before the old path goes away.

36. From Postgres to Rust — with a bridge
✓

The runtime story: keep the seam, change the engine

The same move repeats at the runtime boundary. Durable workflows landed on Restate, local identity on Rauthy, the private edge on Pingora, local S3 on Garage, and observability on OpenObserve — each behind an application-owned protocol, trait, or environment contract.

37. The runtime story: keep the seam, change the engine
✓

One deployment bucket; many matter repositories

Storage and Git deliberately have different cardinality. The target is one private object-storage bucket per deployment; documents, assets, exports, logs, and every Project's files use application-owned logical keys and metadata inside it. Git is the inverse: one deployment-specific GitHub organization holds many private repositories, such as fiat-law-staging-projects/PROJECT_CODE_1 and fiat-law-staging-projects/PROJECT_CODE_2.

38. One deployment bucket; many matter repositories
✓

Rust where we can own the path; partners at the edge

The destination is not an ideological ban on vendors. Surreal Cloud, Restate Cloud, OpenObserve Cloud, Stalwart Managed Email, and Miuda PBX are the Rust-operated lanes under recorded cutover gates. Xero, DocuSign, and the SIP carrier stay at the business edge, where they provide the service we do not claim to reimplement.

39. Rust where we can own the path; partners at the edge
✓

Rust reaches the places lawyers work

Navigator is not only a web app. The same rules meet lawyers in the document folder they already understand, and the same AIDA catalog is available to assistants through MCP and A2A.

40. Rust reaches the places lawyers work
✓

I want a commercial relationship with everything I depend on

A small legal team cannot maintain the world's infrastructure — so I want to pay for it, in the open. A vendor like Restate, or GitHub Sponsors for the libraries. A healthy dependency is one someone is paid to keep healthy.

41. I want a commercial relationship with everything I depend on
✓

Always the latest, always Rust

Two rules keep the interest compounding: take the newest version of every dependency, and use exactly one language. No pinned-and-forgotten crates, no second runtime, no polyglot seams to babysit.

42. Always the latest, always Rust
✓

Swap the seam — it still works

Every heavy dependency sits behind a trait, so changing one does not make the application a rewrite. Signatures, storage, identity, durable execution, policy, telemetry, and the project repository surface have all had an explicit seam. Sometimes the right change is a new provider; sometimes it is retiring a surface entirely.

43. Swap the seam — it still works
✓

The crates we actually run on

The bill of materials for a real legal-tech product — every line a crate you can pull today:

  • HTTP and views — axum, dioxus, tower / tower-http.
  • Async runtime — tokio, multi-threaded, with graceful shutdown.
  • Database transition — Postgres today; SurrealDB follows through the next store slices.
  • Durable execution — restate-sdk.
  • Telemetry — opentelemetry, tracing, OTLP.
  • Archive — arrow and parquet; a real Iceberg table lane is separately tracked.
  • Content — pulldown-cmark.
  • Cloud — google-cloud-storage + reqwest.
  • Identity — jsonwebtoken + oauth2.
  • Tests — fantoccini and cucumber, exercised through the workspace harness.
44. The crates we actually run on
✓

Ethics is part of the stack

Lawyers who code still carry the rules of professional conduct, and the engineering answer is the same as it is for memory safety: make the invariant structural, not aspirational.

  • Scope is a field, not a vibe. Every engagement is scoped in writing before work starts. The conflict check runs first. Before any matter opens, we query every current and former matter. Referral, without a referral fee. When conflicted out, we refer — with no referral fee.
45. Ethics is part of the stack
✓

The simplest developer environment I can get away with

The local loop is production-shaped on purpose: the Rust CLI provisions an isolated KIND dependency tier and the host application process shares that exact environment.

46. The simplest developer environment I can get away with
✓

The online developer environment

So we built the environment in the cloud too. The same Rust processes, the same swappable seams, spun up online — so the loop follows me anywhere, and I barely write the code by hand at all. Agents do the typing; I review.

47. The online developer environment
✓

"It works on my machine in the cloud — and on yours, and on my client's"

The phrase, finally earned. It works on my machine in the cloud. It works on your machine. It works on my client's machine — because the environment is swappable seams, pinned services, and durable runs, not a special box.

48. "It works on my machine in the cloud — and on yours, and on my client's"
✓

Where we are today — live by August 19

Every seam now has its Rust answer, decided and recorded: SurrealDB (Surreal Cloud) for the store, Restate Cloud for durable execution, OpenObserve Cloud for telemetry, Stalwart Managed Email for every matter address, Miuda PBX on RustPBX for voice, Pingora at the private edge, Garage and Rauthy in the local loop, Regorus for policy, Dioxus for every view, Typst for every document. Running by August 19, 2026.

49. Where we are today — live by August 19
✓

Betting on ourselves — Rust in peace

Choosing these vendors is betting on ourselves. If we write successful Rust, our vendors write successful Rust — a healthy ecosystem that stays usable for many years. That lets the firm focus on winning cases, and lets me Rust in peace: no longer a full-time developer, standing on the shoulders of giants.

50. Betting on ourselves — Rust in peace
7

Chapter 7

Wrap Up

✓

Take the method home

The ask is not a star on a repository — it is the method, and every piece of it is a crate you can pull tonight. Read the law. Write the behavior first. Keep the domain seam in Rust. Put a human at the gate.

Read the Foundation mission for why any of this matters — then come find me afterward and let us get crabby together.

51. Take the method home

You finished — claim your certificate

Enter your name and email and the Neon Law Foundation will send a PDF certificate of completion.

We use your email only to send this certificate.

Contact us — support@neonlaw.orgTransparency & public disclosures
  • Neon Law Foundation
    5150 Mae Anne Ave Ste 405-9999, Reno, NV 89523

Neon Law Foundation is a Nevada nonprofit corporation and a 501(c)(3) tax-exempt organization. It does not practice law and cannot represent you.

Nothing on this site is legal advice, and nothing here creates an attorney-client relationship.

© 2026 Polin Shook & Neon Law