THE INTRO CARD is free — what an AI skill card is and how to use one Download →Lost Lauren, contact us

THE INSTRUMENTS · Nº 965 · EDITION 1 · LAUNCHING SOON

LUND CARDS · THE INSTRUMENTSNº 965
THE TOOL SCHEMA CARD — the LSC-1 face
THE CARD AS TEXT · FOR EYES AND FOR MACHINES

THE TOOL SCHEMA CARD · the schema seat · every tool's input, checked before the agent ships

WAKES WHEN tool definitions are written or reviewed, a tool call arrives with a missing or malformed field, a handler needs test inputs, or tools move to strict mode

THE METHOD

  1. lint TOOLS.json [--strict-all] — the verdict, every finding with its rule id, path and fix, the size table, and the strict counts.
  2. samples TOOLS.json --out SAMPLES.jsonl — inputs for the handler tests.
  3. calls TOOLS.json CALLS.jsonl — the logged calls, every failure, the causes.
  4. rules — the facts used, with pages and dates. Edit assets/api-rules.json when the docs move.

REFUSES

  • Answering the naming rule or strict-mode limits from memory
  • Typing an exact token count it did not measure
  • Calling a FAIL a pass
  • Presenting generated samples as real calls
  • Inventing a log

IT MAKES lint — every tool and parameter against the rules; exit 1 on any ERROR; samples — valid and invalid inputs for each tool's handler (JSONL); calls — logged tool calls checked against the schemas; exit 1 when any fails; rules — the platform facts the lint uses, with their sources and dates.

THE LAW Every finding, size and count comes from the machine. Nothing is typed from memory. The platform's rules are data with a date and a page (assets/api-rules.json). When the docs change, the file changes; the machine says which date it used. ERRORs come first, each with its fix. A FAIL is never reported as a pass. Token counts are estimates and are labelled so; exact counts come from the API's token counting endpoint. Generated samples are test inputs. A log of calls is never invented. The tools file is read, not changed. Judgement is marked: the enum hints and the size thresholds are house heuristics, not platform limits.

IN THE BOX scripts/toolschema.py · assets/api-rules.json · the lint rules · the formats · the method by hand · the sources · ten tests.

PROOF selftest 28/28; a lint of an eight-tool support agent and the trigger test on the record (WITNESS.md) · witnessed 2026-10-13 · EDITION 1.

THE SEAL 96 of 100 · LEGENDARY · WITNESSED · Trigger 5 · Machinery 5 · Law 5 · Portability 5 · Proof 4

IT CAN BE WRONG an AI reading a text file: it can be wrong and can invent a number, a rule, a name or a date; check what matters against your own records and the source; the risk is yours. LICENSE-NOTE.md rides in the packet and is the licence.

THE PUNCH · SHA-256 OF SKILL.MD · CDA19DC0435DD9427A3A6805

THE FACE, FULL SIZE → · THE MACHINE FACE → · card.json →

THE TOOL SCHEMA CARD

the schema seat · every tool's input, checked before the agent ships

LINT · SAMPLES · CALLS · RULES

96LEGENDARYWITNESSEDIN CLAUDEIN LUNDRIN CHATGPT

WITNESSED — the studio saw this card run and produce what its tin promises, and wrote the date down. What the marks mean →

THE SPEC SHEET · READ BEFORE YOU BUY · THE STANDARD EVERY CARD MEETS →

SEAL
96 of 100 · LEGENDARY · WITNESSED
EDITION
E1 · witnessed 2026-10-13
MACHINE
scripts/toolschema.py · 4 commands · selftest 28/28
RUNS
On your own computer. Standard library only, offline; no account, no key, no telemetry.
HOSTS
Claude · Claude Code · ChatGPT · Gemini · any AI that reads a file (HOSTS.md names each door)
LICENCE
One person, any number of their own AIs and computers · editions replace files · nothing renews · freeze, not loss
PUNCH
CDA19DC0435DD9427A3A6805 · sha-256 of SKILL.md · check any file against it →

CITE THIS CARDTHE TOOL SCHEMA CARD, Edition 1. Lund Studio LLC, Westminster, Colorado. https://lundr.tech/?view=tool-schema-card. Punch CDA19DC0435DD9427A3A6805. Retrieved 2026-10-13.

What it is.

The schema half of an agent's tools: the input_schema of every tool in a Claude Messages API tools list, checked in four parts.

Use it whenever tool definitions are written or reviewed, a tool call arrives with a missing or malformed field, a handler needs test inputs, or tools move to strict mode. Not for a tool's description wording or which tool is picked (THE TOOL WORDS), tool permissions (THE TOOL MANNERS CARD), stale docs (THE DRIFT CARD).

It carries a machine that shows its working: lint — every tool and parameter against the rules; exit 1 on any ERROR; samples — valid and invalid inputs for each tool's handler (JSONL); calls — logged tool calls checked against the schemas; exit 1 when any fails; rules — the platform facts the lint uses, with their sources and dates — 28 checks in its selftest.

It answers requests such as “lint our tools.json before we ship”, “Claude keeps leaving out the currency field and the handler crashes”, “will these schemas work with strict: true?”, “is this a legal tool name?”, “give me valid and invalid inputs to test each handler”, “which of these logged tool calls were malformed?”.

Seven laws, written into the card.

They are in the card itself, so the AI follows them.

EVERY FINDINGEvery finding, size and count comes from the machine. Nothing is typed from memory.
THE PLATFORM'S RULES ARE DATA WITH…The platform's rules are data with a date and a page (assets/api-rules.json). When the docs change, the file changes; the machine says which date it used.
ERRORS COME FIRSTERRORs come first, each with its fix. A FAIL is never reported as a pass.
TOKEN COUNTS ARE ESTIMATES AND ARE LABELLED SOToken counts are estimates and are labelled so; exact counts come from the API's token counting endpoint.
GENERATED SAMPLES ARE TEST INPUTSGenerated samples are test inputs. A log of calls is never invented.
THE TOOLS FILE IS READThe tools file is read, not changed.
JUDGEMENT IS MARKEDJudgement is marked: the enum hints and the size thresholds are house heuristics, not platform limits.

The method.

  1. lint TOOLS.json [--strict-all] — the verdict, every finding with its rule id, path and fix, the size table, and the strict counts.
  2. samples TOOLS.json --out SAMPLES.jsonl — inputs for the handler tests.
  3. calls TOOLS.json CALLS.jsonl — the logged calls, every failure, the causes.
  4. rules — the facts used, with pages and dates. Edit assets/api-rules.json when the docs move.

What rides in the card.

In the card’s own voice, with a machine that shows its working.

THE REFERENCESreferences/FORMATS.md · LINT-RULES.md · SOURCES.md · THE-METHOD.md
THE MACHINEscripts/toolschema.py · four commandslint — every tool and parameter against the rules; exit 1 on any ERROR; samples — valid and invalid inputs for each tool's handler (JSONL); calls — logged tool calls checked against the schemas; exit 1 when any fails; rules — the platform facts the lint uses, with their sources and dates. 28 checks in its selftest. Needs: Python 3; a tools file in the Messages API format.

What it does once your AI has it.

  • lint Every tool and parameter against the rules; exit 1 on any ERROR
  • samples Valid and invalid inputs for each tool's handler (JSONL)
  • calls Logged tool calls checked against the schemas; exit 1 when any fails
  • rules The platform facts the lint uses, with their sources and dates
  • On the record Example Co's eight-tool support agent linted (6 ERROR, then PASS), its refund handler given 22 checked inputs, a week of calls checked (4 of 7 malformed); 41 of 48 in the trigger test after the rewrite

What it refuses, and where it hands off.

It refuses answering the naming rule or strict-mode limits from memory; typing an exact token count it did not measure; calling a FAIL a pass; presenting generated samples as real calls; inventing a log.

  • a tool's description wording, and which tool the model picks → THE TOOL WORDS
  • what a tool may do without asking (send, spend, delete) → THE TOOL MANNERS CARD
  • docs and instructions that no longer match the code → THE DRIFT CARD
  • the shape of the model's own answer to a downstream system → THE OUTPUT CONTRACT CARD
  • security sign-off on what a tool does → the organisation's own security lead

Reads definitions, not handler code; the platform's rules are dated and change: edit assets/api-rules.json when the docs do. It is an AI reading a text file: it can be wrong, so check what matters against your own records and the source.

What’s in the buy.

  • CARD.md — the whole card: its boot, law, method, machine, seals, refusals and hand-offs, ledger, score and what it carries · SKILL.md — the door your AI reads first · START-HERE.md — the first five minutes, for you
  • FORMATS.md + LINT-RULES.md + SOURCES.md + THE-METHOD.md — in references/, in the card's own voice
  • scripts/toolschema.py — the machine: lint · samples · calls · rules; see NEEDS below; selftest 28/28
  • WITNESS.md — the run on a realistic case as printed, and the trigger test on Haiku, Sonnet and Opus · SELFTEST.md — the machine's own test, as run at the cut · AUDIT.md, the twelve checks · MANIFEST.md, every file hashed
  • tests/evals.json — the cases it must take, hand off and refuse
  • MY-LEDGER.md — the card's memory, on your own machine · TIN.md, the nine lines on the tin · LICENSE-NOTE.md · HOSTS.md, where it runs
  • system/short-prompt.md and system/system-prompt.md — the doors for any AI without skills

PROOF · SELFTEST 28/28 · WITNESSED ON A RUN · TRIGGER TEST 31 OF 48 ON ITS OWN PROMPTS · HAIKU 3/16 · SONNET 12/16 · OPUS 16/16 · 0 WRONG PICKS · EDITION 1 · PUNCH CDA19DC0435DD9427A3A6805

ON EVERY DOOR · A CARD FOR YOUR AI, A FILE FOR YOUR COMPUTER

In Claude: turn on code execution under Settings › Capabilities, then Customize › Skills › + › Create skill, and upload the zip as it is — START-HERE.md in the box walks you through it, and tells you how to keep the ledger. In ChatGPT, Gemini and the rest: a Project, a GPT or a Gem with the card’s files attached and the short door in the box pasted as its instructions. The words run anywhere an AI reads Markdown; the machines run wherever the host runs Python. Witnessed in Claude only. The host marks →

Take it.

Nº 965 — LAUNCHING SOON

Sold as is under the term printed. A card instructs an AI you operate; results depend on your model, your files and your judgement. Not medical, legal, tax or financial advice, never the person’s boss, and not a licence to practise. The terms →

ONE PAYMENT · NOTHING RENEWS ITSELF

OFFLINE · ONE LICENCE · PUNCH-CHECKABLE · THE STANDARD

One payment. The file is yours to keep and keeps working at its edition; new editions issued in the year after you buy reach you by email as replacement files. Tax is added at checkout where it applies. Nothing auto-renews.

One email when it is on sale, from the studio; nothing else, ever.

A TERM, NOT A SUBSCRIPTION: NOTHING RENEWS ITSELF AND NOBODY IS CHARGED AGAIN. WHEN A TERM ENDS THE FILES STAY ON YOUR COMPUTER AND STAY READABLE — FREEZE, NOT LOSS.

THE MACHINE · IN THE OPEN · FROM THE CARD’S OWN WITNESS.MD AND SELFTEST.MD

toolschema.py, every command showing its working.

A small Python program. Your AI runs it; you can too. The blocks below are pasted from the card’s own record, as printed.

lintevery tool and parameter against the rules; exit 1 on any ERROR
samplesvalid and invalid inputs for each tool's handler (JSONL)
callslogged tool calls checked against the schemas; exit 1 when any fails
rulesthe platform facts the lint uses, with their sources and dates
selftest28 checks that prove the machine; it must print 28/28
python3 scripts/toolschema.py lint tools.json
TOOL SCHEMA LINT · tools.json · 8 tools · rules as read 2026-10-12

issue-refund
  ERROR S2   /tools/1/input_schema/properties/amount/type
        "float" is not a JSON Schema type
        fix: use number
  ERROR S3   /tools/1/input_schema/required
        'reason' is required but not in properties: the model gets no type or description for it
        fix: add 'reason' to properties, or drop it from required
  WARN  S6   /tools/1/input_schema/properties/currency
        an open string where an enum belongs: the description lists USD, EUR, GBP
        fix: add "enum": ["USD", "EUR", "GBP"]
update shipping address
  ERROR T1   /tools/2/name
        the name breaks the API's naming rule ^[a-zA-Z0-9_-]{1,128}$ (holds space)
        fix: rename it, for example update_shipping_address
search_kb
  WARN  S8   /tools/3/input_schema/properties/tags
        an array with no items schema: any items pass
        fix: say what each item is with "items"
  NOTE  S9   /tools/3/input_schema/properties/filters
        a free-form object: the handler receives whatever arrives
        fix: list its properties, or say in the description what it holds
escalate_ticket
  ERROR S12  /tools/4/input_examples/1
        example 2 fails its own schema (the docs: an invalid example returns a 400 error): /priority "urgent" is not one of ["low", "medium", "high", "High"]
        fix: fix the example or the schema
  NOTE  S7   /tools/4/input_schema/properties/priority/enum
        values that differ only in case: ["high", "High"]
        fix: keep one spelling; compare case-insensitively in the handler
send_email
  ERROR X1   /tools/5/input_schema/properties/body/maxLength
        strict mode does not support maxLength (structured outputs, JSON Schema limitations)
        fix: drop it, say the bound in the description, and check it in the handler
  WARN  X2   /tools/5/input_schema
        an object without additionalProperties: false; the docs say it must be set to false for objects
        fix: add "additionalProperties": false
create_ticket
  ERROR T3   /tools/6/parameters
        the schema sits under 'parameters'; the Messages API reads input_schema
        fix: rename the key to input_schema
get_customer
  WARN  T4   /tools/7/description
        the tool has no description (the API reference: optional, but strongly recommended)
        fix: say what it does, when to use it and when not; the wording is THE TOOL WORDS' job
  WARN  S5   /tools/7/input_schema/properties/customer_id
        the parameter 'customer_id' has no description
        fix: say what it means, its format and an example value

SIZE · characters of each definition as sent (compact JSON), tokens estimated at 4 characters per token
  lookup_order                         357 chars  ~90 tokens
  issue-refund                         450 chars  ~113 tokens
  update shipping address              534 chars  ~134 tokens
  search_kb                            388 chars  ~97 tokens
  escalate_ticket                      577 chars  ~145 tokens
  send_email                           436 chars  ~109 tokens
  create_ticket                        299 chars  ~75 tokens
  get_customer                         215 chars  ~54 tokens
  all tools                           3256 chars  ~814 tokens

[… 6 more lines, trimmed here]
python3 scripts/toolschema.py lint tools-fixed.json | tail -6
STRICT · 1 tool checked as strict · optional parameters 0 of 24 · union-type parameters 0 of 16 · strict tools 1 of 20

VERDICT · PASS · 0 ERROR · 0 WARN · 0 NOTE
FORMULA · ERROR = the API refuses it, or the handler cannot rely on the field; WARN = likely to cost a malformed call; NOTE = worth a look. Any ERROR fails.
SOURCE · the rules as read 2026-10-12 · the name rule: platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools · strict mode: platform.claude.com/docs/en/build-with-claude/structured-outputs (JSON Schema limitations) · the size and nesting thresholds are house heuristics.
LIMIT · it reads the definitions, not the handler's code; the enum hints and size thresholds are judgement, marked as such; Python's re stands in for the platform's regex engine; count tokens exactly with the API's token counting endpoint.
THE SELFTEST, AS PRINTED
PASS a sound tool lints with no ERROR and no WARN
PASS a name with spaces breaks the naming rule, with a fix offered
PASS a name of 128 characters passes and 129 breaks the rule as read
PASS two tools with one name are an ERROR
PASS a schema under inputSchema is caught and the key named
PASS a required field missing from properties is an ERROR naming it
PASS type 'float' is an ERROR with 'number' offered
PASS a parameter with no type is a WARN; one with no description is a WARN
PASS an open string listing 'One of USD, EUR or GBP' is flagged with the enum to add
PASS an array with no items is a WARN
PASS an input example that fails its own schema is an ERROR (the API answers 400), the good one passes
PASS impossible bounds and an unresolved $ref are ERRORs
PASS strict mode: minimum and maxLength are refused, a lookaround is refused, additionalProperties true is refused
PASS strict limits as read: 21 strict tools and 25 optional parameters are ERRORs
PASS a recursive schema is refused in strict mode
PASS an oversized definition is a WARN with its characters and estimated tokens
PASS samples: every accept passes the schema and every reject fails it, nothing skipped
PASS samples: the minimal input holds only the required fields
PASS samples: the pattern ^[A-Z]{3}-\d{4}$ gets a matching value
PASS samples: an enum gets a value not listed and a value that differs only in case
PASS calls: a good call passes; a wrong type, an enum case slip and an unknown tool are caught and grouped
PASS the validator: true is not 1, 1.0 is an integer, a pattern searches unanchored
PASS the validator: anyOf, oneOf, allOf, not and $defs refs
PASS the validator: dates and emails are checked as formats
PASS the same tools give the same report, byte for byte
PASS the command line: lint exits 0 on a sound file and 1 on an ERROR; --help shows usage; samples writes its file
PASS assets/api-rules.json matches the rules built into this machine
PASS nothing in this machine opens a network connection
selftest 28/28

THE TRIGGER TEST. The card's line was tried on Haiku, Sonnet and Opus beside 14 neighbouring skills, in a clean environment: 31/48 on its own prompts (Haiku 3/16 · Sonnet 12/16 · Opus 16/16), 0 wrong picks; no skill (answered directly) 17.

THE RUNS ARE PASTED FROM THE CARD’S OWN RECORD AS PRINTED. THE CASES ARE THE STUDIO’S OWN EXAMPLES (EXAMPLE CO IS FICTION); NO PRIVATE PERSON IS NAMED.

QUESTIONS AT THE TABLE

Asked before the wire.

What does it need from me?

Python 3; a tools file in the Messages API format.

Does it send anything anywhere?

Its machine reads what you point it at, and HOSTS.md says what it needs; python 3; a tools file in the Messages API format. The words run wherever an AI reads Markdown.

What is on the record?

The selftest (28/28), a run on a realistic case with every command and verdict pasted into WITNESS.md as printed (Example Co's eight-tool support agent linted (6 ERROR, then PASS), its refund handler given 22 checked inputs, a week of calls checked (4 of 7 malformed); 41 of 48 in the trigger test after the rewrite); and the trigger test, the card's line tried on Haiku, Sonnet and Opus beside 14 neighbouring skills: 31/48 on its own prompts, 0 wrong picks; the twelve-check audit (AUDIT.md). The punch on the face is the SHA-256 of SKILL.md, so a downloaded copy can be checked against this room.

Can it be wrong?

Yes — it is an AI reading a text file. Reads definitions, not handler code; the platform's rules are dated and change: edit assets/api-rules.json when the docs do.

What will it never do?

It refuses answering the naming rule or strict-mode limits from memory; typing an exact token count it did not measure; calling a FAIL a pass; presenting generated samples as real calls; inventing a log.

Who may use it?

One person, any number of their own AIs and computers; a team needs a company licence.

← THE INSTRUMENTS · THE FLOOR →

AT YOUR ELBOW, NEVER THE BOSS · NOT LEGAL, MEDICAL, TAX OR FINANCIAL ADVICE · NOT A PAYMENT CARD · © 2026 LUND STUDIO LLC

PAY BYAmerican Express Apple Pay Diners ClubDiscoverGoogle Pay Mastercard PayPalShop Pay Visa
CART · 0