api-shakedown 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- api_shakedown-0.1.0/.gitignore +22 -0
- api_shakedown-0.1.0/LICENSE +21 -0
- api_shakedown-0.1.0/PKG-INFO +431 -0
- api_shakedown-0.1.0/README.md +384 -0
- api_shakedown-0.1.0/examples/petstore.yaml +135 -0
- api_shakedown-0.1.0/pyproject.toml +92 -0
- api_shakedown-0.1.0/src/api_shakedown/__init__.py +3 -0
- api_shakedown-0.1.0/src/api_shakedown/__main__.py +3 -0
- api_shakedown-0.1.0/src/api_shakedown/agents/__init__.py +1 -0
- api_shakedown-0.1.0/src/api_shakedown/agents/_common.py +36 -0
- api_shakedown-0.1.0/src/api_shakedown/agents/chaos.py +146 -0
- api_shakedown-0.1.0/src/api_shakedown/agents/contracts.py +176 -0
- api_shakedown-0.1.0/src/api_shakedown/agents/coordinator.py +211 -0
- api_shakedown-0.1.0/src/api_shakedown/agents/reviewer.py +301 -0
- api_shakedown-0.1.0/src/api_shakedown/agents/stubs.py +163 -0
- api_shakedown-0.1.0/src/api_shakedown/agents/testdata.py +146 -0
- api_shakedown-0.1.0/src/api_shakedown/chaos.py +451 -0
- api_shakedown-0.1.0/src/api_shakedown/chaos_control.py +54 -0
- api_shakedown-0.1.0/src/api_shakedown/cli.py +131 -0
- api_shakedown-0.1.0/src/api_shakedown/config.py +19 -0
- api_shakedown-0.1.0/src/api_shakedown/contracts.py +243 -0
- api_shakedown-0.1.0/src/api_shakedown/harness/__init__.py +26 -0
- api_shakedown-0.1.0/src/api_shakedown/mcp_server.py +218 -0
- api_shakedown-0.1.0/src/api_shakedown/pipeline.py +92 -0
- api_shakedown-0.1.0/src/api_shakedown/py.typed +0 -0
- api_shakedown-0.1.0/src/api_shakedown/spec/__init__.py +17 -0
- api_shakedown-0.1.0/src/api_shakedown/spec/chunking.py +32 -0
- api_shakedown-0.1.0/src/api_shakedown/spec/edge_cases.py +149 -0
- api_shakedown-0.1.0/src/api_shakedown/spec/loader.py +104 -0
- api_shakedown-0.1.0/src/api_shakedown/spec/models.py +78 -0
- api_shakedown-0.1.0/src/api_shakedown/spec/normalize.py +175 -0
- api_shakedown-0.1.0/src/api_shakedown/spec/refs.py +59 -0
- api_shakedown-0.1.0/src/api_shakedown/spec/samples.py +100 -0
- api_shakedown-0.1.0/src/api_shakedown/spec/schema_check.py +31 -0
- api_shakedown-0.1.0/src/api_shakedown/templates/__init__.py +1 -0
- api_shakedown-0.1.0/src/api_shakedown/templates/chaos_cli.py +92 -0
- api_shakedown-0.1.0/src/api_shakedown/templates/contract_runner.py +50 -0
- api_shakedown-0.1.0/src/api_shakedown/templates/robustness_runner.py +37 -0
- api_shakedown-0.1.0/src/api_shakedown/templates/shakedown_support.py +92 -0
- api_shakedown-0.1.0/src/api_shakedown/testdata.py +215 -0
- api_shakedown-0.1.0/src/api_shakedown/wiremock.py +273 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.mypy_cache/
|
|
11
|
+
.coverage
|
|
12
|
+
htmlcov/
|
|
13
|
+
|
|
14
|
+
# secrets: never commit real keys
|
|
15
|
+
.env
|
|
16
|
+
|
|
17
|
+
# generated harnesses
|
|
18
|
+
shakedown-output/
|
|
19
|
+
|
|
20
|
+
.idea/
|
|
21
|
+
.vscode/
|
|
22
|
+
.DS_Store
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Anzar Ahsan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: api-shakedown
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Multi-agent generator of WireMock stubs, contract tests, and chaos scenarios from an OpenAPI spec.
|
|
5
|
+
Project-URL: Homepage, https://github.com/anzar-ahsan-commits/api-shakedown
|
|
6
|
+
Project-URL: Documentation, https://github.com/anzar-ahsan-commits/api-shakedown#readme
|
|
7
|
+
Project-URL: Issues, https://github.com/anzar-ahsan-commits/api-shakedown/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/anzar-ahsan-commits/api-shakedown/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Anzar Ahsan
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: chaos-engineering,contract-testing,langgraph,llm,mcp,openapi,wiremock
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Testing
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Requires-Dist: agentpanel<0.2,>=0.1.0
|
|
25
|
+
Requires-Dist: httpx>=0.27
|
|
26
|
+
Requires-Dist: openapi-spec-validator>=0.7
|
|
27
|
+
Requires-Dist: pyyaml>=6.0
|
|
28
|
+
Requires-Dist: typer>=0.12
|
|
29
|
+
Provides-Extra: anthropic
|
|
30
|
+
Requires-Dist: agentpanel[anthropic]<0.2,>=0.1.0; extra == 'anthropic'
|
|
31
|
+
Provides-Extra: cloud
|
|
32
|
+
Requires-Dist: agentpanel[cloud]<0.2,>=0.1.0; extra == 'cloud'
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: agentpanel[cloud]<0.2,>=0.1.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
36
|
+
Requires-Dist: mcp<3,>=2.3; extra == 'dev'
|
|
37
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
40
|
+
Requires-Dist: twine>=5; extra == 'dev'
|
|
41
|
+
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
42
|
+
Provides-Extra: mcp
|
|
43
|
+
Requires-Dist: mcp<3,>=2.3; extra == 'mcp'
|
|
44
|
+
Provides-Extra: openai
|
|
45
|
+
Requires-Dist: agentpanel[openai]<0.2,>=0.1.0; extra == 'openai'
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
# API Shakedown
|
|
49
|
+
|
|
50
|
+
**Give it an OpenAPI spec. Get back a ready-to-run test harness: WireMock stubs, contract
|
|
51
|
+
tests, robustness probes, and chaos scenarios, written by a team of LLM agents that
|
|
52
|
+
review each other's work.**
|
|
53
|
+
|
|
54
|
+
[](https://github.com/anzar-ahsan-commits/api-shakedown/actions/workflows/ci.yml)
|
|
55
|
+
[](https://pypi.org/project/api-shakedown/)
|
|
56
|
+
[](https://pypi.org/project/api-shakedown/)
|
|
57
|
+
[](https://github.com/anzar-ahsan-commits/api-shakedown/blob/main/LICENSE)
|
|
58
|
+
|
|
59
|
+
Runs **locally on [Ollama](https://ollama.com) by default**: no API key, no data leaves
|
|
60
|
+
your machine. Cloud models (OpenAI, Anthropic) are bring-your-own-key. Available as a
|
|
61
|
+
CLI, a Docker image, and an **MCP server** so an AI assistant can drive it.
|
|
62
|
+
|
|
63
|
+
> Status: alpha (0.1.0). Works end to end on the example spec with a local 8B model.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Contents
|
|
68
|
+
|
|
69
|
+
- [Why](#why)
|
|
70
|
+
- [Quick start](#quick-start)
|
|
71
|
+
- [What you get](#what-you-get)
|
|
72
|
+
- [How it works](#how-it-works)
|
|
73
|
+
- [Install](#install)
|
|
74
|
+
- [Usage](#usage)
|
|
75
|
+
- [Configuration](#configuration)
|
|
76
|
+
- [MCP server](#mcp-server)
|
|
77
|
+
- [Docker](#docker)
|
|
78
|
+
- [Architecture](#architecture)
|
|
79
|
+
- [Limitations](#limitations)
|
|
80
|
+
- [Roadmap](#roadmap)
|
|
81
|
+
- [Development](#development)
|
|
82
|
+
- [Contributing](#contributing)
|
|
83
|
+
- [License](#license)
|
|
84
|
+
|
|
85
|
+
## Why
|
|
86
|
+
|
|
87
|
+
Teams that consume an API need three things that are tedious to write by hand and go
|
|
88
|
+
stale quickly:
|
|
89
|
+
|
|
90
|
+
1. **A realistic mock** of the API to develop and test against.
|
|
91
|
+
2. **Contract tests** that tell you when the real API stops matching its spec.
|
|
92
|
+
3. **Failure drills**: what does your client do when the API is slow, flaky, rate
|
|
93
|
+
limited, returns garbage, or goes down?
|
|
94
|
+
|
|
95
|
+
API Shakedown generates all three from the spec you already have, and keeps them honest:
|
|
96
|
+
**the LLMs never write code that runs**. They propose *data* (response bodies, test
|
|
97
|
+
cases, failure scenarios, test records), and code validates every item against the
|
|
98
|
+
spec, feeds problems back to the model, and falls back to deterministic output when a
|
|
99
|
+
model cannot get it right. Without any model at all (`--offline`), every part still works.
|
|
100
|
+
|
|
101
|
+
## Quick start
|
|
102
|
+
|
|
103
|
+
Prerequisites: Python 3.11+, Docker (for WireMock), and [Ollama](https://ollama.com) with
|
|
104
|
+
a model (`ollama pull qwen3:8b`) unless you use `--offline` or a cloud model.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
pip install api-shakedown
|
|
108
|
+
shakedown doctor # is the model ready?
|
|
109
|
+
shakedown run openapi.yaml --out my-harness # minutes on a local model
|
|
110
|
+
cd my-harness
|
|
111
|
+
docker compose up -d # WireMock with your stubs on :8080
|
|
112
|
+
pip install -r requirements.txt
|
|
113
|
+
SHAKEDOWN_SELECT_STATUS=1 pytest tests/test_contract.py
|
|
114
|
+
python chaos/chaos.py on flaky-start # now point your client at :8080
|
|
115
|
+
python chaos/chaos.py off
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Try it on the bundled example: `shakedown run examples/petstore.yaml --out petstore`.
|
|
119
|
+
|
|
120
|
+
A real run on the example spec with `qwen3:8b`:
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
Petstore 1.0.0: 5 operations (ollama / qwen3:8b)
|
|
124
|
+
Generating test data...
|
|
125
|
+
Test data ready (3 Pet).
|
|
126
|
+
Generating stubs, contract tests, and chaos scenarios...
|
|
127
|
+
stubs: done
|
|
128
|
+
contracts: done
|
|
129
|
+
chaos: done
|
|
130
|
+
review contracts: approved
|
|
131
|
+
review stubs: approved
|
|
132
|
+
review chaos: approved
|
|
133
|
+
|
|
134
|
+
Wrote 14 files to harness in 436s: 15 stubs, 11 contract cases, 11 chaos scenarios, 30 probes.
|
|
135
|
+
Next: cd harness && docker compose up -d (then see README.md)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## What you get
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
my-harness/
|
|
142
|
+
├── README.md # generated: how to run it, every scenario, review notes
|
|
143
|
+
├── docker-compose.yml # WireMock 3 serving the stubs (port: SHAKEDOWN_WIREMOCK_PORT)
|
|
144
|
+
├── wiremock/mappings/ # stub mappings
|
|
145
|
+
├── tests/
|
|
146
|
+
│ ├── test_contract.py # contract tests (cases in contract_cases.json)
|
|
147
|
+
│ └── test_robustness.py # malformed-request probes (cases in robustness_cases.json)
|
|
148
|
+
├── chaos/
|
|
149
|
+
│ ├── chaos.py # switch failure scenarios on/off (standard library only)
|
|
150
|
+
│ └── chaos_scenarios.json
|
|
151
|
+
├── data/dataset.json # test records and edge-case values per field
|
|
152
|
+
├── requirements.txt # pytest, httpx, openapi-schema-validator
|
|
153
|
+
└── shakedown.json # manifest: counts, review outcome, generation notes
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
| Part | What it does |
|
|
157
|
+
|---|---|
|
|
158
|
+
| **Stubs** | Every documented response of every operation. Known ids return their own record, unknown ids return the documented 404, and any other response can be requested with `X-Shakedown-Status: <status>`. |
|
|
159
|
+
| **Contract tests** | Happy paths, documented error statuses, and boundary values. Each checks the status code, `Content-Type`, and the body against the response schema. Run them against the stubs or a real deployment. |
|
|
160
|
+
| **Robustness probes** | Invalid bodies and parameters derived from the schemas (missing required fields, wrong types, out-of-range values, broken JSON). A robust server answers 4xx, never 5xx. |
|
|
161
|
+
| **Chaos scenarios** | Seven baseline failures every client should survive, plus scenarios the LLM targets at your API. |
|
|
162
|
+
| **Test data** | Realistic, consistent records per entity, shared by the stubs and the tests, plus edge-case values for every field. |
|
|
163
|
+
|
|
164
|
+
Baseline chaos scenarios:
|
|
165
|
+
|
|
166
|
+
| Scenario | What happens | A resilient client should |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| `total-outage` | Every endpoint returns 503 | Fail fast, back off, not hammer the API |
|
|
169
|
+
| `slow-responses` | Every response takes 3 s | Stay responsive |
|
|
170
|
+
| `timeouts` | Every response takes 30 s | Give up on its own and free resources |
|
|
171
|
+
| `connection-resets` | Connections are reset | Retry idempotent calls with backoff |
|
|
172
|
+
| `flaky-start` | First 2 calls fail with 503, then recover | Retry and succeed on the third attempt |
|
|
173
|
+
| `rate-limited` | First 3 calls return 429 | Honour `Retry-After` |
|
|
174
|
+
| `truncated-json` | Success bodies are cut off mid-JSON | Report a parse error, never crash |
|
|
175
|
+
|
|
176
|
+
LLM-targeted scenarios from a real run include *createPet fails 3 times with 503 then
|
|
177
|
+
recovers*, *listPets is rate limited*, and *getPet loses required fields*.
|
|
178
|
+
|
|
179
|
+
## How it works
|
|
180
|
+
|
|
181
|
+
```mermaid
|
|
182
|
+
flowchart LR
|
|
183
|
+
spec[/"OpenAPI spec"/] --> load["Load, validate,<br/>normalize, chunk"]
|
|
184
|
+
load --> data["Test data agent"]
|
|
185
|
+
data --> stubs["Stub agent"]
|
|
186
|
+
data --> contracts["Contract agent"]
|
|
187
|
+
data --> chaos["Chaos agent"]
|
|
188
|
+
stubs --> review{"Reviewer agent"}
|
|
189
|
+
contracts --> review
|
|
190
|
+
chaos --> review
|
|
191
|
+
review -- "blocker: revise with feedback" --> stubs
|
|
192
|
+
review -- "blocker" --> contracts
|
|
193
|
+
review -- "blocker" --> chaos
|
|
194
|
+
review -- "approved, or budget spent" --> coord["Coordinator"]
|
|
195
|
+
coord --> harness[/"Harness directory"/]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
1. **Spec layer**: loads YAML/JSON from a path or URL, validates it (problems become
|
|
199
|
+
warnings), inlines `$ref`s safely, and splits operations into prompt-sized chunks so
|
|
200
|
+
large specs fit small models.
|
|
201
|
+
2. **Test data agent** runs first: the stubs and tests share its records.
|
|
202
|
+
3. **Stub, contract, and chaos agents** run in parallel.
|
|
203
|
+
4. **Reviewer** judges each artifact. Blockers send it back to its author with the
|
|
204
|
+
feedback, for a bounded number of rounds; suggestions are kept as notes.
|
|
205
|
+
5. **Coordinator** assembles the harness and its README, including anything the
|
|
206
|
+
reviewer still rejected when the revision budget ran out.
|
|
207
|
+
|
|
208
|
+
Every agent follows the same pattern, which is what keeps small local models reliable:
|
|
209
|
+
|
|
210
|
+
```mermaid
|
|
211
|
+
sequenceDiagram
|
|
212
|
+
participant A as Agent
|
|
213
|
+
participant M as LLM
|
|
214
|
+
participant C as Code checks
|
|
215
|
+
A->>M: task + JSON schema (constrained decoding on Ollama)
|
|
216
|
+
M-->>A: proposal (bodies, cases, scenarios, records)
|
|
217
|
+
A->>C: validate against the spec
|
|
218
|
+
alt problems found
|
|
219
|
+
C-->>A: exact errors, e.g. "listPets 200: 'id' is a required property"
|
|
220
|
+
A->>M: fix these problems
|
|
221
|
+
M-->>A: corrected proposal
|
|
222
|
+
end
|
|
223
|
+
A->>A: keep valid items, fall back to deterministic ones for the rest
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Things code guarantees, so the model never has to:
|
|
227
|
+
|
|
228
|
+
- Request matching, URL patterns, priorities, and path-parameter types in the stubs.
|
|
229
|
+
- Response bodies valid against their schemas.
|
|
230
|
+
- Test inputs that route (valid path parameters, required query parameters), success
|
|
231
|
+
cases that use ids that exist, 404 cases that use ids that do not.
|
|
232
|
+
- Authentication from the spec's security schemes.
|
|
233
|
+
- Chaos scenarios that are internally consistent (a "flaky" failure must recover, a rate
|
|
234
|
+
limit is a 429, a partial outage leaves some endpoints up).
|
|
235
|
+
- Reviewer findings that cite real items, and blockers only on what the author controls.
|
|
236
|
+
|
|
237
|
+
## Install
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
pip install api-shakedown # local models via Ollama
|
|
241
|
+
pip install "api-shakedown[cloud]" # plus OpenAI and Anthropic
|
|
242
|
+
pip install "api-shakedown[mcp]" # plus the MCP server
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Or use the Docker image, which includes everything: see [Docker](#docker).
|
|
246
|
+
|
|
247
|
+
Generated harnesses need Docker (for WireMock) and Python for their tests.
|
|
248
|
+
|
|
249
|
+
## Usage
|
|
250
|
+
|
|
251
|
+
```text
|
|
252
|
+
shakedown doctor Check the LLM provider is reachable and ready
|
|
253
|
+
shakedown inspect SPEC [--json] Show the operations the agents will see
|
|
254
|
+
shakedown run SPEC [options] Generate a harness
|
|
255
|
+
shakedown version
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`shakedown run` options:
|
|
259
|
+
|
|
260
|
+
| Option | Default | |
|
|
261
|
+
|---|---|---|
|
|
262
|
+
| `--out PATH` | `shakedown-output` | Where to write the harness (refuses a non-empty directory) |
|
|
263
|
+
| `--offline` | off | No LLM: deterministic output in seconds |
|
|
264
|
+
| `--no-review` | review on | Skip the reviewer (about 3x faster on the example) |
|
|
265
|
+
| `--max-revisions N` | `1` | Review/revise rounds |
|
|
266
|
+
| `--force` | off | Write into a non-empty directory (only overwrites harness files) |
|
|
267
|
+
| `--provider`, `--model` | from settings | Override the LLM for this run |
|
|
268
|
+
|
|
269
|
+
Using the harness:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
docker compose up -d # stubs on http://localhost:8080
|
|
273
|
+
SHAKEDOWN_SELECT_STATUS=1 pytest tests/test_contract.py # against the stubs
|
|
274
|
+
python chaos/chaos.py list | on <scenario> | off # failure drills
|
|
275
|
+
SHAKEDOWN_TARGET_URL=https://api.example.com/v1 pytest tests # against a real server
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
PowerShell: `$env:SHAKEDOWN_SELECT_STATUS = "1"; pytest tests/test_contract.py`.
|
|
279
|
+
|
|
280
|
+
## Configuration
|
|
281
|
+
|
|
282
|
+
Settings come from environment variables or a `.env` file
|
|
283
|
+
(see [.env.example](https://github.com/anzar-ahsan-commits/api-shakedown/blob/main/.env.example)). Everything is optional.
|
|
284
|
+
|
|
285
|
+
| Variable | Default | |
|
|
286
|
+
|---|---|---|
|
|
287
|
+
| `SHAKEDOWN_PROVIDER` | `ollama` | `ollama`, `openai`, or `anthropic` |
|
|
288
|
+
| `SHAKEDOWN_MODEL` | per provider | `qwen3:8b`, `gpt-5-mini`, `claude-sonnet-5-5` |
|
|
289
|
+
| `SHAKEDOWN_OLLAMA_URL` | `http://localhost:11434` | Where Ollama runs |
|
|
290
|
+
| `SHAKEDOWN_BASE_URL` | | Endpoint override, e.g. an OpenAI-compatible server |
|
|
291
|
+
| `SHAKEDOWN_TIMEOUT` | 600 (Ollama) / 120 | Seconds per request |
|
|
292
|
+
| `SHAKEDOWN_CONTEXT_WINDOW` | `16384` | Ollama context size |
|
|
293
|
+
| `SHAKEDOWN_REASONING` | model default | Ollama: turn a reasoning model's thinking on/off |
|
|
294
|
+
| `SHAKEDOWN_AGENT_MODELS` | | Per-agent models, e.g. `{"reviewer": "anthropic:claude-sonnet-5-5"}` |
|
|
295
|
+
| `SHAKEDOWN_AGENT_REASONING` | thinking off for generators | Per-agent thinking, e.g. `{"reviewer": true}` |
|
|
296
|
+
| `OPENAI_API_KEY`, `ANTHROPIC_API_KEY` | | Bring your own key |
|
|
297
|
+
|
|
298
|
+
Mixing models works well: generate locally, review with a stronger cloud model:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
SHAKEDOWN_AGENT_MODELS='{"reviewer": "anthropic:claude-sonnet-5-5"}' shakedown run openapi.yaml
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Generated harnesses read `SHAKEDOWN_TARGET_URL`, `SHAKEDOWN_SELECT_STATUS`,
|
|
305
|
+
`SHAKEDOWN_API_KEY`, `SHAKEDOWN_BASIC_AUTH`, `SHAKEDOWN_TIMEOUT`, and
|
|
306
|
+
`SHAKEDOWN_WIREMOCK_PORT` / `SHAKEDOWN_WIREMOCK_URL`.
|
|
307
|
+
|
|
308
|
+
## MCP server
|
|
309
|
+
|
|
310
|
+
`shakedown-mcp` (stdio) lets an MCP client such as Claude Code or Claude Desktop
|
|
311
|
+
generate harnesses and run failure drills:
|
|
312
|
+
|
|
313
|
+
| Tool | |
|
|
314
|
+
|---|---|
|
|
315
|
+
| `doctor` | Is the LLM provider ready? |
|
|
316
|
+
| `inspect_spec` | List a spec's operations and warnings |
|
|
317
|
+
| `generate_harness` | Generate a harness, with progress notifications |
|
|
318
|
+
| `list_chaos_scenarios` | Scenarios in a harness |
|
|
319
|
+
| `activate_chaos` / `deactivate_chaos` | Switch a scenario on/off in a running WireMock |
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
pip install "api-shakedown[mcp]"
|
|
323
|
+
claude mcp add api-shakedown -- shakedown-mcp # Claude Code
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Other clients (`mcpServers` in their config):
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
{
|
|
330
|
+
"mcpServers": {
|
|
331
|
+
"api-shakedown": {
|
|
332
|
+
"command": "shakedown-mcp",
|
|
333
|
+
"env": { "SHAKEDOWN_PROVIDER": "ollama" }
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Pass absolute paths. Generating with a local model takes minutes; if your client gives up
|
|
340
|
+
on long tool calls, use `offline` or `review: false`, or raise its tool timeout.
|
|
341
|
+
|
|
342
|
+
## Docker
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
docker build -t api-shakedown .
|
|
346
|
+
docker run --rm -v "$PWD:/work" api-shakedown run /work/openapi.yaml --out /work/harness
|
|
347
|
+
docker run -i --rm -v "$PWD:/work" --entrypoint shakedown-mcp api-shakedown # MCP server
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
The image reaches Ollama on the host at `host.docker.internal`. Details for Linux,
|
|
351
|
+
PowerShell, and cloud keys: [DOCKER.md](https://github.com/anzar-ahsan-commits/api-shakedown/blob/main/DOCKER.md).
|
|
352
|
+
|
|
353
|
+
## Architecture
|
|
354
|
+
|
|
355
|
+
```mermaid
|
|
356
|
+
flowchart TB
|
|
357
|
+
subgraph app["api-shakedown"]
|
|
358
|
+
cli["CLI: shakedown"] --> pipeline["pipeline"]
|
|
359
|
+
mcp["MCP server: shakedown-mcp"] --> pipeline
|
|
360
|
+
pipeline --> agents["agents: testdata, stubs, contracts,<br/>chaos, reviewer, coordinator"]
|
|
361
|
+
agents --> domain["spec, wiremock, contracts,<br/>chaos, testdata (code checks)"]
|
|
362
|
+
pipeline --> harness["harness writer + templates"]
|
|
363
|
+
end
|
|
364
|
+
subgraph core["agentpanel (reusable core)"]
|
|
365
|
+
workflow["Workflow: parallel specialists,<br/>cross-review, bounded revision"]
|
|
366
|
+
structured["structured output:<br/>validate, feed back, retry"]
|
|
367
|
+
llm["providers: Ollama, OpenAI, Anthropic"]
|
|
368
|
+
end
|
|
369
|
+
agents --> workflow
|
|
370
|
+
agents --> structured
|
|
371
|
+
structured --> llm
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
The orchestration core is published separately as
|
|
375
|
+
[**agentpanel**](https://github.com/anzar-ahsan-commits/api-shakedown/blob/main/packages/agentpanel/README.md): a small, domain-agnostic library for
|
|
376
|
+
"specialists draft, reviewers critique, authors revise, a coordinator decides" workflows
|
|
377
|
+
on LangGraph. It never imports the application; a test enforces that.
|
|
378
|
+
|
|
379
|
+
```text
|
|
380
|
+
packages/agentpanel/ # the reusable core (its own PyPI package)
|
|
381
|
+
src/api_shakedown/ # the application
|
|
382
|
+
spec/ # loading, validation, $ref resolution, edge cases, samples
|
|
383
|
+
agents/ # the six agents
|
|
384
|
+
templates/ # runners copied into every harness
|
|
385
|
+
examples/petstore.yaml # example spec
|
|
386
|
+
tests/ # offline tests; `-m live` for Ollama + Docker tests
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Limitations
|
|
390
|
+
|
|
391
|
+
- **Speed on local models**: a full run on the 5-operation example takes about 7 minutes
|
|
392
|
+
with `qwen3:8b`, most of it review; `--no-review` takes about 2.5 minutes.
|
|
393
|
+
- **Small reviewers are imperfect**: an 8B reviewer sometimes raises a false blocker,
|
|
394
|
+
which costs a revision round. Use a stronger model for the reviewer if you can.
|
|
395
|
+
- **Specs**: OpenAPI 3.0-3.2. Swagger 2.0 must be converted first; references to other
|
|
396
|
+
files are not followed; self-referencing schemas are not validated.
|
|
397
|
+
- **Stubs are static**: a create call returns a new record, but stubs do not keep state
|
|
398
|
+
between calls.
|
|
399
|
+
- **Probes against stubs** only cover operations that document a 4xx; they are meant for
|
|
400
|
+
real servers.
|
|
401
|
+
- Tested so far mainly on the bundled example. Reports from larger real-world specs are
|
|
402
|
+
very welcome.
|
|
403
|
+
|
|
404
|
+
## Roadmap
|
|
405
|
+
|
|
406
|
+
- Larger real-world specs: batching and timing at 30+ operations
|
|
407
|
+
- Stateful stubs (WireMock response templating, created records visible to later calls)
|
|
408
|
+
- Auth-failure scenarios (401/403) and "valid but nasty input must not 5xx" probes
|
|
409
|
+
- Review of the test dataset
|
|
410
|
+
- More harness targets (k6 load profiles, Postman collections)
|
|
411
|
+
|
|
412
|
+
## Development
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
git clone https://github.com/anzar-ahsan-commits/api-shakedown.git
|
|
416
|
+
cd api-shakedown
|
|
417
|
+
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
418
|
+
pip install -e packages/agentpanel -e ".[dev]"
|
|
419
|
+
ruff check . && ruff format --check . && mypy
|
|
420
|
+
pytest # offline: LLMs are faked, about 20 s
|
|
421
|
+
pytest -m live # also uses your local Ollama and Docker
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
## Contributing
|
|
425
|
+
|
|
426
|
+
Contributions are welcome: see [CONTRIBUTING.md](https://github.com/anzar-ahsan-commits/api-shakedown/blob/main/CONTRIBUTING.md). Security issues:
|
|
427
|
+
see [SECURITY.md](https://github.com/anzar-ahsan-commits/api-shakedown/blob/main/SECURITY.md).
|
|
428
|
+
|
|
429
|
+
## License
|
|
430
|
+
|
|
431
|
+
[MIT](https://github.com/anzar-ahsan-commits/api-shakedown/blob/main/LICENSE) © 2026 Anzar Ahsan
|