Using Neon Law Navigator
Open any slide to read it. View them all to unlock your certificate.
Chapter 1
Why do this
Learning objectives
- Remember — identify Project, Template, Notation, Workflow, and the unique onboarding / offboarding pair.
- Understand — connect each noun to the database row that makes the workflow durable and inspectable.
- Apply — open the litigation matter, bind the shared retainer template, and view the client portal application.
- Analyze — inspect the notation state and the matter's participation-scoped views.
- Evaluate: identify which outcome your firm would buy first and what it would need to see.
- Create — make a small, testable change in the sample project and refresh the local portal.
The running matter
The local development fixture seeds three open Projects. This is the one the workshop works:
- Name — Cruller v. Prine
- Code —
sample-litigation - Matter — trespass to land, and rescission of the doughnut instrument
- Repository — neon-law-staging/sample-litigation
- Portal —
/app/projects/sample-litigation/portal/
The other two seeded matters are sample-transactional (a company on a monthly retainer) and sample-estate (an estate
plan). Each carries its own repository and its own portal bundle, mounted the same way.
The Project code is the public URL key. Codes use lowercase letters and numbers separated by single hyphens, so a
project page is always readable as /app/projects/<code>.
Chapter 2
Develop locally
Start the local room
The same local web process resolves its public face from the host. In staging, use staging.neonlaw.com for Neon Law,
staging.deleteyourdata.com for DeleteYourData.com, and staging.lawyershook.com for Lawyer Shook. The route and
application stay shared; the host selects the brand's copy, mark, font, and colour layer.
The Navigator CLI owns the complete local lifecycle. From a New Worktree, run:
cargo run -p cli -- dev worktree-env up --path "$PWD"
set -a; source .devx/env; set +a
cargo run -p neon
The boot command provisions the KIND dependency tier, applies the schema, seeds the sample matters, clones and builds
each sample project, stages every dist/ output, and writes the generated environment. The host web process reads that
environment on startup, so the real sample applications are ready at their portal links after each boot.
The explicit refresh command uses the same build and staging path when a sample project changes. Naming one matter refreshes only that bundle, which is the fast loop while iterating on a single app:
cargo run -p cli -- dev sample-project --project sample-litigation
Restart web after refreshing so it reads the new staged bundle. The generated .devx/env contains
NAVIGATOR_SAMPLE_PROJECTS_DIR, the directory every matter's bundle is staged under; source it before starting the host
process.
Sign in
The local Rauthy fixture supplies five role-named accounts, all using the password password:
| Account | Role | Matter access |
|---|---|---|
owner@neonlaw.com | owner | firm-side matter view |
admin@neonlaw.com | admin | administration surface; participation can be granted there |
lawyer@neonlaw.com | lawyer | firm-side matter view |
clerk@neonlaw.com | clerk | supervised matter view |
client@neonlaw.com | client | client matter view and portal |
Open $NAV_BASE_URL/auth/login. Firm accounts land on /app/team; the client account lands on /app/projects. The
project list and detail page use sample-litigation in the URL. The client portal is available at:
$NAV_BASE_URL/app/projects/sample-litigation/portal/
The portal is participation-scoped. The client, lawyer, clerk, and owner rows are part of the fixture, and the admin
account is the local administrator used to exercise the participation controls at /app/admin.
Chapter 3
Work the litigation matter
The four nouns in one workflow
- Project — Cruller v. Prine, the matter that owns the work.
- Template — a versioned Markdown blueprint such as
onboarding__letter. - Notation — one client and one Template bound inside the Project.
- Workflow — the states and transitions that move a Notation from intake through review and signature.
The shared retainer template is available in the canonical catalog. A lawyer can bind it through the Navigator MCP catalog:
create_notation(template_code="onboarding__letter", project_id=<sample-litigation project id>)
The notation begins in its seeded workflow state. The lawyer reviews the generated work, advances the workflow through the configured transitions, and the resulting documents remain tied to that Project and its audit trail.
One onboarding, one offboarding
Every Project has one onboarding notation and one offboarding notation. Those two kinds are unique on the matter: a second retainer is not a second engagement, and a demand letter is not a closing letter.
Onboarding is the letter that opens the matter. Offboarding is the firm-signed closing letter that ends the
representation. Those two shared catalog codes are onboarding__letter and offboarding__letter. Opening the Project
does not create either notation; a lawyer binds them like any other template. The self-serve doors refuse any other kind
as the matter's first notation.
The CLI seeds both letters. This workshop still binds the retainer through Navigator MCP as one onboarding walk. Close the matter with the offboarding letter. Do not bind two onboardings on one Project:
navigator site notation create onboarding__letter \
--project sample-litigation \
--client-email client@neonlaw.com
navigator site notation create offboarding__letter \
--project sample-litigation \
--client-email client@neonlaw.com
Walk the retainer intake one question at a time
Navigator MCP binds the retainer in one call, but a lawyer can also walk it by hand at
/app/lawyer/notations/{notation_id}/step — one question per screen, the same focus-set chrome the client's own
self-serve intake shares: a step list naming the whole chain, a progress bar, and the question's own control below it. A
closed choice — the engagement's governing law, or a yes/no — renders as cards to choose between, not a bare checkbox or
a compact radio list. Completed steps show as plain markers; there is no revisit route today.
The client-facing half of the same chain is /app/projects/{code}/intake/{notation_id} — the client confirms or
corrects whatever the lawyer already entered, through the identical chrome.
The other notations on a matter
After the engagement is on file, the matter accumulates the work itself. Those later notations are not unique. A litigation matter may carry many letters and filings. An estate matter may carry a will, a trust, and directives. A review matter may carry a memo.
The vocabulary is one closed enum, Kind, in rules/src/kind.rs. A template declares kind: in its frontmatter.
Generated PDFs and lawyer uploads reuse the same strings on the asset lane. The notation kinds you add after onboarding:
letter— a letter the firm sends on the client's behalf (demand, notice, settlement)filing— a document filed with a government bodywill,trust,directive— estate instrumentsagreement— a private agreement with a third partypleading— court paper filed with a court (complaint, motion, brief)memo— an analytical work product, not an executed instrument
Filed uploads that are not templates use transcript, inbound_contract, certificate_of_naturalization, or
unclassified. Content pages (post, workshop, event) and matter dashboards are not notations on the Project.
Inspect the client portal
Sign in as client@neonlaw.com, open /app/projects, and select Cruller v. Prine. All three seeded matters are in
that list, because the fixture client participates in each one. The detail page keeps the human-readable code in the
address bar:
/app/projects/sample-litigation
Select the portal link to open the sample application's bundled client experience. The application is built from the public sample repository and mounted under the Project's code, which gives the sample a complete path from repository to matter-specific browser surface.
Make a sample-project change
The sample repository declares its Navigator Project in navigator.yaml:
project: sample-litigation
Edit the sample project, run the refresh command, restart web, and reload the portal URL. Boot validates the manifest,
builds the frontend, stages the output, and publishes the generated assets before the entry document. This keeps the
portal tied to the declared Project while the browser reloads the new version.
That manifest is the whole reason three bundles cannot collide. Each is staged in a directory named for its matter, but boot re-reads the manifest rather than trusting the directory, and refuses a bundle naming a different Project — because publishing one would put one client's application on another client's portal.
Chapter 4
Open a real Project
Fill the matter-open form
A lawyer-tier account reaches the form at /app/projects/new. It asks for a name, a code, an Entity, a description,
scope of services, the client DRI, and a required conflict-check attestation. Navigator stores the code exactly as typed
— the code is immutable, and a code already in use by another matter is refused rather than silently resolved, because
it is a coordinate the caller already committed to elsewhere (a repository's navigator.yaml, a Drive folder name).
Provision the repository and Drive folder — a separate step today
The browser form does not provision the Project's repository or Drive folder by itself. Every other way of opening a
Project — the JSON API, the CLI, the MCP tool — provisions both surfaces as part of opening; the browser form only
writes the matter row. Immediately after submitting, /app/projects/<code> names no repository yet.
Close that gap from the matter page's admin retry, or from the CLI:
navigator project setup <code>
This creates — or adopts, if one already exists — an empty private GitHub repository and Drive folder, and records the repository URL on the row. It writes no files.
Populate the repository
Clone the now-existing empty repository, then build its shell by hand: copy AGENTS.md and .agents/skills/ from
Navigator's own repository root, write README.md and a nested navigator.yaml naming this Project and host, and add a
starting templates/<code>.md. Then reconcile the two generated workflows — .github/workflows/ci.yml (the thin CI
caller) and .github/workflows/cd.yml (the portal-publish caller):
navigator ops github setup <owner>/<code> --action-version <YY.M.D>
This does not write portal/; that only exists once a client-facing application is built. Pass --action-version
explicitly rather than relying on a default, which only resolves from a real release build.
Commit and push. That push is what makes the CI gate live on the new repository.
Stage a document and sync it
The repository shell above does not write documents/. It is the root-level document surface in every Project
repository, alongside apps/ and templates/, and it holds committed YAML pointers while acting as temporary staging,
not a second document store. Git keeps the pointer; Navigator keeps the bytes. Drop a local file below it, list what a
sync would do, then run it:
navigator project sync --dry-run
navigator project sync
navigator project gate
Against a staged documents/exhibits/exhibit-a.png, the dry run prints one line per staged file and a count, and
changes nothing:
would upload documents/exhibits/exhibit-a.png
1 upload planned
The real run derives the document slug from its path below documents/, uploads the bytes through Navigator's
authenticated API, writes exhibit-a.png.yml only after the upload succeeds, and then removes the staged file. It
prints 1 uploaded. The pointer records kind, desired visibility, current revision metadata, and the previous asset
id when the chain has one. It never contains an object-storage coordinate or legal-document bytes; object storage and
the assets revision chain remain authoritative. Folder conventions infer filing for pleadings/, exhibit for
exhibits/, and agreement for agreements/; other paths use unclassified. Visibility defaults to internal.
The real run needs a stored login — navigator site login --host <host-or-url> — and a matter with that code visible to
the account. --dry-run needs neither. The first real run also creates documents/.gitignore without overwriting an
existing file; until that first sync, nothing in the checkout stops git add from staging raw bytes. validate then
rejects every file below documents/ that is not a *.yml pointer or that .gitignore:
./documents/exhibits/exhibit-a.png: error: legal documents and raw document bytes must not be committed; keep only `*.yml` pointers under `documents/`
Pull a fresh checkout's documents
navigator project sync also fills a fresh clone: it downloads each committed pointer's own revision into the staging
path it already names, and discovers live documents the checkout has no pointer for. A fresh clone carries pointers but
no bytes; sync is what fills them back in without a manual document get per pointer.
navigator project sync --dry-run
navigator project sync
The dry run compares each pointer's recorded sha256 against the local file — no login, no network call — and lists
what would change:
would pull documents/exhibits/exhibit-a.png
1 pull(s) planned
The real run downloads through the same authenticated API sync uses, verifies the bytes against the pointer's own
sha256, and writes them to the staged path. A file whose digest already matches is left alone, so running pull again
after a full checkout prints 0 pulled. It hydrates only: a live document the checkout carries no pointer for is
sync's lane, not pull's. A pointer the signed-in account cannot read is reported, not silently skipped.
pull is all-or-nothing for document bytes. It first downloads every missing or stale revision into a task-owned
temporary staging area, then publishes the staged files only after every pointer is present, authorized, downloaded, and
verified against its sha256. If a pointer vanishes, access is denied, a download fails, or a digest mismatches, the
command fails without changing any pre-existing target bytes and without creating any newly hydrated target. The
documents/.gitignore file may still be created or retained; that file is outside the document-byte guarantee. Correct
the failure and rerun pull: a successful run hydrates the complete set, and the next run reports 0 pulled.
The portal is a separate, later decision
Not every Project needs a client-facing application. When one does, its portal/ is hand-built in the vibe-react lane
against a pinned @neon-law/ux release — the shell above deliberately leaves it out, so validate can tell "no portal
yet" from "portal exists" without ambiguity.
Verify
navigator project doctor --project <code>
navigator project drift --dir ~/neon-law
doctor reports whether this machine and this Project's coordinates agree — the repository URL, the Drive folder, and
the portal mount. drift reconciles a machine's checkouts against every live Project row.
Chapter 5
Wrap Up
You finished — claim your certificate
Enter your name and email and Neon Law will send a PDF certificate of completion.
We use your email only to send this certificate.