← Patent Desk / API
Get a token

Driving Patent Desk over HTTP

Everything the page does, you can do from a script. One endpoint does the work; the rest is authentication and polling. The app takes one invention disclosure — prose describing something built or conceived — and, where you have one, a numbered claim set over that same disclosure, plus a task field naming which of four jobs to run over the material. It returns a single JSON envelope.

Base URL

https://api.skillsafe.ai/v1/app-api

The only headers on any call are Authorization: Bearer <token> and Content-Type: application/json — plus Idempotency-Key on /run and /run-stream. There is no slug header. The app slug is named in exactly one place: the JSON body of POST /guest, as {"slug":"patent-desk"}. Get a token from the token page without opening a developer console.

The response envelope

Every endpoint returns the same wrapper. Success carries data; failure carries error. Nothing returns a bare value, so a client can branch on the presence of error alone.

{"ok": true,  "data":  { ... }}
{"ok": false, "error": {"code": "VALIDATION_ERROR", "message": "...", "details": { ... }}}

Error codes

CodeHTTPWhat it meansWhat to do
UNAUTHORIZED401Missing, malformed or expired token.Mint a new one. Guest tokens expire; personal tokens outlive them.
FORBIDDEN403The token is valid but not for this app.Mint the token against this app: POST /guest with {"slug":"patent-desk"}.
VALIDATION_ERROR400The input did not match the app's shape.Read error.details; it names the offending field.
PAYMENT_REQUIRED402Balance below the run's minimum.Call /estimate first and compare against /me.
RATE_LIMITED429Too many requests.Back off and retry; never tight-loop.
JOB_FAILED200The job reached a terminal failed state.Returned inside a job payload, not as an HTTP error. Check status.

The task field comes first

Patent Desk is a four-lane app. Every run must name its lane in task, because all four lanes share one system prompt and one model and are routed by that field alone. The contract is to produce that lane only and never a blend of two. If task is missing or is not one of the four ids, the model picks the closest lane, produces that lane's contract in full, and says so by setting lane to what it chose plus lane_inferred to true — a fallback for a malformed request, not a feature to rely on. Send the lane explicitly.

taskWhat it doesExtra inputartifact.kind
disclosureReads the disclosure and says whether it can support a patent application yet: elements, novelty candidates, statutory class, eligibility risk, 112(a) gaps, questions for the inventor.none
priorartBuilds the prior-art search to run before drafting: classifications, a concept matrix, queries, a protocol and knockout criteria. Produces the search, never its results.markdown
claimsDrafts the claim set the disclosure supports, or revises a draft supplied in claims_text.claims_textclaims
review112Reviews a pasted claim set against 35 U.S.C. 112 — definiteness, antecedent basis, dependency, support — and rewrites the defective claims.claims_textclaims

claims_text is required by review112 and optional on claims, where it is an existing draft to revise rather than replace. The natural order through the app is disclosurepriorartclaimsreview112, and every response names what it thinks comes next in next_lane.

Input fields

FieldTypeRequiredNotes
taskstringyesOne of the four lane ids above.
disclosurestringyesThe invention disclosure itself — the one work object every lane operates on. Prose, possibly with headings, figure references and reference numerals.
claims_textstringreview112 onlyThe numbered claim set, verbatim. Optional elsewhere; on claims it is a draft to revise, keeping the user's numbering where possible.
jurisdictionstringnoDefaults to US. Only US practice is in scope; name another office and the model applies US practice, says so in assumptions and names the one difference that matters most.
contextstringnoFree-text notes: what you think is new, what a competitor ships, what has already been published or sold, who the audience is. The priorart lane uses a named competitor or assignee here to build one of its four queries.
prescanobjectno{flags, resources} — deterministic facts from the in-browser scanner that the model must reconcile. See below.
clip_notestringnoSend only when the input was too long to transmit whole; it names what was cut. The page clips a disclosure from the middle, keeping the head and the tail, and clips a claim set on whole-claim boundaries, dropping claims from the end. A clipped input overrides a lane's "artifact is required": the model returns artifact.kind: "none" and posture: "blocked" rather than inventing the part it was not shown.
retry_notestringnoSent only on an automatic re-ask after a malformed reply. It quotes the parse error and restates the contract; the model answers the same lane on the same input and returns only the JSON object. Reuse the idempotency key with the attempt number appended so a retry cannot double-bill.

The output envelope

All four lanes return exactly the same outer object. Only body is per-lane. The reply is one JSON object and nothing else — no prose before it and no code fence around it — and it arrives as a string in data.output.output, so you parse it yourself.

{
  "lane": "review112",
  "lane_inferred": false,
  "invention": "a short noun phrase naming the invention, or \"unknown\"",
  "title": "short human title for this run, max 70 chars",
  "posture": "filing-ready | needs-work | blocked",
  "verdict": "one sentence naming the single thing that decides the posture",
  "statutory_classes": ["method", "apparatus"],
  "summary": "3-6 sentences a drafter could paste into a file note",
  "assumptions": ["..."],
  "open_questions": ["..."],
  "findings": [
    {"id": "PD-001", "title": "short imperative title",
     "severity": "critical | high | medium | low",
     "area": "eligibility | novelty | claim-scope | definiteness | antecedent-basis | dependency | support | enablement | drafting | search | formalities",
     "claim_no": 3, "term": "the memory",
     "evidence": "the exact text from the input",
     "why": "what goes wrong, naming the provision - e.g. 35 U.S.C. 112(b)",
     "fix": "what to change, in one or two sentences",
     "fix_text": "the corrected claim language, or \"\""}
  ],
  "coverage_check": [
    {"flag_id": "PK-ANTECEDENT-BASIS", "status": "confirmed", "finding_id": "PD-001", "note": "..."}
  ],
  "artifact": {"kind": "none | claims | markdown", "filename": "claims.txt",
               "content": "the whole artifact, or \"\" when kind is none"},
  "next_lane": {"lane": "claims", "reason": "one sentence on why this is the next thing to do"},
  "body": { }
}

The prescan contract

The browser app runs a deterministic scanner over the disclosure and the claim set before every run and passes its findings in prescan.flags, each with a stable PK-* id. The model must return exactly one coverage_check entry per flag id sent, and none for ids that were not sent. That is what makes the free scanner able to hold the paid run accountable — anything unaccounted for is a defect you can detect programmatically:

sent    = {f["id"] for f in payload["prescan"]["flags"]}
covered = {c["flag_id"] for c in result["coverage_check"]}
assert sent == covered, f"unreconciled: {sent - covered}; invented: {covered - sent}"

# resources are context, not findings: they must NOT appear in coverage_check
res = {r["id"] for r in payload["prescan"]["resources"]}
assert not (covered & res), f"resource reconciled as a finding: {covered & res}"

status is one of three values. confirmed — the model agrees, and finding_id names the PD-* finding that carries it. set-aside — it is not a real problem on this material, and note says why. superseded — a different, larger finding covers it, and finding_id names that one. A flag is never silently dropped.

The flag shape

Each entry in prescan.flags is {id, label, severity, claim_no, claims, line, occurrences, terms, detail}.

KeyTypeWhat it holds
idstringThe stable rule id, PK-*. This is the value that must come back as a coverage_check.flag_id.
labelstringThe rule's one-line description, e.g. definite reference with no earlier indefinite antecedent.
severitystringcritical, high, medium or low. Flags arrive sorted by severity in that order.
claim_nonumberThe first claim the rule fired on, or 0 when the rule is about the disclosure or the set as a whole.
claimsarrayEvery claim number the rule fired on, in the order encountered. Empty when claim_no is 0.
linenumberThe first line the rule fired on, or 0.
occurrencesnumberHow many times the rule fired in total across the whole input.
termsarrayUp to twelve distinct offending terms collected across every occurrence — the relative terms, the unsupported claim terms, the definite references with no antecedent.
detailstringFree text from the rule when it has a countable fact to add, e.g. 430 words, 4 independent claims, 312 words. Empty string otherwise.

Flags are deduplicated by rule id before they are sent. One rule firing on six claims becomes one flag: claim_no is the first of them, claims lists all six, occurrences is 6, and terms accumulates across all six. One coverage_check entry still covers the whole group — but an occurrences of 6 means six places need the same change, and the contract forbids the model implying a single site when the count says otherwise.

Where the model and the scanner disagree on a countable fact — how many claims there are, which claim a term appears in, whether a numeral is present — the scanner is right, because it is deterministic and the model is not. Where they disagree about whether the flagged text is actually a problem, the model may say so; that is what set-aside is for.

prescan.resources is context, not findings

prescan.resources is a separate array of {id, label} entries stating what the scanner counted, not what it objects to: words of disclosure, which sections have headings, which figures are referenced, how many distinct reference numerals, how many claims of each kind and the maximum chain depth, which statutory classes are claimed, and which technical-effect vocabulary is present. They need no coverage_check entry, they are not problems, and the model is instructed not to manufacture a finding merely to mention one.

"resources": [
  {"id": "PR-DISCLOSURE-WORDS", "label": "612 words of disclosure"},
  {"id": "PR-SECTIONS",  "label": "sections with headings: technical field, background, summary, drawings, detailed description"},
  {"id": "PR-FIGURES",   "label": "figures referenced: FIG. 1, FIG. 2, FIG. 4"},
  {"id": "PR-NUMERALS",  "label": "5 distinct reference numerals in the text"},
  {"id": "PR-CLAIM-COUNTS", "label": "10 claims (3 independent, 7 dependent), max chain depth 2"},
  {"id": "PR-CLASSES",   "label": "statutory classes claimed: method, apparatus, crm"},
  {"id": "PR-TECHNICAL", "label": "technical-effect vocabulary present: threshold, filter, sensor"}
]

Flags are filtered to the lane being run

Every rule declares which lanes it belongs to, and the scanner sends only the rules for the lane you are about to run. The same disclosure and the same claim set therefore produce a different flag set in each lane — a real defect that is out of lane is simply not sent, so the model is never asked to reconcile something it is not being paid to look at. Compute prescan per lane; do not cache one lane's flags and resend them on another.

For the disclosure and claim set bundled with the app as the worked example, the counts come out:

LaneFlags sentWhich rules can reach this lane
disclosure4The six disclosure-only rules, plus PK-TERM-NOT-IN-SPEC, PK-DISCLOSURE-THIN, PK-VAGUE-ENABLEMENT and PK-ELIGIBILITY-SIGNAL.
priorart1Only three: PK-DISCLOSURE-THIN, PK-VAGUE-ENABLEMENT, PK-ELIGIBILITY-SIGNAL. This lane is about the technology, not the drafting.
claims10The widest set: every claim-drafting rule plus the four disclosure-quality rules.
review1129Every claim rule, including PK-NO-CLAIMS, which reaches this lane and no other.

Those four numbers are one illustration, not a constant. What is constant is the shape: run the same material through two lanes and expect two different coverage_check arrays.

The rules

Thirty-one rules, each with a fixed id and a fixed severity. d is disclosure, p is priorart, c is claims, r is review112.

Rule idSeverityLanesWhat it fires on
PK-NO-CLAIMScriticalrNo numbered claims were found in the claim text. Claims are recognised by a leading number followed by a full stop or a bracket.
PK-NO-INDEPENDENTcriticalr cEvery claim refers to another claim, so the set has no root.
PK-NUMBERING-GAPhighr cClaim numbers are not consecutive from 1 — a 37 CFR 1.126 formalities objection that can break dependencies counting on the order.
PK-DUPLICATE-NUMBERhighr cThe same claim number appears more than once, so any dependency on it is ambiguous.
PK-FORWARD-DEPcriticalr cA claim depends on a later-numbered claim, or on itself. 37 CFR 1.75(c) requires a preceding claim.
PK-CIRCULAR-DEPcriticalr cThe dependency references form a cycle, so no claim in the loop has a definable scope.
PK-MISSING-DEP-TARGETcriticalr cA claim depends on a claim number that does not exist.
PK-MULTIPLE-DEPENDENTmediumr cA claim refers to more than one claim. US-permissible only in the alternative, and it carries a surcharge.
PK-MULTI-SENTENCEhighr cThe claim contains more than one sentence. US practice is one claim, one sentence (MPEP 608.01(m)).
PK-NO-TRANSITIONhighr cNo recognisable transition phrase between preamble and body, so open or closed scope is argued rather than written.
PK-CLOSED-TRANSITIONlowr cconsisting of — a closed transition read strictly. Confirm the narrowness is deliberate.
PK-ANTECEDENT-BASIShighr cA definite reference with no earlier indefinite antecedent in this claim or an ancestor. 112(b), and the most common claim rejection there is.
PK-RELATIVE-TERMmediumr cA relative or approximating term of degree — substantially, about, suitable — with no yardstick in the specification.
PK-MEANS-PLUS-FUNCTIONmediumr cA means-plus-function or nonce-word limitation, construed under 112(f) to the disclosed structure and its equivalents.
PK-REFERENCE-NUMERALlowr cA reference numeral inside a claim. Permitted only in parentheses and not limiting.
PK-MIXED-CLASShighr cOne claim mixes statutory classes — method steps and apparatus structure — which is indefinite under IPXL.
PK-OMNIBUScriticalr cAn omnibus claim: as described herein or as shown in the drawings. Improper in the US (MPEP 1302.04(b)).
PK-AND-ORlowr cand/or in a claim; frequently objected to as indefinite.
PK-LONG-CLAIMlowr cA claim over 250 words. Not improper, but hard to construe and easy to design around.
PK-DEEP-CHAINlowr cA dependency chain more than four claims deep; scope narrows faster than it reads.
PK-THIN-DEPENDENTmediumr cA dependent claim adds almost nothing beyond its reference — a 112(d) rejection.
PK-EXCESS-INDEPENDENTmediumr cMore than three independent claims; an excess-independent-claim fee applies.
PK-EXCESS-TOTALlowr cMore than twenty claims in total; an excess-claim fee applies.
PK-TERM-NOT-IN-SPEChighr c dA claim term appears nowhere in the disclosure. 112(a) written description, and adding it later is new matter.
PK-DISCLOSURE-THINhighd p cThe disclosure is very short. Enablement is judged on what the specification teaches, and the gap cannot be filled after filing.
PK-MISSING-SECTIONmediumdA standard specification section has no heading (MPEP 608.01(a)); usually it also means missing content.
PK-NO-FIGURESmediumdThe disclosure references no figures, where 37 CFR 1.81 requires a drawing if one is necessary to understand the invention.
PK-FIGURE-GAPlowdFigure numbers are referenced with a gap — either a missing drawing or a stale reference.
PK-NUMERAL-CONFLICTmediumdOne reference numeral is attached to two different element names, making the specification ambiguous.
PK-VAGUE-ENABLEMENTmediumd p cThe disclosure leans on any suitable or known in the art, which is where enablement quietly goes missing.
PK-ELIGIBILITY-SIGNALmediumd p cAbstract-idea vocabulary with no technical-improvement language — the shape that draws a 101 rejection. Informational, not a verdict.

Renaming a flag id breaks the reconciliation contract in both directions: the model has no entry to return and your assertion has nothing to match. Treat the PK-* ids as an interface.

You may send an empty prescan, or omit it entirely. The lane still runs; it simply has fewer deterministic facts to ground itself in, coverage_check comes back as an empty array, and nothing checks the model's counting for you.

1. A tiny client

A few lines of setup that every later step reuses: the base URL, the bearer token, and a JSON post that raises on the error branch of the envelope. Two headers, no more — Authorization and Content-Type. The slug constant is here only because step 2 needs it in a request body; it never becomes a header. Replace the "YOUR_TOKEN" placeholder by reading the token from wherever your program keeps secrets rather than committing it.

2. Get a token

A guest token is minted on demand and is enough for /me and /estimate. Running a lane is metered, so it needs a personal token — sign in at the token page and copy it from there. This is the one and only call that names the app: {"slug": "patent-desk"} in the JSON body. Every POST /guest mints a new guest identity, so reuse one token across a session rather than minting per request.

3. Check who you are and what you can spend

GET /me is free and tells you the subject type and the credit balance. Compare that balance against the estimate in the next step before you run anything — a 402 after submitting a disclosure is a failure of the client, not of the user.

4. Price the run before you make it

POST /estimate is free, creates no job and charges nothing. It takes the same body the run will take — the input object itself, not wrapped in an input key — and returns the model, the markup and the two numbers that matter. hold_credits is the amount reserved against your balance, priced at the full output cap; the actual charge is usually far lower, so present it as reserved and never as the price. min_credits is the floor you must be able to cover for the run to be accepted at all.

The hold differs per lane. The four lanes have different output caps — a claims or review112 run that has to reproduce a whole claim set reserves considerably more than a disclosure read. Estimate the lane you are about to run, and re-estimate whenever task changes.

5. Run a lane and poll for the result

POST /run takes the input object as its body and returns a job_id immediately; poll GET /jobs/{job_id} until status is terminal (succeeded, failed or cancelled). The model's reply is a string at data.output.output, so parse it yourself.

Always send an Idempotency-Key, and derive it from (task, input, attempt). All three parts matter. Include task or the second lane over the same disclosure will collide with the first and hand you back the first lane's cached result. Include a hash of the input so editing a claim starts a new run. Include an attempt counter so a deliberate re-ask (a retry_note re-ask, say) is a new run while a transport-level retry of the same attempt reuses the key and cannot double-bill.

6. Stream it instead, for anything interactive

POST /run-stream is the same call with the same body over Server-Sent Events. Deltas arrive as they are generated, which is what the page uses to advance its progress stages while a claim set is being rewritten. The same Idempotency-Key rule applies. Accumulate the deltas and parse the JSON once the stream closes — a half-received envelope is not valid JSON and a claim rewritten halfway is worse than no claim.

7. One worked example per lane

All four requests below send the same disclosure — an acoustic-emission detector for incipient thermal runaway in a lithium-ion pack, the material the app ships as its free example — and differ in task, in whether they send claims_text, and in the lane-filtered prescan. The envelope is identical across all four; only body and artifact change. Arrays shown as ... follow the shapes documented above, abbreviated here to one representative entry.

task: "disclosure" — Read the intake

What the invention is, the elements it needs and how well each is described, the novelty candidates, the statutory posture, where 112(a) support is thin, and what to ask the inventor before anyone drafts. This is the only lane that emits no file.

Request

{
  "task": "disclosure",
  "disclosure": "<the invention disclosure>",
  "jurisdiction": "US",
  "context": "We think the new part is the current-steadiness gate, not the acoustic sensing itself.",
  "prescan": {
    "resources": [
      {"id": "PR-DISCLOSURE-WORDS", "label": "612 words of disclosure"},
      {"id": "PR-FIGURES", "label": "figures referenced: FIG. 1, FIG. 2, FIG. 4"}
    ],
    "flags": [
      {"id": "PK-NUMERAL-CONFLICT", "severity": "medium",
       "label": "one reference numeral is attached to two different element names",
       "claim_no": 0, "claims": [], "line": 41, "occurrences": 1,
       "terms": ["104"], "detail": "104: acoustic sensor, coolant pump"},
      {"id": "PK-VAGUE-ENABLEMENT", "severity": "medium",
       "label": "the disclosure leans on 'any suitable' or 'known in the art'",
       "claim_no": 0, "claims": [], "line": 40, "occurrences": 2,
       "terms": ["any suitable", "conventional means"], "detail": ""},
      {"id": "PK-FIGURE-GAP", "severity": "low",
       "label": "figure numbers are referenced with a gap",
       "claim_no": 0, "claims": [], "line": 33, "occurrences": 1,
       "terms": [], "detail": "FIG. 2 to FIG. 4"}
    ]
  }
}

Response data.output.output, parsed

{
  "lane": "disclosure",
  "lane_inferred": false,
  "invention": "acoustic-emission detection of incipient thermal runaway in a battery pack",
  "title": "Acoustic runaway detection - intake read",
  "posture": "needs-work",
  "verdict": "The invention is identifiable and arguably novel, but one numeral names two parts and the adhesive and filter design are left to \"any suitable\" means.",
  "statutory_classes": ["method", "apparatus"],
  "summary": "The disclosure describes a housing-mounted piezoelectric sensor whose 150-400 kHz burst rate is gated on steady pack current ...",
  "assumptions": ["US practice applied; no other jurisdiction was named."],
  "open_questions": ["What is the measured false-positive rate without the current-steadiness gate?"],
  "findings": [
    {"id": "PD-001", "title": "Give reference numeral 104 to one element only",
     "severity": "high", "area": "formalities", "claim_no": 0, "term": "104",
     "evidence": "An acoustic sensor 104 is bonded to the inner face of the pack housing 102",
     "why": "A numeral must name one element throughout; 37 CFR 1.84(p) and MPEP 608.01. Reusing 104 for the coolant pump makes every claim that leans on it ambiguous.",
     "fix": "Renumber the coolant pump, e.g. to 106, everywhere it appears.",
     "fix_text": ""}
  ],
  "coverage_check": [
    {"flag_id": "PK-NUMERAL-CONFLICT", "status": "confirmed", "finding_id": "PD-001", "note": ""},
    {"flag_id": "PK-VAGUE-ENABLEMENT", "status": "confirmed", "finding_id": "PD-002",
     "note": "Both sites need a worked example; the adhesive one is the weaker."},
    {"flag_id": "PK-FIGURE-GAP", "status": "confirmed", "finding_id": "PD-003", "note": ""}
  ],
  "artifact": {"kind": "none", "filename": "", "content": ""},
  "next_lane": {"lane": "priorart", "reason": "Acoustic emission monitoring of cells is a known field; the search must run before claim scope is chosen."},
  "body": {
    "inventive_concept": "Gating an acoustic burst-rate threshold on the pack current being steady, so gassing is distinguished from mechanical creak under a load step.",
    "problem_solved": "Surface thermistors detect runaway roughly ninety seconds too late to do anything but vent.",
    "elements": [
      {"name": "acoustic sensor", "role": "Hears 150-400 kHz emission bursts from every cell in the module.",
       "essential": true, "disclosed": "full",
       "evidence": "a piezoelectric element with a usable response from 100 kHz to 500 kHz"},
      {"name": "bonding adhesive", "role": "Couples the sensor to the housing.",
       "essential": true, "disclosed": "absent",
       "evidence": "bonded to the inner face of the pack housing 102 with any suitable adhesive"}
    ],
    "novel_features": [
      {"feature": "current-steadiness gate on the burst-rate threshold",
       "why_novel": "The applicant identifies this, not the acoustic sensing, as the new part.",
       "evidence": "while the pack current, measured by a shunt 110, has varied by less than two percent",
       "confidence": "medium"}
    ],
    "statutory_posture": {
      "classes": ["method", "apparatus"],
      "eligibility_risk": "low",
      "reason": "The claim reads on a physical sensor and a contactor actuation, not on a calculation alone.",
      "what_would_lower_it": "Keep the contactor-opening step in every independent claim."
    },
    "support_gaps": [
      {"requirement": "enablement", "gap": "No adhesive is named and no bond-line requirement is given.",
       "why_it_matters": "35 U.S.C. 112(a): acoustic coupling through the bond is what makes the sensor work at all.",
       "what_to_add": "One worked adhesive, its thickness and the coupling loss it gives."}
    ],
    "questions_for_inventor": ["Was the 150-400 kHz band chosen empirically, and over how many cell chemistries?"],
    "readiness": {"score_of_10": 6, "blockers": ["The adhesive and band-pass design are not enabled."], "ready_to_draft": false}
  }
}

task: "priorart" — Build the search

Classifications, a concept matrix, at least four queries each different in kind, a five-to-eight-step protocol ending in a step that records what was found, and the criteria by which a hit would knock out a claim element. This lane produces the search, never its results — the model has no search access on the run and will not name a patent number, a publication or a date as prior art. artifact.kind is markdown: a search log to fill in while working.

Request

{
  "task": "priorart",
  "disclosure": "<the invention disclosure>",
  "jurisdiction": "US",
  "context": "Competitor packs use surface thermistors only. Nothing published or sold yet.",
  "prescan": {
    "resources": [{"id": "PR-TECHNICAL", "label": "technical-effect vocabulary present: threshold, filter, sensor, band-pass"}],
    "flags": [
      {"id": "PK-VAGUE-ENABLEMENT", "severity": "medium",
       "label": "the disclosure leans on 'any suitable' or 'known in the art'",
       "claim_no": 0, "claims": [], "line": 40, "occurrences": 2,
       "terms": ["any suitable", "conventional means"], "detail": ""}
    ]
  }
}

Response data.output.output, parsed

{
  "lane": "priorart",
  "lane_inferred": false,
  "invention": "acoustic-emission detection of incipient thermal runaway in a battery pack",
  "title": "Acoustic runaway detection - search plan",
  "posture": "filing-ready",
  "verdict": "The technology classifies cleanly into battery-management and acoustic-emission testing, so the search is executable as written.",
  "statutory_classes": ["method", "apparatus"],
  "summary": "Four queries in two schemes, aimed at the intersection of acoustic emission sensing and battery safety cut-off ...",
  "assumptions": ["US practice applied."],
  "open_questions": ["Is there an internal disclosure date that fixes the cut-off for this search?"],
  "findings": [
    {"id": "PD-001", "title": "Search the current-steadiness gate separately",
     "severity": "high", "area": "search", "claim_no": 0, "term": "current-steadiness gate",
     "evidence": "the burst rate exceeds forty bursts per second while the pack current ... has varied by less than two percent",
     "why": "This is the applicant's identified point of novelty, and a single reference showing it with acoustic sensing would anticipate claim 1 under 102.",
     "fix": "Run Q3 before any drafting decision on claim 1's breadth.", "fix_text": ""}
  ],
  "coverage_check": [
    {"flag_id": "PK-VAGUE-ENABLEMENT", "status": "set-aside",
     "finding_id": "", "note": "Real, but an enablement matter the disclosure lane owns; it does not change what to search."}
  ],
  "artifact": {"kind": "markdown", "filename": "search-log.md",
               "content": "# Prior-art search log\n\n| Query | Engine | Date run | Hits | Kept | Why kept |\n|---|---|---|---|---|---|\n| Q1 | ... |\n"},
  "next_lane": {"lane": "claims", "reason": "Claim scope should be chosen after Q1-Q4 have been run."},
  "body": {
    "search_scope": {
      "technology": "acoustic emission monitoring of electrochemical cells for safety cut-off",
      "problem": "detecting internal gas generation before casing temperature rises",
      "solution": "band-limited burst counting gated on steady pack current",
      "field_of_search": "In scope: battery management, acoustic emission NDT, cell venting prediction. Out of scope: ultrasonic state-of-charge estimation by transit time."
    },
    "classifications": [
      {"scheme": "CPC", "code": "H01M 10/48",
       "definition": "Accumulators combined with arrangements for measuring, testing or indicating condition.",
       "why": "The monitoring system is combined with the pack itself.", "confidence": "high"},
      {"scheme": "CPC", "code": "G01N 29/14",
       "definition": "Investigating materials by detecting acoustic emission arising from the material itself.",
       "why": "Bursts originate in the cell, not from an injected pulse.", "confidence": "high"},
      {"scheme": "IPC", "code": "",
       "definition": "Battery thermal-runaway prediction by non-thermal sensing.",
       "why": "Described in words rather than by code: no IPC subclass is confidently known for the intersection.",
       "confidence": "low"}
    ],
    "concept_matrix": [
      {"concept": "acoustic emission", "synonyms": ["ultrasonic emission", "acoustic signature", "AE burst"],
       "narrower": ["piezoelectric burst count"], "broader": ["vibration sensing"], "must_appear": true},
      {"concept": "thermal runaway", "synonyms": ["cell venting", "exothermic excursion"],
       "narrower": ["incipient runaway"], "broader": ["battery fault"], "must_appear": true}
    ],
    "queries": [
      {"id": "Q1", "engine": "Google Patents",
       "query": "CPC=(H01M10/48) AND CPC=(G01N29/14)",
       "targets": "The classification intersection - anything already sitting in both subclasses.",
       "expected_noise": "Ultrasonic state-of-charge measurement, which is a transit-time method."},
      {"id": "Q3", "engine": "Espacenet",
       "query": "txt=(acoustic OR ultrasonic) AND txt=(\"burst rate\" OR \"emission rate\") AND txt=(current AND (steady OR stable OR quiescent))",
       "targets": "The current-steadiness gate specifically, which is the applicant's point of novelty.",
       "expected_noise": "Charger-side ripple measurement, which uses the same vocabulary."}
    ],
    "protocol": [
      {"step": 1, "name": "Classification sweep", "action": "Run Q1 and read titles and first claims only.",
       "stop_condition": "Every hit is triaged keep or discard, with a one-line reason."},
      {"step": 6, "name": "Record the search", "action": "Fill the search log with engine, date, hit count, references kept and why.",
       "stop_condition": "A colleague could re-run the search from the log alone."}
    ],
    "non_patent_sources": ["Journal of Power Sources, acoustic characterisation of Li-ion failure", "SAE J2464 abuse-testing procedure"],
    "knockout_criteria": [
      {"claim_element": "gating a burst-rate threshold on pack-current steadiness",
       "anticipated_if": "one reference shows acoustic burst counting, a threshold comparison and a current-steadiness condition together",
       "obvious_if": "one reference shows acoustic burst counting with a threshold and another shows current-steadiness gating of any battery fault signal, with a stated reason to combine",
       "fallback_position": "the adaptive threshold referenced to the quietest window since rest"}
    ],
    "limits": [
      "This plan was produced without running any search: no result here is a search result.",
      "Unpublished applications, up to eighteen months old, cannot be found by any of these queries.",
      "Non-English filings will be reached only through the classification queries."
    ]
  }
}

task: "claims" — Draft the set

The broadest claim the pasted material actually enables and describes, plus the ladder of narrower positions to retreat to: one broad independent claim in the primary class, dependents adding one limitation each, and a second or third independent claim in the other classes the disclosure supports. Send claims_text and it becomes a draft to revise instead, keeping your numbering where possible and explaining each change in that claim's rationale. artifact.content is the set as plain numbered text — the string the review lane consumes.

Request

{
  "task": "claims",
  "disclosure": "<the invention disclosure>",
  "jurisdiction": "US",
  "context": "Audience is our outside counsel, who will draft the real application.",
  "prescan": {
    "resources": [{"id": "PR-DISCLOSURE-WORDS", "label": "612 words of disclosure"}],
    "flags": [
      {"id": "PK-VAGUE-ENABLEMENT", "severity": "medium",
       "label": "the disclosure leans on 'any suitable' or 'known in the art'",
       "claim_no": 0, "claims": [], "line": 40, "occurrences": 2,
       "terms": ["any suitable", "conventional means"], "detail": ""}
    ]
  }
}

Response data.output.output, parsed

{
  "lane": "claims",
  "lane_inferred": false,
  "invention": "acoustic-emission detection of incipient thermal runaway in a battery pack",
  "title": "Acoustic runaway detection - claim set",
  "posture": "needs-work",
  "verdict": "A three-class set is supportable, but the adhesive is not enabled well enough to appear in any claim.",
  "statutory_classes": ["method", "apparatus", "crm"],
  "summary": "Claim 1 is the method: receive, band-pass, count in a sliding window, and open the contactor on a burst-rate threshold with the current steady ...",
  "assumptions": ["Three independent claims and twelve total, so no excess-claim fee applies."],
  "open_questions": ["Should the 150-400 kHz band appear in claim 1 or only in a dependent?"],
  "findings": [
    {"id": "PD-001", "title": "Leave the adhesive out of every claim",
     "severity": "medium", "area": "support", "claim_no": 0, "term": "any suitable adhesive",
     "evidence": "bonded to the inner face of the pack housing 102 with any suitable adhesive",
     "why": "35 U.S.C. 112(a): a limitation whose only description is \"any suitable\" is unsupported, and it would be the easiest term in the set to attack.",
     "fix": "Claim the coupling functionally - the sensor being acoustically coupled to the housing - and list the adhesive in not_claimed.",
     "fix_text": "an acoustic sensor acoustically coupled to a housing of the battery pack"}
  ],
  "coverage_check": [
    {"flag_id": "PK-VAGUE-ENABLEMENT", "status": "confirmed", "finding_id": "PD-001",
     "note": "Both occurrences bear on claim scope; the adhesive one is the one that changes the claim."}
  ],
  "artifact": {
    "kind": "claims",
    "filename": "claims.txt",
    "content": "1. A method for detecting incipient thermal runaway in a battery pack, the method comprising: receiving an acoustic signal from an acoustic sensor acoustically coupled to a housing of the battery pack; ...\n\n2. The method of claim 1, wherein the sliding window is ten seconds.\n\n3. ...\n"
  },
  "next_lane": {"lane": "review112", "reason": "Run the drafted set back through the 112 review before it goes to counsel."},
  "body": {
    "strategy": {
      "primary_class": "method",
      "coverage_theory": "The method claim reads on the pack maker operating the vehicle pack; the apparatus claim reads on the module supplier shipping the sensor and controller; the CRM claim reads on a firmware vendor shipping the detection code alone.",
      "breadth_ladder": "Claim 1 gives up the specific band and the specific threshold; claims 2-5 win back the ten-second window, the forty-burst threshold, the 150-400 kHz band and the adaptive threshold."
    },
    "claim_set": [
      {"num": 1, "type": "independent", "statutory_class": "method", "depends_on": 0,
       "text": "A method for detecting incipient thermal runaway in a battery pack, the method comprising: receiving an acoustic signal from an acoustic sensor acoustically coupled to a housing of the battery pack; band-pass filtering the acoustic signal to produce a filtered signal; counting, in a sliding window, threshold crossings of the filtered signal to produce a burst rate; and opening a contactor of the battery pack when the burst rate exceeds a burst-rate threshold and a pack current varies by less than a predetermined fraction over the sliding window.",
       "rationale": "The broadest form the disclosure supports; the current-steadiness condition is recited because it is the identified point of novelty.",
       "support": "when the burst rate exceeds forty bursts per second while the pack current ... has varied by less than two percent over the same window"},
      {"num": 2, "type": "dependent", "statutory_class": "method", "depends_on": 1,
       "text": "The method of claim 1, wherein the sliding window is ten seconds.",
       "rationale": "First fallback: the one window length actually bench-tested.",
       "support": "maintains a sliding ten-second window of the burst count"}
    ],
    "elements_mapped": [
      {"element": "acoustic sensor", "claim_nos": [1, 6, 9],
       "disclosure_support": "An acoustic sensor 104 is bonded to the inner face of the pack housing 102"},
      {"element": "current shunt", "claim_nos": [1, 7],
       "disclosure_support": "while the pack current, measured by a shunt 110, has varied by less than two percent"}
    ],
    "fallbacks": [
      {"if_rejected": "claim 1 over acoustic emission monitoring with a fixed threshold",
       "narrow_to": "the adaptive threshold referenced to the quietest window since the pack was last at rest",
       "from_claim": 5}
    ],
    "counts": {"independent": 3, "dependent": 9, "total": 12},
    "not_claimed": ["The bonding adhesive: described only as \"any suitable\", so claiming it would invite a 112(a) rejection."]
  }
}

task: "review112" — Review against 35 U.S.C. 112

The lane the app is named for. Claim by claim in numerical order: is every term definite under 112(b), does every definite reference have antecedent basis, is the claim one sentence in one statutory class, does a dependent claim further limit its parent as 112(d) requires, is every claimed term supported under 112(a). Defective claims are rewritten, not merely objected to. claims_text is required: without it the lane returns posture: "blocked" and empty body arrays rather than guessing at a claim set.

Request

{
  "task": "review112",
  "disclosure": "<the invention disclosure>",
  "claims_text": "1. A method for detecting incipient thermal runaway in a battery pack, the method comprising: ...",
  "jurisdiction": "US",
  "prescan": {
    "resources": [
      {"id": "PR-CLAIM-COUNTS", "label": "10 claims (3 independent, 7 dependent), max chain depth 2"},
      {"id": "PR-CLASSES", "label": "statutory classes claimed: method, apparatus, crm"}
    ],
    "flags": [
      {"id": "PK-FORWARD-DEP", "severity": "critical",
       "label": "a claim depends on a later-numbered claim, or on itself",
       "claim_no": 4, "claims": [4], "line": 14, "occurrences": 1, "terms": [], "detail": "4 -> 5"},
      {"id": "PK-ANTECEDENT-BASIS", "severity": "high",
       "label": "definite reference with no earlier indefinite antecedent",
       "claim_no": 6, "claims": [6], "line": 20, "occurrences": 1,
       "terms": ["the shunt"], "detail": ""},
      {"id": "PK-MIXED-CLASS", "severity": "high",
       "label": "one claim mixes statutory classes - method steps and apparatus structure",
       "claim_no": 9, "claims": [9], "line": 27, "occurrences": 1,
       "terms": ["further comprising the steps of"], "detail": ""},
      {"id": "PK-THIN-DEPENDENT", "severity": "medium",
       "label": "dependent claim adds almost nothing beyond its reference",
       "claim_no": 8, "claims": [8], "line": 25, "occurrences": 1, "terms": [], "detail": ""},
      {"id": "PK-RELATIVE-TERM", "severity": "medium",
       "label": "relative or approximating term of degree",
       "claim_no": 1, "claims": [1], "line": 3, "occurrences": 1,
       "terms": ["substantially"], "detail": ""}
    ]
  }
}

Response data.output.output, parsed

{
  "lane": "review112",
  "lane_inferred": false,
  "invention": "acoustic-emission detection of incipient thermal runaway in a battery pack",
  "title": "Acoustic runaway detection - 112 review",
  "posture": "needs-work",
  "verdict": "Claim 4 depends forward on claim 5, which is fatal as filed, and claim 9 mixes an apparatus with method steps.",
  "statutory_classes": ["method", "apparatus", "crm"],
  "summary": "Ten claims reviewed. Two are unfixable as written without amendment - the forward dependency in claim 4 and the mixed class in claim 9 ...",
  "assumptions": ["US practice applied; jurisdiction was US."],
  "open_questions": ["Is \"substantially steady\" in claim 1 meant to be the two percent given in the specification?"],
  "findings": [
    {"id": "PD-001", "title": "Redirect claim 4 to claim 1",
     "severity": "critical", "area": "dependency", "claim_no": 4, "term": "claim 5",
     "evidence": "4. The method of claim 5, wherein the acoustic sensor is a piezoelectric element.",
     "why": "37 CFR 1.75(c) requires a dependent claim to refer to a preceding claim; a forward reference is objected to on sight.",
     "fix": "Depend claim 4 on claim 1, or renumber so the referenced claim precedes it.",
     "fix_text": "The method of claim 1, wherein the acoustic sensor is a piezoelectric element."},
    {"id": "PD-002", "title": "Give \"the shunt\" an antecedent",
     "severity": "high", "area": "antecedent-basis", "claim_no": 6, "term": "the shunt",
     "evidence": "6. The method of claim 1, wherein the pack current is measured by the shunt.",
     "why": "35 U.S.C. 112(b): no earlier claim introduces \"a shunt\", so the definite reference has no antecedent basis.",
     "fix": "Introduce it indefinitely in this claim.",
     "fix_text": "The method of claim 1, wherein the pack current is measured by a shunt coupled in series with the battery pack."}
  ],
  "coverage_check": [
    {"flag_id": "PK-FORWARD-DEP", "status": "confirmed", "finding_id": "PD-001", "note": ""},
    {"flag_id": "PK-ANTECEDENT-BASIS", "status": "confirmed", "finding_id": "PD-002", "note": ""},
    {"flag_id": "PK-MIXED-CLASS", "status": "confirmed", "finding_id": "PD-003", "note": ""},
    {"flag_id": "PK-THIN-DEPENDENT", "status": "confirmed", "finding_id": "PD-004",
     "note": "Claim 8 recites the parent and nothing else; 112(d)."},
    {"flag_id": "PK-RELATIVE-TERM", "status": "set-aside", "finding_id": "",
     "note": "\"Substantially steady\" has a yardstick in the specification - two percent over the window - so it is definite as supported. Reciting the number would be narrower but is not required."}
  ],
  "artifact": {
    "kind": "claims",
    "filename": "claims-reviewed.txt",
    "content": "1. A method for detecting incipient thermal runaway in a battery pack, the method comprising: ...\n\n4. The method of claim 1, wherein the acoustic sensor is a piezoelectric element.\n\n...\n"
  },
  "next_lane": {"lane": "claims", "reason": "Claim 9 needs redrafting as an apparatus claim rather than patching."},
  "body": {
    "claim_reviews": [
      {"num": 1, "type": "independent", "depends_on": 0, "statutory_class": "method",
       "definiteness": "clear", "one_sentence": true, "transition": "comprising",
       "scope_note": "Covers operating any pack that opens a contactor on a gated acoustic burst rate.",
       "verdict": "clean"},
      {"num": 4, "type": "dependent", "depends_on": 5, "statutory_class": "method",
       "definiteness": "questionable", "one_sentence": true, "transition": "none",
       "scope_note": "Would narrow claim 1 to a piezoelectric sensor, if its dependency were proper.",
       "verdict": "depends forward on claim 5"},
      {"num": 9, "type": "independent", "depends_on": 0, "statutory_class": "mixed",
       "definiteness": "indefinite", "one_sentence": true, "transition": "comprising",
       "scope_note": "Recites an apparatus and then a measuring step, so infringement is undecidable.",
       "verdict": "mixes statutory classes"}
    ],
    "structure": {
      "independent": 3, "dependent": 7, "total": 10, "max_depth": 2,
      "multiple_dependent": [7],
      "improper_dependencies": [{"claim_no": 4, "refers_to": 5, "problem": "forward reference"}],
      "fee_thresholds": ["multiple-dependent claim surcharge for claim 7"]
    },
    "s112b": [
      {"claim_no": 6, "term": "the shunt", "issue": "antecedent-basis", "severity": "high",
       "why": "35 U.S.C. 112(b): no earlier claim introduces a shunt.", "fix": "Introduce it indefinitely in claim 6."},
      {"claim_no": 9, "term": "further comprising the steps of", "issue": "mixed-class", "severity": "high",
       "why": "35 U.S.C. 112(b) under IPXL: an apparatus claim reciting a method step leaves infringement undecidable.",
       "fix": "Recite the measurement as a configured capability of the controller."}
    ],
    "s112a": [
      {"claim_no": 9, "term": "means for receiving an acoustic signal", "in_disclosure": true,
       "note": "The specification discloses a piezoelectric element as the corresponding structure, which is what 112(f) construction will read the means to cover."}
    ],
    "s112d": [
      {"claim_no": 8, "problem": "adds no limitation beyond claim 1",
       "fix": "Cancel it, or add the adaptive-threshold limitation from the specification."}
    ],
    "rewrites": [
      {"claim_no": 4, "before": "The method of claim 5, wherein the acoustic sensor is a piezoelectric element.",
       "after": "The method of claim 1, wherein the acoustic sensor is a piezoelectric element.",
       "what_changed": "dependency redirected to a preceding claim"},
      {"claim_no": 9, "before": "... and further comprising the steps of measuring the pack current.",
       "after": "... wherein the controller is further configured to measure the pack current.",
       "what_changed": "method step converted to a configured capability, so the claim is wholly an apparatus"}
    ],
    "clean_claims": [1, 2, 3, 5, 10]
  }
}

The pipeline

The claims lane returns artifact.kind: "claims", and its content is deliberately not JSON and not markdown: it is a plain numbered claim set, 1. A method ... with a blank line between claims and nothing else — no headings, no commentary, no numbering prefix beyond the number itself. That is exactly the shape the review112 lane expects in claims_text.

So you feed the string straight back in. Two calls, the same disclosure, and the drafted set goes through the 112 review that would otherwise wait for a human to copy and paste it. That handoff is the point of the app. The review112 run then returns artifact.kind: "claims" in turn, with its rewrites applied in the same numbering, so a third call can review the reviewed set if a practitioner has edited it.

Give the second call its own idempotency key. Same disclosure, different task: if task is not in the key, the review run collides with the draft run and hands back the draft lane's cached result.

run_and_wait is step 5 wrapped in a function: post to /run with the idempotency key, poll GET /jobs/{job_id} until terminal, and return json.loads(status["output"]["output"]).

Notes that will save you a support round trip

This is drafting output for a licensed practitioner to review. It is not legal advice. Patent Desk is not your attorney and does not form an attorney-client relationship. A patentability call, a filing decision, a bar-date question and a freedom-to-operate opinion all need a licensed practitioner in your jurisdiction. Nothing here predicts allowance, estimates odds of grant or advises on a deadline, and no output should be filed without review.