Build it
The legal brand's folder, one file at a time. Its words, its rules table and its Pool first, then six Services, with check after each one.
legal's wordsmatter is a jobasset is a subjectreview is a tasksigner is a membernetwork is a pooloutcome is a end
The brand is a folder: brand.ts, rules.ts, pools/attorneys.ts, and one file per Service under services/. Write them in that order and run check after each. The count it prints is lines of code, comments left out, and every file stays within 40.
The brand's words. Every surface its clients, agents and attorneys read says matter, review and signer, and also keeps api.lawyer's own paths for the same operations. Your brand's words covers each key.
cat brand.tsimport { Brand } from 'services.dev'
// A legal brand shaped like api.lawyer. Its words render every surface its
// buyers, agents and signers read: /matters, matter.ordered, get_matter. `also` keeps api.lawyer's own paths
// for the same rows: a matter's journal and attestations are its record, its documents are its files, and a
// signer's conflicts ledger is /conflicts.
export default Brand({
domain: 'api.lawyer',
words: { job: 'matter', subject: 'asset', task: 'review', member: 'signer', pool: 'network', end: 'outcome' },
also: {
'job.record': ['/matters/:id/journal', '/matters/:id/attestations?type=attested'],
'job.files.list': '/matters/:id/documents',
'job.files.put': 'POST /matters/:id/documents',
'job.end': '/matters/:id/terminal',
'member.ledger.get': '/conflicts',
'member.ledger.add': '/conflicts/entries',
},
})With no Service yet, check has nothing to sell:
npx services.dev check # after brand.tsNo Services here.
next npx services.dev initWho may perform each act, per Service, frozen under a version. Every row is illustrative and records its position. The rules table reads each one.
$ cat rules.ts
import { Rules } from 'services.dev'
// Rows per Service, frozen and versioned. A brand's counsel authors its real
// table, and every row records its position. An advice row reserves a class of answer, held in the job's thread until
// the attorney on the matter adopts it. An attorney's fee is the signer's own, sold on their account at the same
// checkout; a practitioner's act on a patent is the brand's.
const practitioner = ['patent attorney', 'patent agent']
export default Rules({
version: '2026-10',
The people: four roles, each a credential the Pool's verifier checks, and what a member sees before and after they claim. The attorneys' Pool shows a member join.
$ cat pools/attorneys.ts
import { Pool } from 'services.dev'
// One Pool, shared by every legal Service: attorneys join, the verifier checks each admission, and
// a cascade offers each Task one member at a time, because `check` names parties. Tiers are computed from outcomes,
// so the default fill ladder widens to the next one down. An attorney's own malpractice policy covers their act; one
// who carries none is covered by the Pool's, at $4 an act. A claim holds three times the step's estimate, at least a day.
export const attorneys = Pool({
name: 'attorneys',
roles: {
attorney: { credential: 'bar admission' },
The first Service answers an office action and files it. Now check reads the whole folder: the brand, the table and the Pool, then the Service's steps, who signs, and what each matter leaves you.
$ cat services/trademark-response.ts
import { Service } from 'services.dev'
import { attorneys } from '../pools/attorneys.ts'
import rules from '../rules.ts'
// The attorney comes from the attorneys Pool, admitted anywhere, and signs and files on their own
// account. The office action's three-month clock sits on the family, and an extension moves it.
export default Service({
name: 'Trademark Office Action Response',
description: 'An office action answered and filed.',
input: { serial: 'text: such as 97123456', action: 'file: the office action', issued: 'date: such as 2026-10-01', client: 'party' },
npx services.dev check # after services/trademark-response.tsbrand.ts · 10 lines · legal · api.lawyer · words job → matter, subject → asset, task → review, member → signer, pool → network, end → outcome
rules.ts · 36 lines · rules 2026-10 · 6 Services · 16 rows · 1 shared
pools/attorneys.ts · 20 lines · attorneys · 4 roles: attorney, practitioner, watcher, student · joins in 3 steps · cascade · hold 24h
inert rules rail on 9 rows: the ledger names who sells each fee; money moves at payout
services/trademark-response.ts · 21 lines · $349 per job, within 48 hours, charged on file's receipt.
who An attorney signs every response before it is filed. (rules 2026-10) The client consents first and uploads at evidence.
roles attorney · bar admission · from attorneys · $175 an act
steps consent · client · consent → read · ai · cites source → evidence · client · upload → draft · ai → attack · ai · adversarial · 3 lenses → respond · attorney · * · stamped · 2-item checklist → file · USPTO → fee · USPTO · routed
bounds reserved respond and file to bar admission · the attorney sells the fee · open fee · refused litigate
agent order_trademark_response · 30 of 30 words · add "such as …" to client for an agent to try it
ledger +$349.00 · attorney's fee $175.00, sold by the attorney (rail member) · brand $174.00 · AI $2.10 (example) · coverage $4.00 · you $167.90
margin at least $100.20 when the first attorney signs ($349.00 − $175.00 attorney − $69.80 AI cap − $4.00 coverage) · $12.70 at the ladder's cap, the lower of 50% and what the floor leaves · −$78.80 after a decline and a second attorney
a job that stops costs you at most $244.80
apps customer portal · delivery portal · owner console
✗ The rules table binds a name nothing reads: a key that names no Service file, or a row no step performs that is neither an advice class nor refused. Rename it to what it means, or take it out. rules.services has a key 'provisional-patent', and no Service file is services/provisional-patent.ts. rules.services has a key 'contract-review', and no Service file is services/contract-review.ts. rules.services has a key 'demand-letter', and no Service file is services/demand-letter.ts. rules.services has a key 'docket-watch', and no Service file is services/docket-watch.ts. rules.services has a key 'formation', and no Service file is services/formation.ts.
at rules.ts:12 · rules.services['provisional-patent']
https://services.dev/docs/reference/check/rule_unread
mcp 13 buyer tools · 4,633 of 8,000 tokens · 9 more with ?toolset=sandbox
The table names six Services and the folder has one, so check holds the brand at rule_unread until each is written.
A subscription on the patent family that routes an office action to the response. Docket watch walks it:
$ cat services/docket-watch.ts
import { Service } from 'services.dev'
import { attorneys } from '../pools/attorneys.ts'
import rules from '../rules.ts'
import trademarkResponse from './trademark-response.ts'
// A subscription on the patent family, $12 a month. Every Monday the AI checks the docket, and inside
// the last week before a date on the family, the watcher acknowledges it too. An office action routes to its own Service.
export default Service({
name: 'Docket Watch',
description: 'A docket watched every week, and an office action routed to its response.',
npx services.dev check # after services/docket-watch.tsservices/docket-watch.ts · 10 lines · $12 per month, charged at the start of each month.
ledger +$12.00 · AI $0.84 (example) · watcher $4.00 · coverage $4.00 · you $3.16
✗ The rules table binds a name nothing reads: a key that names no Service file, or a row no step performs that is neither an advice class nor refused. Rename it to what it means, or take it out. rules.services has a key 'provisional-patent', and no Service file is services/provisional-patent.ts. rules.services has a key 'contract-review', and no Service file is services/contract-review.ts. rules.services has a key 'demand-letter', and no Service file is services/demand-letter.ts. rules.services has a key 'formation', and no Service file is services/formation.ts.
✗ 1 to fixIts patent family names the docket watch as its steward.
$ cat services/provisional-patent.ts
import { Service } from 'services.dev'
import { attorneys } from '../pools/attorneys.ts'
import rules from '../rules.ts'
import docketWatch from './docket-watch.ts'
// The practitioner comes from the attorneys Pool, and the rules reserve signing and filing. price.self
// lets the applicant sign and file it themselves, for $79. The practitioner who signs stays of record on the patent
// family; if their registration lapses, another practitioner covers it, then the brand. The docket watch keeps its dates.
export default Service({
name: 'Provisional Patent Application',
npx services.dev check # after services/provisional-patent.ts ✗ The rules table binds a name nothing reads: a key that names no Service file, or a row no step performs that is neither an advice class nor refused. Rename it to what it means, or take it out. rules.services has a key 'contract-review', and no Service file is services/contract-review.ts. rules.services has a key 'demand-letter', and no Service file is services/demand-letter.ts. rules.services has a key 'formation', and no Service file is services/formation.ts.
services/provisional-patent.ts · 24 lines · $199 per job, within 5 days, charged on file's receipt.
✗ 1 to fixEach file, whole, then what check prints once it's added; each one's page walks it:
$ cat services/contract-review.ts
import { Service } from 'services.dev'
import { attorneys } from '../pools/attorneys.ts'
import rules from '../rules.ts'
// The attorney comes from the attorneys Pool, admitted where the client is, and rules.ts ratifies
// the advice in US-CA, US-NY and US-TX. Advice the AI drafts in the thread is held for the attorney who claimed advise,
// included in their fee, up to three answers. The client consents before any attorney reads the parties' names.
export default Service({
name: 'Contract Review',
description: 'A contract flagged, then advised on.',
npx services.dev check # after services/contract-review.tsservices/contract-review.ts · 16 lines · $99 per job, within 48 hours, charged on acceptance.
✗ The rules table binds a name nothing reads: a key that names no Service file, or a row no step performs that is neither an advice class nor refused. Rename it to what it means, or take it out. rules.services has a key 'demand-letter', and no Service file is services/demand-letter.ts. rules.services has a key 'formation', and no Service file is services/formation.ts.
✗ 1 to fix$ cat services/demand-letter.ts
import { Service } from 'services.dev'
import { attorneys } from '../pools/attorneys.ts'
import rules from '../rules.ts'
// The attorney comes from the attorneys Pool, and signs on their own account. Whether to settle is the
// client's decision alone (rules.ts): every offer reaches them, and an offer under their floor raises below_floor rather
// than being turned away. The floor is merits: only the client sets it, and it is their default answer.
// The draft doesn't cite here: under cite: 'source' every output field is { value, source }, which the
// typed `settlement` doesn't say (a finding for the next pass).
export default Service({
npx services.dev check # after services/demand-letter.ts ✗ The rules table binds a name nothing reads: a key that names no Service file, or a row no step performs that is neither an advice class nor refused. Rename it to what it means, or take it out. rules.services has a key 'formation', and no Service file is services/formation.ts.
services/demand-letter.ts · 26 lines · $149 per job, within 48 hours, charged on send's receipt.
✗ 1 to fix$ cat services/formation.ts
import { Service } from 'services.dev'
import { attorneys } from '../pools/attorneys.ts'
import rules from '../rules.ts'
// The brand forms the entity, an open act; which entity, and the 83(b), are an attorney's advice, admitted
// where the founders are. Two clocks recur on the company and outlive the job: its end asks the client to own them.
export default Service({
name: 'Company Formation',
description: 'A company formed, papers signed.',
input: {
npx services.dev check # after services/formation.tsservices/formation.ts · 30 lines · $299 per job, within 48 hours, charged on form_entity's receipt.
✓ ready to sell · 6 Services · each keeps at least 3% of every jobThe last reads the table's last name, and the brand is ready to sell. Every branch runs what these files can do.