agentleFS
emtcmcaemtcmca/claude-for-legal-billing/skills/ledes-export/SKILL.md

ledes-export

Skill1 starsChanged 3 months agoMITView on GitHub

Export a billing invoice to LEDES 1998B format for submission to corporate legal department e-billing systems. Use after generating an invoice exhibit with invoice-generate, when a client's legal ops team requires LEDES format for their matter management or e-billing platform.

The file

Show its rules and text

We split this skill into the rules it gives an agent

14 rules. About 0 are common, 3 are distinctive, and 11 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 11

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Read ~/.claude/plugins/config/claude-for-legal/billing/CLAUDE.md.

    line 25
  2. Very specific:

    If no matching invoice found: "Invoice [id] not found in invoice-register.yaml.

    line 39
  3. Very specific:

    --client <slug> [--period YYYY-MM]: Read [billing_data_path]/time-register.yaml.

    line 41
  4. Distinctive:

    If neither argument is provided: list clients that have billed or approved entries and ask which one to export.

    line 43
  5. Distinctive:

    Read the register through the validator, not by hand: Run:

    line 47
  6. Distinctive:

    Do not recompute them and do not carry figures forward from earlier in the conversation.

    line 55
  7. Very specific:

    If scripts/register-read.ps1 is not present, this is an install predating it.

    line 62
  8. Very specific:

    All dates in LEDES 1998B are formatted YYYYMMDD (no separators).

    line 80
  9. Very specific:

    If loaded from an invoice record, use period_start and period_end instead of computing from entries.

    line 86
  10. Very specific:

    If original_amount is null, the entry was never written down.

    line 92
  11. Very specific:

    If original_amount is set, LINE_ITEM_ADJUSTMENT_AMOUNT = original_amount - amount, to 2 decimal places.

    line 93
  12. Very specific:

    No trailing newline after the last []

    line 102
  13. Very specific:

    All numeric amounts formatted with exactly 2 decimal places (e.g., 280.00)

    line 103
  14. Very specific:

    If exporting without a finalized invoice (--client + --period), use the filename [client-slug]-[YYYY-MM].ledes.

    line 152

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

/billing-legal:ledes-export

When this runs

An invoice has been generated and the client requires LEDES 1998B format for their e-billing system. This is common for corporate legal departments, insurance companies, and large institutional clients.

Instructions

Preflight - read /billing-legal:billing-guardrails first. It carries the approval gate, the append-only record rule, UTBMS field discipline, and the boundary on what this plugin records rather than decides. Where it conflicts with the steps below, the stricter rule wins.

1. Read config

Read ~/.claude/plugins/config/claude-for-legal/billing/CLAUDE.md. Check for placeholders — if present, stop and direct to /billing-legal:cold-start-interview.

Get:

  • billing_data_path
  • Firm name
  • LEDES export setting — if disabled, warn: "LEDES export is disabled in your billing config. Enable it with /billing-legal:customize or set LEDES export: enabled in your billing CLAUDE.md. Proceeding anyway — you can always run this skill directly."
  • Default timekeeper classification

2. Resolve scope

Parse $ARGUMENTS:

--invoice <id> (preferred): Load the invoice record from [billing_data_path]/invoice-register.yaml where id: [id]. Get period_start, period_end, client, entry_ids, total_fees, date.

If no matching invoice found: "Invoice [id] not found in invoice-register.yaml. Check /billing-legal:billing-report --invoice [id] or use --client to export by client and period."

--client <slug> [--period YYYY-MM]: Read [billing_data_path]/time-register.yaml. Filter to entries with client: [slug] and status: billed (or approved if --period is used without a finalized invoice). If --period is supplied, restrict to entries in that month.

If neither argument is provided: list clients that have billed or approved entries and ask which one to export.

3. Load entries and attorney profiles

Read the register through the validator, not by hand. Run:

powershell -NoProfile -NonInteractive -File "[billing_data_path]/scripts/register-read.ps1" -Client [client-slug]

It resolves the data path from config, confirms the register exists, parses every entry, checks that each amount equals hours x rate, and emits JSON with per-status totals. Use its numbers. Do not recompute them and do not carry figures forward from earlier in the conversation.

  • Exit 2: the register is absent. Stop, report the path it printed, write nothing.
  • Exit 3: it parsed but failed an invariant. Show the errors array and stop before any write. A register whose arithmetic does not hold has been edited by something other than this plugin.
  • Exit 4: config missing or still holds placeholders. Direct to /billing-legal:cold-start-interview.

If scripts/register-read.ps1 is not present, this is an install predating it. Say so, then fall back to reading the file directly under the rule below.

If time-register.yaml does not exist, STOP. Say: "No time register at [billing_data_path]/time-register.yaml. That file is absent, not empty -- billing data may be unsynced, the data path may be wrong, or the file may have been moved. I am not going to report figures I cannot read." Do not create it, do not proceed with zeroes, and do not answer from earlier in the conversation. Absent is a different condition from empty or comment-only, which is the normal state of a fresh install.

From time-register.yaml, load all entries matching the resolved scope. Exclude entries with status: write-off — zero-dollar lines are not valid in LEDES format.

For each unique attorney slug in the entries, read [billing_data_path]/attorneys/[slug].yaml. Get:

  • name
  • timekeeper_id (fall back to attorney slug if field is absent)
  • timekeeper_classification (fall back to Default timekeeper classification from config, then AT)

Read [billing_data_path]/clients/[client-slug].yaml. Get:

  • name
  • ledes_client_id (fall back to client slug uppercased, with hyphens replaced by underscores, e.g., acme-corp → ACME_CORP)

4. Compute dates

All dates in LEDES 1998B are formatted YYYYMMDD (no separators).

  • INVOICE_DATE: use date from invoice record, or today's date if exporting outside a finalized invoice
  • BILLING_START_DATE: earliest entry date in scope, formatted YYYYMMDD
  • BILLING_END_DATE: latest entry date in scope, formatted YYYYMMDD

If loaded from an invoice record, use period_start and period_end instead of computing from entries.

5. Compute write-down adjustment per entry

LEDES requires LINE_ITEM_ADJUSTMENT_AMOUNT — the amount reduced from the original billing through a write-down. The register stores the pre-write-down figures, so this is arithmetic, not inference:

  • If original_amount is null, the entry was never written down. LINE_ITEM_ADJUSTMENT_AMOUNT = 0.00. This is the common case.
  • If original_amount is set, LINE_ITEM_ADJUSTMENT_AMOUNT = original_amount - amount, to 2 decimal places. amount is already the post-write-down figure, so LINE_ITEM_TOTAL still uses amount.
  • Never parse notes to recover a figure. notes holds the attorney's reason in free text, in whatever words they chose. A number reconstructed from a sentence is a guess, and a guess in an adjustment column silently understates what the client was given. Entries written down before original_amount existed carry null and correctly export 0.00.

6. Build the LEDES 1998B file

LEDES 1998B format rules:

  • Line 1: LEDES1998B[] (literal, no spaces)
  • Line 2: pipe-delimited column headers, ending with []
  • Lines 3+: one data row per time entry, pipe-delimited, ending with []
  • No trailing newline after the last []
  • All numeric amounts formatted with exactly 2 decimal places (e.g., 280.00)
  • Dates formatted YYYYMMDD
  • Pipe characters in narrative text must be replaced with a space

Column order (fixed — do not reorder):

INVOICE_DATE|INVOICE_NUMBER|CLIENT_ID|LAW_FIRM_MATTER_ID|INVOICE_TOTAL|BILLING_START_DATE|BILLING_END_DATE|INVOICE_DESCRIPTION|LINE_ITEM_NUMBER|EXP/FEE/INV_ADJ_TYPE|LINE_ITEM_TASK_CODE|LINE_ITEM_EXPENSE_CODE|LINE_ITEM_ACTIVITY_CODE|TIMEKEEPER_ID|TIMEKEEPER_NAME|LINE_ITEM_NUMBER_OF_UNITS|LINE_ITEM_ADJUSTMENT_AMOUNT|LINE_ITEM_TOTAL|LINE_ITEM_DESCRIPTION|LAW_FIRM_MATTER_ID|TIMEKEEPER_CLASSIFICATION

Field values per row:

ColumnValue
INVOICE_DATEInvoice date, YYYYMMDD
INVOICE_NUMBERInvoice ID (e.g., INV-2026-007)
CLIENT_IDclient.ledes_client_id or slug uppercased
LAW_FIRM_MATTER_IDentry.matter_slug (or empty string if null)
INVOICE_TOTALSum of all entry amounts in this export, 2 decimal places — same value on every row
BILLING_START_DATEPeriod start, YYYYMMDD
BILLING_END_DATEPeriod end, YYYYMMDD
INVOICE_DESCRIPTIONLegal Services - [Firm Name] (ASCII hyphen, never an em dash)
LINE_ITEM_NUMBERSequential integer starting at 1
EXP/FEE/INV_ADJ_TYPEF (fee — for all time entries)
LINE_ITEM_TASK_CODEentry.task_code or empty string
LINE_ITEM_EXPENSE_CODE(empty)
LINE_ITEM_ACTIVITY_CODEentry.activity_code or empty string
TIMEKEEPER_IDattorney.timekeeper_id or attorney slug
TIMEKEEPER_NAMEattorney.name
LINE_ITEM_NUMBER_OF_UNITSentry.hours (decimal, e.g., 0.80)
LINE_ITEM_ADJUSTMENT_AMOUNTWrite-down delta or 0.00
LINE_ITEM_TOTALentry.amount, 2 decimal places
LINE_ITEM_DESCRIPTIONentry.narrative (pipe chars replaced with spaces)
LAW_FIRM_MATTER_IDentry.matter_slug again (LEDES spec repeats this column)
TIMEKEEPER_CLASSIFICATIONattorney.timekeeper_classification

Example output:

LEDES1998B[]
INVOICE_DATE|INVOICE_NUMBER|CLIENT_ID|LAW_FIRM_MATTER_ID|INVOICE_TOTAL|BILLING_START_DATE|BILLING_END_DATE|INVOICE_DESCRIPTION|LINE_ITEM_NUMBER|EXP/FEE/INV_ADJ_TYPE|LINE_ITEM_TASK_CODE|LINE_ITEM_EXPENSE_CODE|LINE_ITEM_ACTIVITY_CODE|TIMEKEEPER_ID|TIMEKEEPER_NAME|LINE_ITEM_NUMBER_OF_UNITS|LINE_ITEM_ADJUSTMENT_AMOUNT|LINE_ITEM_TOTAL|LINE_ITEM_DESCRIPTION|LAW_FIRM_MATTER_ID|TIMEKEEPER_CLASSIFICATION[]
20260601|INV-2026-007|ACME_CORP|acme-msa-2026|420.00|20260501|20260531|Legal Services - Hartley & Associates LLP|1|F|L200|||aj001|Alice Jones|0.80|0.00|280.00|Reviewed vendor MSA redline; drafted markup on limitation of liability and IP ownership|acme-msa-2026|AT[]
20260601|INV-2026-007|ACME_CORP|acme-msa-2026|420.00|20260501|20260531|Legal Services - Hartley & Associates LLP|2|F|L200|||aj001|Alice Jones|0.40|0.00|140.00|Call with client re counterparty response; revised markup|acme-msa-2026|AT[]

7. Write the file

Write to [billing_data_path]/invoices/[invoice-id].ledes.

If exporting without a finalized invoice (--client + --period), use the filename [client-slug]-[YYYY-MM].ledes.

8. Confirm

✓ LEDES 1998B export written:
   File:     [billing_data_path]/invoices/[filename].ledes
   Entries:  [N] line items
   Total:    $[total]
   Client:   [Client Name]  (CLIENT_ID: [ledes_client_id])
   Period:   [start] – [end]

Write-off entries excluded: [N]  (zero-dollar lines are not valid in LEDES format)

To submit: attach this file to your e-billing portal upload.
To view: open in any text editor — it's pipe-delimited plain text.

Tip: if the client's system rejects the file, verify the CLIENT_ID matches
what their e-billing system expects. Update it with:
  /billing-legal:rate-card override --client [slug]

Notes on LEDES 1998B compatibility

LEDES 1998B is the most widely accepted variant. A few edge cases:

  • No task code: Some e-billing systems require LINE_ITEM_TASK_CODE. If entries are missing task codes, the upload may be rejected. Consider enabling Task codes: required in your billing config.
  • Timekeeper ID: Many corporate clients map timekeeper IDs to their own records. Set timekeeper_id on attorney profiles to match the ID your client has on file, via /billing-legal:rate-card set --attorney [slug].
  • Client ID: Corporate clients often assign their own matter/client IDs. Set ledes_client_id on the client profile to match, via /billing-legal:rate-card override --client [slug].
  • Flat-fee matters: LEDES line items require a unit count and line total. For flat-fee entries, hours are logged but amounts are $0 (or the flat amount divided across entries). The export will include these as-is.

What this skill does not do

  • Submit the file to any e-billing system — this is a file export only
  • Generate the primary invoice — use /billing-legal:invoice-generate first
  • Validate against a specific client's LEDES configuration — contact the client's legal ops team for their field requirements

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.