AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Uspto Odp Search

skill-leonardhope-uspto-odp-natural-language-search-uspto-odp-natural-language-search · by LeonardHope

>

No reviews yet
0 installs
16 views
0.0% view→install

Install

$ agentstack add skill-leonardhope-uspto-odp-natural-language-search-uspto-odp-natural-language-search

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-leonardhope-uspto-odp-natural-language-search-uspto-odp-natural-language-search)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
4mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Uspto Odp Search? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

USPTO Open Data Portal Search Skill

Overview

This skill gives you access to every major USPTO API through natural language. The user asks a question in plain English, and your job is to figure out which API to query, build the right request, run it, and present the results clearly.

All APIs are accessed through the USPTO Open Data Portal (ODP) platform using a single API key. You have 11 Python modules in the scripts/ directory:

| Module | Purpose | Key Functions | |--------|---------|---------------| | patent_search.py | Patent application search (keyword, assignee, inventor, CPC, patent number, examiner, status) | search_by_assignee(), search_by_inventor(), search_by_keyword(), search_by_patent_number(), search_by_application_number(), search_by_cpc(), search_by_examiner(), search_by_status(), search_patents(), download_search_results() | | file_wrapper.py | File wrapper sub-resources for specific applications | get_application(), get_application_by_patent_number(), get_application_documents(), get_continuity(), get_patent_term_adjustment(), get_assignment(), get_attorney(), get_transactions(), get_foreign_priority(), get_associated_documents(), get_meta_data(), get_status_codes() | | ptab_search.py | PTAB trials, appeals, interferences | search_proceedings(), get_proceeding(), search_trial_decisions(), search_trial_documents(), search_appeal_decisions(), search_interference_decisions() | | petition_search.py | Final petition decisions | search_petition_decisions(), get_petition_decision(), download_petition_decisions() | | office_actions_search.py | Office action rejections, text, citations, enriched citations (DSAPI/Lucene) | search_rejections(), search_office_action_text(), search_office_action_citations(), search_enriched_citations() | | assignment_search.py | Patent ownership/assignment chain | get_assignment_chain(), search_patent_assignments(), get_assignments_by_company(), get_assignments_for_application() | | tsdr_search.py | Trademark status and document retrieval (TSDR API) | get_trademark_status(), get_trademark_documents(), get_trademark_document(), download_trademark_document(), get_multi_status(), get_last_update() | | bulk_data_search.py | Bulk dataset product search and download | search_bulk_datasets(), get_bulk_dataset(), download_bulk_file() | | download_documents.py | File wrapper document listing and PDF download | list_documents(), download_documents(), fetch_all_documents() | | format_results.py | Output formatting | format_patent_list(), format_patent_detail(), format_ptab_results(), format_assignment_results(), format_rejection_results(), format_petition_results() | | uspto_client.py | Shared client with auth, rate limiting, retry logic | get_client(), USPTOClient |


Setup

Only one API key is needed for everything, including trademarks.

cd scripts/
python uspto_client.py

If the output contains [SETUP_REQUIRED], guide the user through setup:

Quickest option -- interactive setup script:

python get_started.py

This creates a Python virtual environment (.venv), installs dependencies, prompts for the API key, masks the value, and saves it to a .env file in the project root.

Alternative -- set environment variable directly:

export USPTO_ODP_API_KEY="their_key"

Where to get the key:

  • Register at https://data.uspto.gov/myodp (free, requires ID.me verification)
  • This single key covers all ODP APIs: patent search, file wrapper, PTAB, assignments, office actions, petition decisions, bulk data, and TSDR trademarks

How to Handle User Requests

Follow these steps for every request.

Step 1: Parse the Natural Language

Break down what the user is asking for. Identify:

  • Entity: What are they looking for? (patents, applications, proceedings, assignments, rejections, trademarks, bulk data)
  • Filters: By whom? (inventor, assignee, examiner) When? (date range) What about? (keywords, CPC codes)
  • Relationships: Continuity? Ownership chain? PTAB challenges? Rejections?
  • Scope: Single patent/trademark lookup vs. broad search vs. analytics

Step 2: Choose the Right API

Use this decision matrix. Check conditions top to bottom -- use the first match.

Patent Application Search (patent_search.py)

| User wants to... | Key signals in request | Script function | |---|---|---| | Search by company/assignee | company name + "patents", "assigned to", "portfolio" | search_by_assignee(name, date_from=, date_to=, limit=) | | Search by inventor name | person name + "inventor", "invented by", "patents by" | search_by_inventor(last_name, first_name=, date_from=, date_to=, limit=) | | Search by keyword/technology | technology terms, "patents about", "related to" | search_by_keyword(keywords, date_from=, date_to=, limit=) | | Look up a specific granted patent | patent number only, basic info | search_by_patent_number(patent_number) | | Look up a specific application | application number (16/xxx, etc.) | search_by_application_number(application_number) | | Search by CPC/classification | CPC code, technology class, "class H04L" | search_by_cpc(cpc_code, date_from=, date_to=, limit=) | | Search by examiner | examiner name, "examiner Smith" | search_by_examiner(examiner_name, limit=) | | Search by application status | "pending", "patented", "abandoned" | search_by_status(status, limit=) | | Advanced/custom search | complex filters, range queries, specific fields | search_patents(q=, filters=, range_filters=, sort=, fields=, offset=, limit=) | | Download search results in bulk | "export", "download results", "CSV" | download_search_results(q=, filters=, range_filters=, format=) |

File Wrapper Sub-Resources (file_wrapper.py)

| User wants to... | Key signals in request | Script function | |---|---|---| | Get full data for a specific application | application number + "everything", "details", "full record" | get_application(application_number) | | Resolve patent number to application data | patent number + need app-level data | get_application_by_patent_number(patent_number) | | Get application metadata (status, dates, parties) | "status", "who filed", "filing date", "classification" | get_meta_data(application_number) | | Get prosecution history / file wrapper docs | "office actions", "prosecution", "file wrapper", "IDS" | get_application_documents(application_number, offset=, limit=) | | See parent/child application relationships | "continuation", "divisional", "family", "priority", "parent", "child" | get_continuity(application_number) | | Check patent term adjustment | "PTA", "term adjustment", "patent term" | get_patent_term_adjustment(application_number) | | Get assignment records for an application | "assignment", "owner" + application number | get_assignment(application_number) | | Get attorney/agent of record | "attorney", "agent", "law firm", "who represents" | get_attorney(application_number) | | Get transaction/event history | "transactions", "events", "history", "timeline" | get_transactions(application_number) | | Get foreign priority claims | "foreign priority", "Paris Convention", "PCT" | get_foreign_priority(application_number) | | Get associated document metadata | "publication", "grant XML", "associated documents" | get_associated_documents(application_number) | | Look up status codes | "status code", "what does status X mean" | get_status_codes(query=) |

PTAB Trials, Appeals, and Interferences (ptab_search.py)

| User wants to... | Key signals in request | Script function | |---|---|---| | Find PTAB trial proceedings | "IPR", "PGR", "CBM", "PTAB", "challenged", "invalidated", "trial" | search_proceedings(query=, patent_number=, party_name=, trial_number=, proceeding_type=) | | Get details for a specific trial | trial number (e.g. "IPR2020-00001") | get_proceeding(trial_number) | | Read PTAB trial decisions | "PTAB decision", "final written decision", "institution decision" | search_trial_decisions(query=, patent_number=, trial_number=) | | Find PTAB trial documents/filings | "PTAB filings", "exhibits", "petitioner brief" | search_trial_documents(query=, trial_number=) | | Search appeal decisions | "appeal", "BPAI", "appeal decision", "ex parte appeal" | search_appeal_decisions(query=, appeal_number=) | | Search interference decisions | "interference", "priority of invention" | search_interference_decisions(query=, interference_number=) |

Office Actions (office_actions_search.py)

| User wants to... | Key signals in request | Script function | |---|---|---| | Check 101/102/103/112 rejections | "rejection", "101", "102", "103", "112", "Alice", "obviousness", "anticipation" | search_rejections(application_number=, patent_number=, rejection_type=, art_unit=, criteria=) | | Read office action text | "office action text", "examiner's reasoning", "what did the examiner say" | search_office_action_text(application_number=, patent_number=, criteria=) | | See what prior art was cited in OAs | "cited references", "prior art cited", "citations in office action" | search_office_action_citations(application_number=, patent_number=, criteria=) | | Get enriched/parsed citations | "enriched citations", "which claims cited against", "citation context" | search_enriched_citations(application_number=, patent_number=, cited_reference=, criteria=) |

Patent Assignments (assignment_search.py)

| User wants to... | Key signals in request | Script function | |---|---|---| | Find who owns a patent | "owner", "assigned to", "chain of title", "who owns" | get_assignment_chain(patent_number) | | Get assignments for an application | application number + "assignment", "ownership" | get_assignments_for_application(application_number) | | Track patent acquisitions/sales | "bought", "sold", "transferred", "acquired" | search_patent_assignments(patent_number=, application_number=) | | Find assignments involving a company | company name + "assignments", "acquisitions", "transfers" | get_assignments_by_company(company_name, as_assignee=, as_assignor=) |

Petition Decisions (petition_search.py)

| User wants to... | Key signals in request | Script function | |---|---|---| | Search petition decisions | "petition", "revival", "extension of time", "petition decision" | search_petition_decisions(query=, application_number=, patent_number=) | | Get a specific petition decision | petition decision record ID | get_petition_decision(record_id) | | Download petition decision results | "download petitions", "export petition data" | download_petition_decisions(query=, format=) |

Trademark Status & Documents (tsdr_search.py)

| User wants to... | Key signals in request | Script function | |---|---|---| | Check trademark status | "trademark status", "mark status", serial/registration number, "TSDR" | get_trademark_status(serial_number=, registration_number=, case_id=) | | List trademark case documents | "trademark documents", "trademark file", "office actions for mark" | get_trademark_documents(case_id) | | Get single trademark document info | specific document ID from a trademark case | get_trademark_document(case_id, doc_id) | | Download trademark document PDF | "download trademark document", "get trademark PDF" | download_trademark_document(case_id, doc_id, dest_path) | | Batch trademark status lookup | multiple serial/registration numbers at once | get_multi_status(case_type, ids) | | Check TSDR data freshness | "when was TSDR updated", "data freshness" | get_last_update() |

Bulk Data Products (bulk_data_search.py)

| User wants to... | Key signals in request | Script function | |---|---|---| | Find available bulk datasets | "bulk data", "bulk download", "dataset", "data dump" | search_bulk_datasets(query=, offset=, limit=) | | Get details on a specific dataset | product ID, dataset name | get_bulk_dataset(product_id) | | Download a bulk data file | "download dataset", specific product + file name | download_bulk_file(product_id, file_name, dest_path) |

File Wrapper Document Download (download_documents.py)

| User wants to... | Key signals in request | Script function | |---|---|---| | List documents in file wrapper | "list documents", "what's in the file wrapper", "show prosecution docs" | list_documents(app_number, key_only=False, codes=None) | | Download prosecution documents | "download", "save", "get the PDFs", "pull the file history" | download_documents(app_number, output_dir=, key_only=True, codes=None, download_all=False) | | Download specific document types | "download office actions", "get the IDS filings", specific doc codes | download_documents(app_number, codes=["CTNF","CTFR"]) |

Step 3: Handle Fuzzy / Ambiguous Queries

Users will not give you exact names or numbers. Handle this gracefully:

Company names: The ODP search uses free-text matching, so pass the company name directly. If results are sparse, try common variations (with/without "Inc.", "LLC", "Corp.", etc.) as separate searches:

from patent_search import search_by_assignee
result = search_by_assignee("Atari")
# If sparse, also try: search_by_assignee("Atari, Inc.")

Inventor names: Uses quoted full name for exact matching when both first and last names are provided. If only a last name is given, results may be broad -- ask the user for a first name or other filter to narrow down:

from patent_search import search_by_inventor
result = search_by_inventor("Tesla", first_name="Nikola")

Patent numbers: Strip formatting automatically. Accept any of these: 10,000,000, US10000000, 10000000, US 10,000,000. The clean_patent_number() utility in uspto_client.py handles this.

Application numbers: Accept 16/123,456 or 16123456 -- the clean_app_number() utility handles cleanup.

Trademark identifiers: TSDR accepts serial numbers (prefix sn), registration numbers (prefix rn), reference numbers (prefix ref), and international registration numbers (prefix ir). The _format_case_id() helper in tsdr_search.py handles formatting:

from tsdr_search import get_trademark_status
# Any of these work:
result = get_trademark_status(serial_number="88123456")
result = get_trademark_status(registration_number="1234567")
result = get_trademark_status(case_id="sn88123456")

Ambiguous entities: If the user says "Apple patents", that clearly means Apple Inc. But if they say "Tesla", ask whether they mean Tesla Inc. or Nikola Tesla the inventor -- unless context makes it obvious.

Patent vs. trademark: If the user says "check the status of 88123456", the 8-digit number starting with 88 is likely a trademark serial number. Standard patent application numbers are formatted as XX/XXX,XXX. Use context clues to determine which API to call.

Step 4: Run the Query

Import and call the appropriate script function. All scripts are in the scripts/ directory relative to this skill. For example:

import os, sys
skill_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(skill_dir, "scripts"))
from patent_search import search_by_assignee
result = search_by_assignee("Atari")

Or run via command line from the skill's root directory:

cd scripts/
python patent_search.py assignee "Atari"
python patent_search.py patent 10000000
python patent_search.py inventor "Smith" --first "John"
python patent_search.py keyword "autonomous vehicle lidar"
python patent_search.py cpc H04L
python patent_search.py examiner "Smith"
python file_wrapper.py get 16123456
python file_wrapper.py documents 16123456
python file_wrapper.py continuity 16123456
python file_wrapper.py pta 14643719
python ptab_search.py proceedings --patent-number 10000000
python ptab_sear

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [LeonardHope](https://github.com/LeonardHope)
- **Source:** [LeonardHope/USPTO-ODP-Natural-Language-Search](https://github.com/LeonardHope/USPTO-ODP-Natural-Language-Search)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.