DuckTap — a CLI factory for AI agents. Print agent-native CLIs + MCP servers + skills from any API or website.
Project description
DuckTap
Tape any API to your agent in one command. DuckTap is a CLI factory for AI agents. Point it at an OpenAPI spec, a HAR file, or a plain website, and it prints a Python CLI, an MCP server, and a Claude/Cursor/Codex skill — wired up, cached, scored, ready to ship.
Website: ducktap-website.vercel.app
DuckTap is inspired by Printing Press by @mvanhorn — same north star (muscle memory for agents) — rebuilt in Python with multi-LLM support, a web dashboard, Playwright-powered browser sniffing, and a real plugin system.
$ ducktap press tests/fixtures/petstore.yaml --out ./out --name petstore
Pressed petstore (19 operations) -> out
python-cli: 10 files
mcp-server: 5 files
skill: 3 files
Scorecard: 92/100 (A)
- coverage: 95 — 19 operations exposed
- documentation: 100 — 19/19 operations have docs
- auth: 100 — 2 auth scheme(s)
- typed_params: 54 — 29/53 params typed/enum
- artifacts: 100 — 3/3 expected artifact dirs present
- naming: 100 — 19/19 unique operation ids
Why a CLI factory?
In a world of AI agents, a well-designed CLI is muscle memory. No hunting through docs, no wrong turns, no wasted tokens. DuckTap reads the spec, sniffs the traffic when no spec exists, and prints:
- A Python CLI (
<api>-dt-cli) — Click-based, auth from env vars, JSON by default, pretty mode for humans, local SQLite mirror for compound queries, retries on transient errors. - An MCP server (
<api>-dt-mcp) — every operation exposed as an MCP tool, stdio transport, drop into Claude Desktop or Cursor in 60 seconds. - A skill for Claude Code, Cursor (
.mdc), and a generictools.json— so any agent harness can pick up where the others left off. - A scorecard grading coverage, docs, auth clarity, typed params, artifacts, and naming.
Install
git clone https://github.com/zanni098/DuckTap
cd ducktap
pip install -e ".[dev]"
ducktap --version
For browser sniffing:
pip install -e ".[dev,sniff]"
playwright install chromium
Quick start
# 1. From an OpenAPI spec (file or URL)
ducktap press https://petstore3.swagger.io/api/v3/openapi.yaml
# 2. From a HAR file (recorded browser traffic)
ducktap press ./capture.har --name myapi
# 3. From a website with no public spec
ducktap sniff https://example.com
# 4. From the curated catalog (built-in or community)
ducktap catalog list
ducktap catalog print stripe
# 4b. Use the community library (https://github.com/zanni098/ducktap-library)
git clone https://github.com/zanni098/ducktap-library ~/ducktap-library
export DUCKTAP_CATALOG=~/ducktap-library
ducktap catalog list # now shows the full library too
# 5. Browse + drive everything from the dashboard
ducktap ui # http://127.0.0.1:8765
What you get under ./out/:
out/
├── petstore-dt-cli/ # pip install -e . → petstore-dt-cli --help
│ ├── pyproject.toml
│ ├── README.md
│ ├── petstore_dt_cli/
│ │ ├── main.py
│ │ ├── commands.py # one click subcommand per API operation
│ │ ├── client.py # httpx + env-var auth + retries
│ │ └── mirror.py # local SQLite cache
│ └── tests/test_smoke.py
├── petstore-dt-mcp/ # pip install -e . → add to Claude Desktop config
│ └── petstore_dt_mcp/server.py
└── skills/ducktap-petstore/
├── SKILL.md # Claude Code skill
├── ducktap-petstore.mdc # Cursor rule
└── tools.json # generic agent tool definitions
How DuckTap improves on Printing Press
| Printing Press | DuckTap | |
|---|---|---|
| Language | Go | Python — easier to extend, richer LLM ecosystem |
| LLM | Claude only | Multi-LLM via LiteLLM (Anthropic, OpenAI, Gemini, Ollama, Groq, Azure) |
| Skills | Claude Code | Claude Code + Cursor .mdc + generic tools.json |
| UI | None | Local FastAPI dashboard (ducktap ui) |
| Plugins | Source fork | Entry-point plugin system — drop-in discoverers & generators |
| Browser sniff | Custom Go browser | Playwright — full HAR export, scriptable actions |
| Generated CLI runtime | Single Go binary | Python (pip-installable, hackable, single-file editable) |
See docs/COMPARISON.md for the full feature matrix.
Commands
ducktap press <source> # discover + generate (the default loop)
ducktap research <source> # discover only — emit normalized APISpec JSON
ducktap sniff <url> # browser-sniff a site (needs [sniff] extra)
ducktap scorecard <source> # quality scorecard
ducktap shipcheck <name> # structural & runtime sanity checks
ducktap catalog list|print # browse the recipe library
ducktap plugins list # show installed discoverers + generators
ducktap ui # local web dashboard
Plugins
Add a discoverer or generator without forking. Register via Python entry points:
# your_plugin/pyproject.toml
[project.entry-points."ducktap.plugins"]
mything = "your_plugin.module" # module just calls plugins.register_discoverer(...)
See docs/PLUGINS.md and the sample at
src/ducktap/plugins/builtin/graphql_intro.py.
Architecture
input (URL | spec | HAR)
│
▼
┌─────────────┐
│ Discovery │ openapi / har / browser-sniff / graphql (plugin) / …
└──────┬──────┘
▼
APISpec (Pydantic) ──── intermediate normalized representation
│
▼
┌─────────────┐
│ Generator │ python-cli / mcp-server / skill / …
└──────┬──────┘
▼
artifacts/ (CLI pkg + MCP pkg + SKILL.md + cursor.mdc + tools.json)
│
▼
┌─────────────┐
│ Verify │ scorecard + shipcheck + (optional) live smoke test
└─────────────┘
See docs/ARCHITECTURE.md.
Roadmap
See docs/ROADMAP.md. Highlights for v0.2+:
- LLM-assisted polish step (operation descriptions, command names, doc strings)
- GraphQL first-class (today: plugin, beta)
- Auth doctor — detect login flows during sniffing, emit accurate auth blocks
- Compound query macros (canonical "what's interesting about X" recipes)
- CLI publish to PyPI + GitHub in one command
License
MIT — see LICENSE.
Acknowledgements
Inspired by Printing Press by Matt Van Horn and the agent-CLI playbook proved out by discrawl and gogcli.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ducktap-0.1.2.tar.gz.
File metadata
- Download URL: ducktap-0.1.2.tar.gz
- Upload date:
- Size: 144.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b5b365b913584a119434ba5a4340e03aee67d902e2b2daeddd92a27d8adfb59
|
|
| MD5 |
ed833d7006e9011afde2b88ea627ba52
|
|
| BLAKE2b-256 |
9ba1a9f90604e52e00379936735e5415f9623a738f7b4b96f6d597046db81f47
|
Provenance
The following attestation bundles were made for ducktap-0.1.2.tar.gz:
Publisher:
publish.yml on zanni098/DuckTap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ducktap-0.1.2.tar.gz -
Subject digest:
0b5b365b913584a119434ba5a4340e03aee67d902e2b2daeddd92a27d8adfb59 - Sigstore transparency entry: 1518522741
- Sigstore integration time:
-
Permalink:
zanni098/DuckTap@0bc34531d7895886fc48791dd8771eebccc4bc30 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/zanni098
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0bc34531d7895886fc48791dd8771eebccc4bc30 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ducktap-0.1.2-py3-none-any.whl.
File metadata
- Download URL: ducktap-0.1.2-py3-none-any.whl
- Upload date:
- Size: 49.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4761c3364fb8730bee9d48d2cced7b888817653d67fbfcdd5ec72b46a60f5ab
|
|
| MD5 |
8ecc465e46671854bc49edef4b639141
|
|
| BLAKE2b-256 |
1ed4e6c873fb330a7d9f02687aff0a1a61abc2c5b858fdba287eb85b25068adf
|
Provenance
The following attestation bundles were made for ducktap-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on zanni098/DuckTap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ducktap-0.1.2-py3-none-any.whl -
Subject digest:
c4761c3364fb8730bee9d48d2cced7b888817653d67fbfcdd5ec72b46a60f5ab - Sigstore transparency entry: 1518522776
- Sigstore integration time:
-
Permalink:
zanni098/DuckTap@0bc34531d7895886fc48791dd8771eebccc4bc30 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/zanni098
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0bc34531d7895886fc48791dd8771eebccc4bc30 -
Trigger Event:
push
-
Statement type: