From l4-computational-law
Writes, validates, and deploys L4 rules to encode contracts, regulations, and policies as type-checked functional logic with obligations, deadlines, and API deployment.
npx claudepluginhub joshuarweaver/cascade-code-general-misc-4 --plugin smucclaw-l4-ideThis skill uses the workspace's default tool permissions.
L4 is a statically-typed, pure-functional language for computational law. It is layout-sensitive like Python, has Haskell-style algebraic data types, and adds legal-drafting affordances: backtick identifiers that read like prose, regulative rules (`PARTY … MUST … WITHIN … HENCE … LEST …`), and `@export`/`@desc` annotations that publish typed decision functions to a REST API/MCP.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
L4 is a statically-typed, pure-functional language for computational law. It is layout-sensitive like Python, has Haskell-style algebraic data types, and adds legal-drafting affordances: backtick identifiers that read like prose, regulative rules (PARTY … MUST … WITHIN … HENCE … LEST …), and @export/@desc annotations that publish typed decision functions to a REST API/MCP.
Canonical documentation — always authoritative for the currently-published L4:
https://legalese.com/l4/README.md
This file is a compact operational guide. For anything syntactic you do not remember, link through to the corresponding page on legalese.com/l4/... rather than guessing. Three deeper references ship in this skill:
#TRACE, and the MUST/MAY/SHANT/DO HENCE LEST BREACH machinery^, asyndetic .../.., § sections, computed fields, IS vs MEANS vs IF, mixfix)Reach for this skill when the user wants to:
jl4-service or Legalese Cloud, including as MCP tools for other AI agents.l4 file with the l4 CLI (l4 check, l4 run)L4 is the wrong tool for imperative scripting, UI code, numerical computing, or anything that requires mutation. If the task does not involve legal semantics or auditable decisions, reach for something else.
When given a PDF, URL, or natural-language description:
DECLARE-- Enum (sum type)
DECLARE RiskCategory IS ONE OF LowRisk, MediumRisk, HighRisk, Uninsurable
-- Enum with per-constructor fields
DECLARE Shape IS ONE OF
Circle HAS radius IS A NUMBER
Rectangle HAS width IS A NUMBER
height IS A NUMBER
-- Record (product type)
DECLARE Driver HAS
`name` IS A STRING
`age` IS A NUMBER
`years licensed` IS A NUMBER
`accident count` IS A NUMBER
`has tickets` IS A BOOLEAN
Records can declare computed fields (derived attributes) with MEANS; see references/gotchas.md and https://legalese.com/l4/reference/types/DECLARE.md.
L4 has three function-definition forms. Use whichever reads most like the source text.
-- General form: DECIDE … IS / … MEANS
GIVEN driver IS A Driver
GIVETH A RiskCategory
DECIDE `assess risk` driver IS
CONSIDER driver's `accident count`
WHEN 0 THEN IF driver's `has tickets`
THEN MediumRisk
ELSE LowRisk
WHEN 1 THEN MediumRisk
WHEN 2 THEN HighRisk
OTHERWISE Uninsurable
-- Boolean-returning shortcut: DECIDE … IF
GIVEN driver IS A Driver
GIVETH A BOOLEAN
DECIDE `meets minimum age` IF
driver's `age` AT LEAST 18
-- Plain MEANS
GIVEN n IS A NUMBER
`square of` n MEANS n TIMES n
Key idioms:
IF … THEN … ELSE idioms must always be indented in stair-stepping fashion. BRANCH IF … OTHERWISE is the flat multi-way-if form. Note that OTHERWISE must match IF intendation, not BRANCH.CONSIDER … WHEN … OTHERWISE … is the pattern-match form.WHERE introduces local helpers using … MEANS, DECIDE … IS, DECIDE … IF. LET x MEANS … IN … introduces a single local binding.YIELD makes lambdas: GIVEN n YIELD n GREATER THAN 0.`the applicant qualifies`); use them to make rules read like legal prose.`employee` `works for` `employer`.'s: person's age, application's employee's nationality. Note that function arguments bind stronger than genitive. f r's foo parses as (f r)'s foo, not f (r's foo).Isomorphic encoding — match the logical shape of the source text. If legislation has sections numbered 1.1 / 1.2 / 1.3 with three clauses joined by AND, your L4 should have three conjuncts in the same order. This keeps the rule auditable against the statute.
§ `Part I — Eligibility`
§§ `1.2 Conditions for coverage`
GIVEN damage IS A Damage
GIVETH A BOOLEAN
DECIDE `coverage applies` IF
NOT `caused by excluded pests` damage
AND ( `bird damage to contents` damage
OR `animal-caused water escape` damage)
§, §§, §§§, etc. mark sections — they are structural, not comments. See references/gotchas.md.
When the source text says "must", "may", "shall not", or "within X days", use L4's regulative rules:
paymentObligation MEANS
PARTY `The Borrower`
MUST `pay` `outstanding amount` EXACTLY `To Lender`
WITHIN 30
HENCE FULFILLED
LEST BREACH BY `The Borrower` BECAUSE "payment deadline exceeded"
Full treatment — MUST/MAY/SHANT/DO, HENCE/LEST semantics (note: SHANT flips polarity), BREACH BY … BECAUSE …, RAND/ROR composition, PROVIDED guards, EXACTLY matching, recursive obligations, and #TRACE simulation — is in references/regulative.md.
l4 CLI# Fast path — typecheck only, no evaluation. Use for lint / CI.
l4 check path/to/file.l4
# Full path — typecheck + evaluate every #EVAL/#EVALTRACE directive.
l4 run path/to/file.l4
# Pin "now" for reproducible evaluation of NOW/TODAY
l4 run --fixed-now=2025-01-01T00:00:00Z path/to/file.l4
# Machine-readable envelope for editors, CI, and agents
l4 run path/to/file.l4 --json
# From a Haskell checkout (no installed binary, needs legalese/l4-ide repo)
cabal run l4 -- run path/to/file.l4
If l4 isn't on your PATH and you're running inside VS Code, open the
L4 sidebar menu and pick Install L4 CLI. A shell-wrapper is
provided at scripts/validate.sh for environments
where PATH is problematic. Type errors are reported with line numbers —
iterate until the check passes.
Other subcommands (run l4 <command> --help for details):
l4 format FILE — reformat an .l4 file to stdout (gofmt-style).l4 ast FILE — dump the parsed AST (debugging L4 itself or tooling).l4 batch FILE --inputs rows.{json,yaml,csv} — evaluate an @export
function against many rows, streaming NDJSON output (one object per
row).l4 trace FILE [--format dot|png|svg] [-o DIR] — render
#EVALTRACE evaluation traces as GraphViz (PNG/SVG needs -o).l4 state-graph FILE — extract regulative-rule state transition
graphs as GraphViz DOT.#EVAL, #ASSERT, #TRACE`Alice` MEANS Driver WITH
`name` IS "Alice"
`age` IS 25
`years licensed` IS 7
`accident count` IS 0
`has tickets` IS FALSE
#EVAL `assess risk` `Alice`
#ASSERT `assess risk` `Alice` EQUALS LowRisk
Available directives: #EVAL, #EVALTRACE, #TRACE, #CHECK, #ASSERT.
See the Deployment section below. In short: add @export above the functions that should become API endpoints, add @desc to their parameters. Exported functions should answer the highest utility questions a reader of the rules might have. Often the rule definition is not written as such and a separate file importing the rules needs to decorate those export functions.
jl4-servicejl4-service turns L4 rule bundles into live, multi-tenant REST APIs. The same annotated source is automatically exposed as:
POST /deployments/{id}/functions/{fn}/evaluation/functions/{fn}/evaluation/batch (parallel case evaluation)/functions/{fn}/query-plan for interactive questionnaires that only ask the inputs that still matter/deployments/{id}/openapi.jsonPOST /deployments/{id}/.mcp for LLM tool-use clients<script src="/.webmcp/embed.js"> for browser AI agents?trace=full&graphviz=true on any evaluationSelf-hosted or managed. You can run jl4-service yourself (cabal run jl4-service), or use the managed Legalese Cloud offering, which gives each org a subdomain (https://{org-slug}.legalese.cloud), handled compilation, OAuth protection, and one-click deployment from the VS Code extension's Deploy tab. Both expose the same API shape, so annotations and client code are portable.
@export — publish a functionOnly functions marked @export are visible to the service. Place it directly above the GIVEN/function definition — not between GIVETH and DECIDE:
| Form | Effect |
|---|---|
@export <description> | Export this function with a human-readable description |
@export default <description> | Export as the bundle's default function |
@desc <description> | Internal description only — does not export |
The description is the single highest-value sentence in the whole file: it is what an LLM agent sees in its tool list when deciding whether to call this rule. Write it as if the agent has no other context.
-- ✘ Vague — agent cannot tell when to call this
@export do the calculation
-- ✘ Implementation detail leaking out
@export Apply the branching logic defined in §3.2
-- ✔ Clear domain intent
@export Calculate the annual income tax owed by an individual resident taxpayer
Module-level ASSUMEs that an @export function references are promoted to
parameters of that function and must be supplied by the caller — they behave
just like GIVEN parameters at the API boundary. ASSUMEs not referenced by
any exported function remain internal assumptions.
Function-typed inputs are not allowed for @export. Neither a GIVEN
parameter nor a referenced ASSUME may have a FUNCTION FROM … TO … type
on an exported function: GIVENs can't be passed over JSON, and function-typed
ASSUMEs stay uninterpreted at runtime (any call fails with a stuck
"assumed term" error). The typechecker and jl4-service deploy both reject
such bundles with Function type inputs are not supported for @export.
@desc — document parametersPut an inline @desc on every GIVEN parameter an API caller has to supply. These descriptions flow into the OpenAPI parameter docs and the MCP tool's inputSchema, and they are what LLMs read when deciding how to construct a valid call.
@export Calculate the cost of parking for a given day
GIVEN
day_of_week IS A NUMBER @desc Day of the week (1 = Monday, 2 = Tuesday, ..., 7 = Sunday)
is_public_holiday IS A BOOLEAN @desc Whether the day is a gazetted public holiday
current_weather IS A STRING @desc Current weather conditions. One of: "fair", "rain", "snow"
GIVETH A NUMBER
DECIDE parking_cost IS ...
A full working example is at assets/example-parking.l4.
Because exported metadata is what a downstream LLM sees in its tool-use context:
STRING accepts a fixed set, list them in the @desc. The type STRING is opaque to the schema generator — the LLM only knows what you tell it.@desc Amount in USD cents beats amount. Same for dates (ISO 8601, e.g. 2025-03-15) and durations (number of days).@desc for what the number means.@export answers "is this the tool I want?"; @desc answers "what do I put here?"@export and parameter @descs.l4 check (fast) or l4 run (full evaluation)..l4 files.curl -X POST http://localhost:8080/deployments \
-F "id=my-rules" \
-F "sources=@/tmp/bundle.zip"
GET /deployments/{id}/openapi.json to confirm the exported surface.curl -X POST http://localhost:8080/deployments/my-rules/functions/parking_cost/evaluation \
-H "Content-Type: application/json" \
-d '{"arguments": {"day_of_week": 6, "is_public_holiday": false, "current_weather": "fair"}}'
L4 identifiers with spaces (`calculate premium`) are automatically hyphenated for JSON/URL use (calculate-premium). The REST API accepts both the spaced and hyphenated forms. If two L4 names would collide after sanitization (e.g. `foo bar` and `foo-bar`), compilation fails with an explicit error.
When the agent is pointed at a .legalese.cloud host, endpoints are OAuth-protected. Discovery starts at:
https://{org-slug}.legalese.cloud/.well-known/oauth-protected-resource
Fetch this first to learn which authorization server issues tokens and what scopes are required (the same resource_metadata link appears in WWW-Authenticate: Bearer … challenges). Then pass Authorization: Bearer <token> on REST, MCP, and WebMCP requests.
Other useful well-known paths on a Legalese Cloud org:
/.well-known/mcp — MCP server discovery/.well-known/webmcp — WebMCP discovery manifest/openapi.json — org-wide OpenAPI 3.0 spec/deployments?functions=full — cached metadata for all deploymentsFor the full service reference (CLI flags, resource limits, deontic evaluation shapes), see the jl4-service README bundled with the running server.
Just enough to write most rules without a round-trip. Anything not here, check https://legalese.com/l4/reference/GLOSSARY.md.
| L4 | Meaning |
|---|---|
NUMBER | Integers and rationals |
STRING | Text |
BOOLEAN | TRUE / FALSE |
DATE / TIME / DATETIME | Calendar date / time-of-day (wallclock) / instant |
LIST OF T | Ordered collection |
MAYBE T | Optional (JUST x / NOTHING) |
EITHER A B | Choice (LEFT x / RIGHT y) |
DECLARE T HAS ... | Record |
DECLARE T IS ONE OF a, b, c | Enum (optionally with per-constructor HAS fields) |
TODAY returns DATE. CURRENTTIME returns TIME. Both need e.g. TIMEZONE IS "America/New_York" to return a value.
NOW returns DATETIME and is always "Etc/UTC" unless otherwise specified.
Full table at https://legalese.com/l4/reference/GLOSSARY.md. The ones used constantly:
AND, OR, NOT, IMPLIES (=>), UNLESS (= AND NOT)EQUALS, GREATER THAN / ABOVE, LESS THAN / BELOW, AT LEAST (≥), AT MOST (≤)PLUS, MINUS, TIMES, DIVIDED BY, MODULO — or +, -, *, /CONCAT, APPENDLIST a, b, c, EMPTY, x FOLLOWED BY xsIF cond THEN a ELSE b
CONSIDER value
WHEN Pat1 THEN r1
WHEN Pat2 WITH field THEN r2
OTHERWISE rDefault
BRANCH IF x EQUALS 1 THEN "one"
IF ^ EQUALS 2 THEN "two"
OTHERWISE "other"
The caret ^ is the ditto operator — "same as the cell above". See references/gotchas.md.
Person WITH `name` IS "Alice", `age` IS 30
person's `name`
application's employee's nationality -- chaining
#EVAL expr — evaluate and print#EVALTRACE expr — evaluate with execution trace#CHECK expr — type-check without evaluating#ASSERT bool_expr — assert must be TRUE#TRACE contract AT time WITH ... — simulate a regulative rule; see references/regulative.md@desc — human-readable description behind any line or GIVEN parameter (internal unless paired with @export)@export — atop the GIVEN. mark a function for deployment@nlg — natural-language generation hint@ref, @ref-src, @ref-map — cross-reference to a legal sourceImports should be the first lines in a file before anything else.
IMPORT prelude
IMPORT `excel-date`
The prelude is always available. For the full library list (prelude, daydate, time, datetime, timezone, math, currency, legal-persons, jurisdiction, actus, llm, excel-date, holdings, date-compat), see references/builtins.md or https://legalese.com/l4/reference/libraries.md.
Filenames with hyphens, spaces, or other non-identifier characters must be backtick-quoted.
L4's target users are policy writers and legal authors, not programmers. Write rules that read like prose and make generous use of the tick marked identifiers containing full phrases
-- ✔ Reads like legal text
GIVEN person IS A Person
GIVETH A BOOLEAN
DECIDE `the person is eligible for benefits` IF
`the person is a citizen`
AND `the person has resided for at least 5 years`
AND NOT `the person has been disqualified`
-- ✘ Reads like programmer code
GIVEN p IS A Person
GIVETH A BOOLEAN
isEligible p MEANS p's citizen && p's years >= 5 && !p's disqualified
Use backtick identifiers liberally. `the applicant` not applicant. `has valid identification` not hasValidID.
OTHERWISE or handle every enum constructor.IMPORT.TOSTRING, TONUMBER, TODATE, …); L4 does no implicit coercion. See references/builtins.md.#TRACE returns a residual obligation instead of FULFILLED — the trace ended in a state with open obligations. Read the residual: it tells you exactly what's still owed and by whom.For compiler-error recipes, see https://legalese.com/l4/reference/errors.md.
All documentation for the currently-published L4 release lives under https://legalese.com/l4/...:
The website tracks the currently-published L4 version; treat it as ground truth over any snippet in this skill.