ghost-api-cli 0.2.0__py3-none-any.whl
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.
- ghost_api/__init__.py +3 -0
- ghost_api/__main__.py +5 -0
- ghost_api/adopt.py +173 -0
- ghost_api/agent/__init__.py +0 -0
- ghost_api/agent/orchestrator.py +413 -0
- ghost_api/agent/prompts.py +149 -0
- ghost_api/agent/tools.py +84 -0
- ghost_api/analysis/__init__.py +0 -0
- ghost_api/analysis/analyzer.py +130 -0
- ghost_api/analysis/detectors.py +188 -0
- ghost_api/analysis/exposure.py +80 -0
- ghost_api/analysis/graphql.py +67 -0
- ghost_api/analysis/models.py +64 -0
- ghost_api/analysis/schema.py +109 -0
- ghost_api/analysis/url_grouping.py +217 -0
- ghost_api/api.py +264 -0
- ghost_api/audit.py +78 -0
- ghost_api/browser/__init__.py +0 -0
- ghost_api/browser/auth_state.py +172 -0
- ghost_api/browser/driver.py +273 -0
- ghost_api/browser/egress.py +183 -0
- ghost_api/browser/gate.py +127 -0
- ghost_api/browser/install.py +28 -0
- ghost_api/browser/snapshot.py +221 -0
- ghost_api/capture/__init__.py +0 -0
- ghost_api/capture/filters.py +255 -0
- ghost_api/capture/har.py +148 -0
- ghost_api/capture/models.py +41 -0
- ghost_api/capture/personal.py +188 -0
- ghost_api/capture/recorder.py +181 -0
- ghost_api/cli/__init__.py +44 -0
- ghost_api/cli/_common.py +219 -0
- ghost_api/cli/client.py +487 -0
- ghost_api/cli/data.py +492 -0
- ghost_api/cli/explore.py +379 -0
- ghost_api/cli/manage.py +437 -0
- ghost_api/config.py +132 -0
- ghost_api/drift.py +344 -0
- ghost_api/drive.py +211 -0
- ghost_api/errors.py +106 -0
- ghost_api/events.py +213 -0
- ghost_api/exitcodes.py +21 -0
- ghost_api/export/__init__.py +71 -0
- ghost_api/export/confidence.py +45 -0
- ghost_api/export/html.py +41 -0
- ghost_api/export/openapi.py +201 -0
- ghost_api/export/report.py +227 -0
- ghost_api/export/site_data.py +196 -0
- ghost_api/export/tabular.py +88 -0
- ghost_api/export/viewer/report.html +286 -0
- ghost_api/generator/__init__.py +221 -0
- ghost_api/generator/cassettes.py +80 -0
- ghost_api/generator/models_gen.py +144 -0
- ghost_api/generator/naming.py +174 -0
- ghost_api/generator/package.py +197 -0
- ghost_api/generator/python_gen.py +172 -0
- ghost_api/generator/spec.py +486 -0
- ghost_api/generator/templates/client.py.j2 +518 -0
- ghost_api/generator/templates/client.test.ts.j2 +106 -0
- ghost_api/generator/templates/client.ts.j2 +339 -0
- ghost_api/generator/templates/models.py.j2 +45 -0
- ghost_api/generator/templates/package_readme.md.j2 +111 -0
- ghost_api/generator/templates/pyproject.toml.j2 +22 -0
- ghost_api/generator/templates/test_client.py.j2 +105 -0
- ghost_api/generator/ts_gen.py +232 -0
- ghost_api/integrations/__init__.py +0 -0
- ghost_api/integrations/claude_code/commands/ghost-data.md +10 -0
- ghost_api/integrations/claude_code/commands/ghost-diff.md +10 -0
- ghost_api/integrations/claude_code/commands/ghost-explore.md +10 -0
- ghost_api/integrations/claude_code/skills/ghost-api/SKILL.md +46 -0
- ghost_api/integrations/setup.py +84 -0
- ghost_api/llm/__init__.py +0 -0
- ghost_api/llm/doctor.py +60 -0
- ghost_api/llm/gateway.py +476 -0
- ghost_api/llm/providers.py +124 -0
- ghost_api/memory/__init__.py +0 -0
- ghost_api/memory/knowledge.py +157 -0
- ghost_api/memory/store.py +883 -0
- ghost_api/net.py +235 -0
- ghost_api/netguard.py +203 -0
- ghost_api/pipeline.py +745 -0
- ghost_api/probe/__init__.py +0 -0
- ghost_api/probe/prober.py +311 -0
- ghost_api/probe/replay.py +313 -0
- ghost_api/project.py +186 -0
- ghost_api/py.typed +0 -0
- ghost_api/runtime.py +397 -0
- ghost_api/serve/__init__.py +101 -0
- ghost_api/serve/explorer_mcp.py +305 -0
- ghost_api/serve/mcp.py +121 -0
- ghost_api/serve/mock.py +130 -0
- ghost_api/serve/rest.py +132 -0
- ghost_api/site.py +84 -0
- ghost_api/specdiff.py +122 -0
- ghost_api/ui/__init__.py +0 -0
- ghost_api/ui/keys.py +134 -0
- ghost_api/ui/repl.py +453 -0
- ghost_api/ui/terminal.py +573 -0
- ghost_api/verify/__init__.py +0 -0
- ghost_api/verify/classify.py +84 -0
- ghost_api/verify/repair.py +40 -0
- ghost_api/verify/runner.py +110 -0
- ghost_api/verify/verifier.py +291 -0
- ghost_api/watch.py +313 -0
- ghost_api/web/__init__.py +1 -0
- ghost_api/web/server.py +690 -0
- ghost_api/web/static/assets/Endpoints-zPnjlcM8.js +46 -0
- ghost_api/web/static/assets/Run-D85zWHey.js +91 -0
- ghost_api/web/static/assets/Settings-D0aWHFAt.js +11 -0
- ghost_api/web/static/assets/Site-a88shEmP.js +71 -0
- ghost_api/web/static/assets/Watches-CqZWIa9G.js +16 -0
- ghost_api/web/static/assets/circle-x-BcTE_1tr.js +11 -0
- ghost_api/web/static/assets/index-Ds2e5B9f.js +141 -0
- ghost_api/web/static/assets/index-xQpyIBbG.css +1 -0
- ghost_api/web/static/assets/minus-C2xqP1eQ.js +6 -0
- ghost_api/web/static/assets/refresh-cw-CxdR_8Oi.js +6 -0
- ghost_api/web/static/favicon.svg +1 -0
- ghost_api/web/static/index.html +26 -0
- ghost_api/workflows.py +203 -0
- ghost_api_cli-0.2.0.dist-info/METADATA +1019 -0
- ghost_api_cli-0.2.0.dist-info/RECORD +125 -0
- ghost_api_cli-0.2.0.dist-info/WHEEL +5 -0
- ghost_api_cli-0.2.0.dist-info/entry_points.txt +2 -0
- ghost_api_cli-0.2.0.dist-info/licenses/LICENSE +21 -0
- ghost_api_cli-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1019 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ghost-api-cli
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: An AI agent that turns any website into a typed, tested API client.
|
|
5
|
+
Author: Danielraj
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Danielraj5605/Ghost-api
|
|
8
|
+
Project-URL: Documentation, https://github.com/Danielraj5605/Ghost-api#readme
|
|
9
|
+
Project-URL: Changelog, https://github.com/Danielraj5605/Ghost-api/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Issues, https://github.com/Danielraj5605/Ghost-api/issues
|
|
11
|
+
Project-URL: Security, https://github.com/Danielraj5605/Ghost-api/blob/main/SECURITY.md
|
|
12
|
+
Keywords: api,reverse-engineering,api-client,openapi,code-generation,playwright,ai-agent,llm,web-scraping,sdk-generator
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
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 :: Code Generators
|
|
22
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: playwright>=1.45
|
|
28
|
+
Requires-Dist: httpx>=0.27
|
|
29
|
+
Requires-Dist: pydantic>=2.7
|
|
30
|
+
Requires-Dist: typer>=0.12
|
|
31
|
+
Requires-Dist: rich>=13.7
|
|
32
|
+
Requires-Dist: python-dotenv>=1.0
|
|
33
|
+
Requires-Dist: genson>=1.3
|
|
34
|
+
Requires-Dist: jinja2>=3.1
|
|
35
|
+
Requires-Dist: pyyaml>=6.0
|
|
36
|
+
Requires-Dist: fastapi>=0.110
|
|
37
|
+
Requires-Dist: uvicorn>=0.29
|
|
38
|
+
Requires-Dist: openpyxl>=3.1
|
|
39
|
+
Requires-Dist: prompt_toolkit>=3.0.43
|
|
40
|
+
Provides-Extra: mcp
|
|
41
|
+
Requires-Dist: mcp>=1.2; extra == "mcp"
|
|
42
|
+
Provides-Extra: notify
|
|
43
|
+
Requires-Dist: plyer>=2.1; extra == "notify"
|
|
44
|
+
Provides-Extra: docs
|
|
45
|
+
Requires-Dist: mkdocs<2,>=1.6; extra == "docs"
|
|
46
|
+
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
|
|
47
|
+
Provides-Extra: dev
|
|
48
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
49
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
50
|
+
Requires-Dist: mypy>=1.11; extra == "dev"
|
|
51
|
+
Requires-Dist: openapi-spec-validator>=0.7; extra == "dev"
|
|
52
|
+
Requires-Dist: types-PyYAML; extra == "dev"
|
|
53
|
+
Requires-Dist: psutil>=5.9; extra == "dev"
|
|
54
|
+
Requires-Dist: types-psutil; extra == "dev"
|
|
55
|
+
Requires-Dist: pywinpty>=2.0; sys_platform == "win32" and extra == "dev"
|
|
56
|
+
Dynamic: license-file
|
|
57
|
+
|
|
58
|
+
# Ghost API
|
|
59
|
+
|
|
60
|
+
**An AI agent that turns any website into a typed, tested API client.**
|
|
61
|
+
|
|
62
|
+
Give Ghost API a website and a plain-English goal. It opens the site in a real browser, watches the hidden requests the site makes to its own server, works out how that hidden API behaves, and writes a clean Python (or TypeScript) client library for it, with tests.
|
|
63
|
+
|
|
64
|
+

|
|
65
|
+
|
|
66
|
+
<sub>A real run on quotes.toscrape.com from the web dashboard (`ghost-api ui`): the agent loads the page, the API call is tested, a client is generated and verified, and "Try it" calls the endpoint. 2 free LLM calls, about 20 seconds.</sub>
|
|
67
|
+
|
|
68
|
+
> **Status:** Version 0.2.0. All 11 build stages are done and evaluated on four sites (see [Evaluation](#evaluation)): every goal endpoint found, nothing invented, every generated client test passing, for 1–10 free LLM calls per site. It has a live terminal UI, a local web dashboard and a shareable one-file HTML report. See [IMPLEMENTATION.md](IMPLEMENTATION.md) for how it was built.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
**Documentation:** guides, the command reference and the Python API are in [docs/](docs/index.md)
|
|
73
|
+
(build the site with `pip install -e ".[docs]"` then `mkdocs serve`).
|
|
74
|
+
|
|
75
|
+
## Table of contents
|
|
76
|
+
|
|
77
|
+
- [The simple explanation](#the-simple-explanation)
|
|
78
|
+
- [The problem](#the-problem)
|
|
79
|
+
- [What Ghost API does](#what-ghost-api-does)
|
|
80
|
+
- [Example](#example)
|
|
81
|
+
- [How it works](#how-it-works)
|
|
82
|
+
- [Why it's an agent, not a script](#why-its-an-agent-not-a-script)
|
|
83
|
+
- [Memory](#memory)
|
|
84
|
+
- [Features](#features)
|
|
85
|
+
- [Tech stack](#tech-stack)
|
|
86
|
+
- [Getting started](#getting-started)
|
|
87
|
+
- [What can I do with it?](#what-can-i-do-with-it)
|
|
88
|
+
- [Three ways to see the results](#three-ways-to-see-the-results)
|
|
89
|
+
- [Usage](#usage)
|
|
90
|
+
- [Output](#output)
|
|
91
|
+
- [Project structure](#project-structure)
|
|
92
|
+
- [Running on free LLM tiers](#running-on-free-llm-tiers)
|
|
93
|
+
- [Responsible use](#responsible-use)
|
|
94
|
+
- [Evaluation](#evaluation)
|
|
95
|
+
- [Limitations](#limitations)
|
|
96
|
+
- [Roadmap](#roadmap)
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## The simple explanation
|
|
101
|
+
|
|
102
|
+
Picture a restaurant with **no menu**. You can eat there, but only by pointing at other people's plates. Behind the scenes, every time someone orders, the waiter hands the kitchen a neat order slip:
|
|
103
|
+
|
|
104
|
+
> "Table 4: 1x Pasta, no cheese, large."
|
|
105
|
+
|
|
106
|
+
The kitchen understands those slips perfectly. You just never see them.
|
|
107
|
+
|
|
108
|
+
**Ghost API sits in the restaurant, watches every order slip going to the kitchen, and writes the menu for you.** After that you can order directly, without pointing at plates.
|
|
109
|
+
|
|
110
|
+
| In the analogy | In real life |
|
|
111
|
+
|---|---|
|
|
112
|
+
| The restaurant | Any website (a bookstore, a weather site, a job board) |
|
|
113
|
+
| Pointing at plates | Copying data by hand, or fragile "scraper" programs that break when the design changes |
|
|
114
|
+
| The order slips | The hidden requests a website makes to its own server |
|
|
115
|
+
| The menu | A small code library that gets the data directly, cleanly and reliably |
|
|
116
|
+
|
|
117
|
+
**What makes it "AI":** Ghost API doesn't just record. Like a curious person, it:
|
|
118
|
+
|
|
119
|
+
1. **Explores** the site by clicking, searching and scrolling
|
|
120
|
+
2. **Notices patterns**, such as "every time I open a book, the site asks for `/books/<number>`"
|
|
121
|
+
3. **Tests its guesses**, such as "if I ask for page 2, do I get different results?"
|
|
122
|
+
4. **Fixes its mistakes** when a guess turns out wrong
|
|
123
|
+
5. **Remembers** what it learned, so next time is faster
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## The problem
|
|
128
|
+
|
|
129
|
+
Almost every modern website loads its data through a **hidden internal API**. When you open a product page, your browser quietly calls something like:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
GET https://shop.example.com/api/v2/products/123?include=reviews
|
|
133
|
+
-> { "id": 123, "name": "Blue Shoes", "price": 59.99, "reviews": [...] }
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Developers often want that data in their own code. Their options today are poor:
|
|
137
|
+
|
|
138
|
+
| Approach | Why it's poor |
|
|
139
|
+
|---|---|
|
|
140
|
+
| Scrape the HTML | Breaks whenever the page layout changes, and is slow |
|
|
141
|
+
| Reverse-engineer by hand in browser DevTools | Takes hours: clicking around, copying requests, guessing what each field means |
|
|
142
|
+
| Tools like mitmproxy or Postman | Record raw traffic, but don't understand it or write any code |
|
|
143
|
+
|
|
144
|
+
No existing tool both **discovers** these hidden APIs and **produces working code** for them.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## What Ghost API does
|
|
149
|
+
|
|
150
|
+
| Input | Output |
|
|
151
|
+
|---|---|
|
|
152
|
+
| A website URL | A typed Python client library (`httpx` + `pydantic`) |
|
|
153
|
+
| A plain-English goal ("search books and get details") | A pytest test suite that runs against the live site |
|
|
154
|
+
| | An OpenAPI 3 spec |
|
|
155
|
+
| | A report showing what was found, how confident it is, and the agent's reasoning |
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Example
|
|
160
|
+
|
|
161
|
+
Real output from the practice site `quotes.toscrape.com/scroll` (abridged):
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
$ ghost-api run https://quotes.toscrape.com/scroll --goal "list quotes with their authors and tags"
|
|
165
|
+
|
|
166
|
+
Exploring site...
|
|
167
|
+
GET 200 /api/quotes?page=1
|
|
168
|
+
Step 1 finish(goal_covered=True) The discovered endpoint already returns quotes, their authors, and tags
|
|
169
|
+
|
|
170
|
+
Testing 1 endpoint(s) with direct calls...
|
|
171
|
+
GET /api/quotes
|
|
172
|
+
confirmed can be called directly, outside the browser HTTP 200, 10 records
|
|
173
|
+
confirmed paginates with page parameter 'page' the next page returned 10 different records
|
|
174
|
+
confirmed needs none of its custom headers or cookies
|
|
175
|
+
|
|
176
|
+
Verifying the generated client against the live API...
|
|
177
|
+
Round 1: 2 passed
|
|
178
|
+
|
|
179
|
+
Generated QuotesToscrapeClient in output/quotes.toscrape.com
|
|
180
|
+
get_quotes() -> QuotesResponse + iter_get_quotes()
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The generated client:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from quotes_toscrape_client import QuotesToscrapeClient
|
|
187
|
+
|
|
188
|
+
with QuotesToscrapeClient() as api:
|
|
189
|
+
page = api.get_quotes() # -> QuotesResponse (pydantic)
|
|
190
|
+
print(page.quotes[0].author.name) # nested models: Quote, Author
|
|
191
|
+
for p in api.iter_get_quotes(max_pages=3): # pagination handled for you
|
|
192
|
+
...
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The same client in TypeScript (`--lang typescript`):
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import { QuotesToscrapeClient } from "./quotes_toscrape_client.ts";
|
|
199
|
+
|
|
200
|
+
const api = new QuotesToscrapeClient();
|
|
201
|
+
const page = await api.getQuotes(); // Promise<QuotesResponse>
|
|
202
|
+
for await (const p of api.iterGetQuotes({ maxPages: 3 })) console.log(p.page);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
The TypeScript client is made for **Node 18+** (servers, scripts, serverless functions). In a
|
|
206
|
+
web page it mostly won't work: browsers block reading another site's replies unless that site
|
|
207
|
+
allows it (CORS), and they don't let code set the identifying User-Agent header. For a web
|
|
208
|
+
app, call the client from your own small server and let the page call that:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
// server.ts (Node): the page calls /api/quotes on your server, your server calls the site.
|
|
212
|
+
import { createServer } from "node:http";
|
|
213
|
+
import { QuotesToscrapeClient } from "./quotes_toscrape_client.ts";
|
|
214
|
+
|
|
215
|
+
const api = new QuotesToscrapeClient();
|
|
216
|
+
createServer(async (req, res) => {
|
|
217
|
+
if (req.url !== "/api/quotes") return void res.writeHead(404).end();
|
|
218
|
+
res.setHeader("Content-Type", "application/json");
|
|
219
|
+
res.end(JSON.stringify(await api.getQuotes()));
|
|
220
|
+
}).listen(3000);
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
A harder case: on `hn.algolia.com` the agent switched the search filter to "Comments", found
|
|
224
|
+
that the real API is a POST to Algolia's servers (a third-party domain), and the prober
|
|
225
|
+
confirmed that paging works in the JSON body and that the `x-algolia-api-key` URL parameter
|
|
226
|
+
is required (HTTP 403 without it). The client it generated:
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from hn_algolia_client import HnAlgoliaClient # key from HN_ALGOLIA_X_ALGOLIA_API_KEY
|
|
230
|
+
|
|
231
|
+
with HnAlgoliaClient() as api:
|
|
232
|
+
results = api.search_stories(index="Item_dev", query="python") # -> SearchResults
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## How it works
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
+---------------------+
|
|
241
|
+
| START |
|
|
242
|
+
| URL + goal + lang |
|
|
243
|
+
+----------+----------+
|
|
244
|
+
v
|
|
245
|
+
+---------------------+
|
|
246
|
+
| 0. PRE-CHECKS |
|
|
247
|
+
| robots.txt, memory |---- known site? ---> load past
|
|
248
|
+
| lookup, budgets | knowledge
|
|
249
|
+
+----------+----------+
|
|
250
|
+
v
|
|
251
|
+
+----------------------------------------------------+
|
|
252
|
+
| AGENT LOOP |
|
|
253
|
+
| 1. OBSERVE page snapshot + captured traffic |
|
|
254
|
+
| 2. DECIDE LLM picks: explore / test / ask / |
|
|
255
|
+
| finish |
|
|
256
|
+
| 3. ACT run a tool (click, type, call API) |
|
|
257
|
+
| 4. LEARN update endpoint map + schemas |
|
|
258
|
+
| goal covered? budget left? --no--> back to 1 |
|
|
259
|
+
+----------+-----------------------------------------+
|
|
260
|
+
| yes
|
|
261
|
+
v
|
|
262
|
+
+---------------------+
|
|
263
|
+
| 5. GENERATE CODE | client + models + tests
|
|
264
|
+
+----------+----------+
|
|
265
|
+
v
|
|
266
|
+
+---------------------+ fail +--------------+
|
|
267
|
+
| 6. VERIFY (tests) |--------------->| 7. DIAGNOSE |--> back to
|
|
268
|
+
+----------+----------+ | & REPLAN | agent loop
|
|
269
|
+
| pass +--------------+ (max 3x)
|
|
270
|
+
v
|
|
271
|
+
+---------------------+
|
|
272
|
+
| 8. SAVE MEMORY + |
|
|
273
|
+
| WRITE REPORT |
|
|
274
|
+
+---------------------+
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Step by step
|
|
278
|
+
|
|
279
|
+
**0. Pre-checks.** It reads `robots.txt`, looks the domain up in memory, and sets budgets (maximum LLM calls, steps and minutes).
|
|
280
|
+
|
|
281
|
+
**1. Observe.** The agent gets a compact view of the page: the clickable elements and inputs with short IDs (such as `[12] button "Search"`), a summary of the new network requests, the endpoints found so far, and which parts of the goal are still uncovered.
|
|
282
|
+
|
|
283
|
+
**2. Decide.** The LLM picks **one** action and explains why:
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"thought": "I found the book list endpoint but not book details. Clicking a book should trigger it.",
|
|
288
|
+
"action": "click",
|
|
289
|
+
"args": { "element_id": 23 }
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**3. Act.** The chosen tool runs: click, type, scroll, navigate, call an endpoint directly, ask the user, or finish.
|
|
294
|
+
|
|
295
|
+
**4. Learn.** Ordinary code, not the LLM, processes the traffic:
|
|
296
|
+
- Filters out noise (images, CSS, fonts, analytics, ads)
|
|
297
|
+
- Groups URLs into templates: `/api/books/123` and `/api/books/456` become `/api/books/{id}`
|
|
298
|
+
- Infers JSON schemas from real responses and merges them across samples
|
|
299
|
+
- Classifies query parameters as required, optional or constant
|
|
300
|
+
|
|
301
|
+
**5. Generate.** The LLM gives endpoints and fields readable names. Jinja2 templates produce the client, pydantic models, tests and an OpenAPI spec.
|
|
302
|
+
|
|
303
|
+
**6. Verify.** The generated tests run against the live site and check that each response matches its schema.
|
|
304
|
+
|
|
305
|
+
**7. Diagnose and replan.** If a test fails, the agent works out why and recovers:
|
|
306
|
+
|
|
307
|
+
| Failure | Likely cause | Agent's response |
|
|
308
|
+
|---|---|---|
|
|
309
|
+
| 401 or 403 | Missing cookie, token or header | Retry with the browser's cookies, then find which header is required |
|
|
310
|
+
| Schema mismatch | Too few samples | Explore more, then widen the schema |
|
|
311
|
+
| 404 | Wrong URL template | Re-check how the URL was grouped |
|
|
312
|
+
| 429 | Rate limited | Back off and slow down |
|
|
313
|
+
| Timeout | Slow endpoint | Retry, then mark as unstable |
|
|
314
|
+
|
|
315
|
+
**8. Save and report.** It saves what it learned to memory and writes `report.md`.
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Why it's an agent, not a script
|
|
320
|
+
|
|
321
|
+
A fixed script can record traffic. Ghost API has to **make decisions**:
|
|
322
|
+
|
|
323
|
+
| Decision | Example |
|
|
324
|
+
|---|---|
|
|
325
|
+
| Where to explore next | "I've found search but not reviews. Click the reviews tab." |
|
|
326
|
+
| When it has seen enough | "Three similar responses. The schema is stable, so stop." |
|
|
327
|
+
| Which guesses to test | "This looks like cursor pagination, not page numbers. Test it." |
|
|
328
|
+
| How to recover from failure | "Direct call returned 403. Retry with the browser's cookies." |
|
|
329
|
+
| When to ask you | "This needs a login. Please log in in the browser window, then press Enter." |
|
|
330
|
+
|
|
331
|
+
**Design principle:** the LLM decides and names things. Deterministic code does the heavy lifting: capture, grouping, schema inference and code generation. This keeps it cheap, fast, and reliable even with small free models.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Memory
|
|
336
|
+
|
|
337
|
+
Ghost API improves with use:
|
|
338
|
+
|
|
339
|
+
- **Per-site memory:** endpoints, schemas, auth style and pagination style for each domain. A second run re-verifies instead of re-exploring.
|
|
340
|
+
- **Lessons learned:** notes such as "this site needs the X-CSRF header" are fed back into the prompt on later runs.
|
|
341
|
+
- **LLM cache:** identical prompts return cached answers, which saves free-tier quota.
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Features
|
|
346
|
+
|
|
347
|
+
- **One command:** URL and goal in; endpoint map, typed client, tests, report and OpenAPI spec out
|
|
348
|
+
- **AI exploration** in a real browser (Playwright), one decision per step, with live reasoning
|
|
349
|
+
- **Capture** of the site's JSON API traffic, including third-party APIs (for example Algolia),
|
|
350
|
+
with analytics, health checks and infrastructure filtered out
|
|
351
|
+
- **Redaction** of cookies, tokens and keys before anything is stored, logged or sent to an LLM
|
|
352
|
+
- **Analysis:** URL templates (`/books/{id}`), parameter types, merged JSON schemas
|
|
353
|
+
- **Hypothesis testing** by direct calls: pagination (page, offset, cursor), required headers,
|
|
354
|
+
API keys, auth style
|
|
355
|
+
- **Python client** with pydantic models, rate limiting, retries, credentials from env vars and
|
|
356
|
+
`iter_...()` helpers for pagination; passes `mypy --strict`
|
|
357
|
+
- **Verification:** the generated tests run against the live API; failures are diagnosed and
|
|
358
|
+
repaired (up to 3 rounds), and every endpoint is marked verified, unverified or failed
|
|
359
|
+
- **Memory:** `refresh` re-checks a known site with as little work as possible
|
|
360
|
+
- **Report and OpenAPI 3.1** export, plus a replayable log of every run
|
|
361
|
+
- **Free:** runs on free LLM tiers with fallback between providers, caching and budgets
|
|
362
|
+
- **Live terminal UI** in the style of Claude Code: phase stepper, compact step log, a status
|
|
363
|
+
line that updates in place, and a summary card with a copy-paste "use it" line
|
|
364
|
+
- **Web dashboard** (`ghost-api ui`): start runs, watch the agent's browser and reasoning live,
|
|
365
|
+
browse endpoints with their schemas, call them with "Try it", read and download the code
|
|
366
|
+
- **Shareable report:** every run writes `report.html`, one file that works offline
|
|
367
|
+
- **Data download, no code:** `ghost-api fetch` and the dashboard's Download data:
|
|
368
|
+
all pages to CSV, Excel or JSON
|
|
369
|
+
- **Watch & alerts:** new / changed / gone items, to your phone, a webhook or the desktop
|
|
370
|
+
- **REST and MCP servers:** use sites from Excel, any language, or an AI assistant
|
|
371
|
+
- **Personal-data leak check:** spots and hides emails, phones, PAN/GST/Aadhaar, UPI and
|
|
372
|
+
bank details, and reports which endpoints expose them
|
|
373
|
+
|
|
374
|
+
- **TypeScript client** too (`--lang typescript`): interfaces, a fetch-based client for Node 18+
|
|
375
|
+
(for web pages, call it from your own server), async page iterators, and Node tests; passes
|
|
376
|
+
`tsc --strict`
|
|
377
|
+
|
|
378
|
+
- **GraphQL:** each named operation becomes its own typed method (`get_user(id)`), with the
|
|
379
|
+
query built in and the variables as arguments; mutations are never replayed or generated
|
|
380
|
+
|
|
381
|
+
**Not yet:** WebSocket and server-sent-event APIs.
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Tech stack
|
|
386
|
+
|
|
387
|
+
| Part | Tool |
|
|
388
|
+
|---|---|
|
|
389
|
+
| Language | Python 3.11+ |
|
|
390
|
+
| Browser automation | Playwright (Chromium) |
|
|
391
|
+
| LLM access | Small built-in gateway over the OpenAI-compatible APIs of Gemini (main), Groq and OpenRouter (fallbacks) |
|
|
392
|
+
| HTTP | httpx |
|
|
393
|
+
| Data models | pydantic |
|
|
394
|
+
| Schema inference | genson |
|
|
395
|
+
| Code generation | Jinja2 |
|
|
396
|
+
| CLI and terminal UI | Typer + Rich |
|
|
397
|
+
| Web dashboard | FastAPI + uvicorn (local server), React + Vite + Tailwind CSS (frontend, prebuilt) |
|
|
398
|
+
| Tests | pytest |
|
|
399
|
+
| Storage | SQLite |
|
|
400
|
+
|
|
401
|
+
Runs on an ordinary laptop: 8 GB RAM, no GPU.
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Getting started
|
|
406
|
+
|
|
407
|
+
**You need:** Python 3.11+ and, for the AI agent, one free LLM key from
|
|
408
|
+
[Google AI Studio](https://aistudio.google.com/apikey) (Gemini), [Groq](https://console.groq.com/keys)
|
|
409
|
+
or [OpenRouter](https://openrouter.ai/keys). Without a key, runs still load and scroll pages
|
|
410
|
+
and map what they see (`--no-agent`).
|
|
411
|
+
|
|
412
|
+
**1. Install** (once; any OS). [pipx](https://pipx.pypa.io) or [uv](https://docs.astral.sh/uv/)
|
|
413
|
+
put the `ghost-api` command on your PATH in its own environment:
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
pipx install git+https://github.com/Danielraj5605/Ghost-api
|
|
417
|
+
# or: uv tool install git+https://github.com/Danielraj5605/Ghost-api
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
(After the first PyPI release this becomes `pipx install ghost-api-cli`.)
|
|
421
|
+
|
|
422
|
+
**2. Set up a folder** for your work. `init` creates the project file, downloads the
|
|
423
|
+
browser Ghost API drives (Chromium, about 150 MB, once), asks for an LLM key (optional,
|
|
424
|
+
typed hidden, saved in `.env`) and keeps keys and data out of git:
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
mkdir my-apis && cd my-apis
|
|
428
|
+
ghost-api init
|
|
429
|
+
ghost-api doctor # checks Python, Chromium, the project and each key
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**3. Explore a site:**
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
ghost-api run https://quotes.toscrape.com/scroll --goal "list quotes with their authors"
|
|
436
|
+
ghost-api # or the interactive session: paste a site, say what you want
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### With Claude Code (no LLM key needed)
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
ghost-api integrate claude-code # also: cursor, vscode, desktop
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Then in Claude Code: `/ghost-explore https://quotes.toscrape.com/scroll quotes with authors`.
|
|
446
|
+
Claude reads each page and decides what to click; Ghost API acts under its rules, maps the
|
|
447
|
+
hidden API, tests every endpoint, and writes the typed client, report and OpenAPI spec. In a
|
|
448
|
+
test on the demo shop, Claude mapped all five endpoints (all verified) in 12 turns. Claude
|
|
449
|
+
alone found them too (7 turns): on easy sites Ghost API's value is what comes after, such as
|
|
450
|
+
checking the live API again in seconds with no LLM, offline tests, change detection, rules and
|
|
451
|
+
an audit trail. Measured in [docs/benchmark.md](docs/benchmark.md).
|
|
452
|
+
Real runs on public practice sites: [docs/gallery.md](docs/gallery.md).
|
|
453
|
+
|
|
454
|
+
### From Python
|
|
455
|
+
|
|
456
|
+
Everything the command does is also a function, with the same rules:
|
|
457
|
+
|
|
458
|
+
```python
|
|
459
|
+
from ghost_api.api import discover, fetch, diff
|
|
460
|
+
|
|
461
|
+
result = discover("https://quotes.toscrape.com/scroll", "list quotes with their authors")
|
|
462
|
+
print(result.status, [e["path"] for e in result.endpoints], result.client_files)
|
|
463
|
+
|
|
464
|
+
rows = fetch("quotes.toscrape.com/scroll", "get_quotes", pages=3) # list of records
|
|
465
|
+
changes = diff("quotes.toscrape.com/scroll", live=True) # breaking or not
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
Also `refresh`, `generate`, `operations` and `sites`. Errors are exceptions you can catch:
|
|
469
|
+
`NotAllowed` (robots.txt), `NoLLMKey`, `NothingRemembered`, `GhostApiError`.
|
|
470
|
+
|
|
471
|
+
### Project settings
|
|
472
|
+
|
|
473
|
+
`ghost-api init` writes `ghost-api.toml`. Every command run in that folder, or any folder
|
|
474
|
+
below it, uses the project's database and output folder, and its defaults:
|
|
475
|
+
|
|
476
|
+
```toml
|
|
477
|
+
[project]
|
|
478
|
+
database = ".ghost-api/ghost_api.db" # runs, traffic, endpoints (keep it private)
|
|
479
|
+
output = "output" # reports, clients, downloads
|
|
480
|
+
|
|
481
|
+
[defaults] # any command option, by name
|
|
482
|
+
lang = "typescript"
|
|
483
|
+
rate_limit = 0.5
|
|
484
|
+
max_steps = 30
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Options on the command line win over the file, and `GHOST_API_DB` wins over both. Keys are
|
|
488
|
+
read from `.env` in the current folder, the project folder, then `~/.ghost-api/.env`
|
|
489
|
+
(handy for one set of keys everywhere).
|
|
490
|
+
|
|
491
|
+
### Scripts and CI: `--json` and exit codes
|
|
492
|
+
|
|
493
|
+
Add `--json` anywhere on a command to get its result as JSON on stdout; progress and
|
|
494
|
+
messages go to stderr, so it pipes cleanly:
|
|
495
|
+
|
|
496
|
+
```bash
|
|
497
|
+
ghost-api run https://quotes.toscrape.com/scroll -g "list quotes" --no-agent --json > run.json
|
|
498
|
+
ghost-api inspect quotes.toscrape.com/scroll --json | jq '.endpoints[].path'
|
|
499
|
+
ghost-api fetch quotes.toscrape.com/scroll get_quotes --pages 3 --json | jq '.rows'
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
| Exit code | Meaning |
|
|
503
|
+
|---|---|
|
|
504
|
+
| 0 | Done (a run may still have found nothing; check the JSON or report) |
|
|
505
|
+
| 1 | Failed: an error, failed checks, or nothing stored to work on |
|
|
506
|
+
| 2 | Wrong command line or setup: bad option, missing LLM key, unreadable `ghost-api.toml` |
|
|
507
|
+
| 3 | The site said no: robots.txt disallows it, or a bot-protection page |
|
|
508
|
+
| 130 | Stopped with Ctrl+C |
|
|
509
|
+
|
|
510
|
+
### From source (contributors)
|
|
511
|
+
|
|
512
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the developer setup. In short, pick the block for
|
|
513
|
+
your terminal (no Node.js needed: the dashboard comes prebuilt):
|
|
514
|
+
|
|
515
|
+
**Windows, Command Prompt (cmd)**
|
|
516
|
+
|
|
517
|
+
```bat
|
|
518
|
+
git clone https://github.com/Danielraj5605/Ghost-api ghost-api
|
|
519
|
+
cd ghost-api
|
|
520
|
+
python -m venv .venv
|
|
521
|
+
.venv\Scripts\activate.bat
|
|
522
|
+
pip install -e .
|
|
523
|
+
playwright install chromium
|
|
524
|
+
copy .env.example .env
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Windows, PowerShell**
|
|
528
|
+
|
|
529
|
+
```powershell
|
|
530
|
+
git clone https://github.com/Danielraj5605/Ghost-api ghost-api
|
|
531
|
+
cd ghost-api
|
|
532
|
+
python -m venv .venv
|
|
533
|
+
.venv\Scripts\Activate.ps1
|
|
534
|
+
pip install -e .
|
|
535
|
+
playwright install chromium
|
|
536
|
+
Copy-Item .env.example .env
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
If PowerShell says running scripts is disabled, run
|
|
540
|
+
`Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` once, or use Command Prompt.
|
|
541
|
+
|
|
542
|
+
**macOS / Linux**
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
git clone https://github.com/Danielraj5605/Ghost-api ghost-api
|
|
546
|
+
cd ghost-api
|
|
547
|
+
python3 -m venv .venv
|
|
548
|
+
source .venv/bin/activate
|
|
549
|
+
pip install -e .
|
|
550
|
+
playwright install chromium
|
|
551
|
+
cp .env.example .env
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
Then put at least one key in `.env` and check it:
|
|
555
|
+
|
|
556
|
+
```bash
|
|
557
|
+
ghost-api doctor # checks each key with one tiny call
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
You'll know the environment is active when your prompt starts with `(.venv)`. Use
|
|
561
|
+
`pip install -e ".[dev]"` instead if you want the tests and linters. If the `ghost-api`
|
|
562
|
+
command is blocked or not found, `python -m ghost_api` does the same thing
|
|
563
|
+
(for example `python -m ghost_api doctor`).
|
|
564
|
+
|
|
565
|
+
**Run it from any folder (Windows).** To start Ghost API by just typing `ghost-api` in
|
|
566
|
+
any Command Prompt or PowerShell window, the way you start `claude`, run this once from
|
|
567
|
+
the project folder:
|
|
568
|
+
|
|
569
|
+
```bat
|
|
570
|
+
scripts\install-command.cmd
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
It adds a small `ghost-api` launcher to `%USERPROFILE%\.local\bin` (and puts that folder
|
|
574
|
+
on your PATH if needed). The launcher uses the project's virtual environment, so there's
|
|
575
|
+
nothing to activate, and always works with the project's `.env`, memory and `output\`
|
|
576
|
+
folder. Then open a new window and type `ghost-api` (it asks for a website and a goal),
|
|
577
|
+
`ghost-api ui` for the dashboard, or any command below. On macOS/Linux, `pipx install -e .`
|
|
578
|
+
does the same job.
|
|
579
|
+
|
|
580
|
+
What `.env` looks like:
|
|
581
|
+
|
|
582
|
+
```
|
|
583
|
+
GEMINI_API_KEY=your_key_here
|
|
584
|
+
GROQ_API_KEY=optional_fallback_key
|
|
585
|
+
OPENROUTER_API_KEY=optional_second_fallback
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
## What can I do with it?
|
|
591
|
+
|
|
592
|
+
Ghost API first learns a website's hidden API (`ghost-api run ...`). After that, you can use
|
|
593
|
+
what it learned in five ways, most of them without writing any code:
|
|
594
|
+
|
|
595
|
+
| I want to... | Do this |
|
|
596
|
+
|---|---|
|
|
597
|
+
| **Get the data in a spreadsheet** | `ghost-api fetch turftown.in/chennai get_nearby_venues area=velachery sport=football --format xlsx` follows all the pages and saves an Excel, CSV or JSON file. In the dashboard: open an endpoint and press **Download data**. `ghost-api fetch SITE` lists what you can fetch. |
|
|
598
|
+
| **Know when something changes** | `ghost-api watch add quotes.toscrape.com list_quotes --every 6h --notify ntfy:my-long-private-topic` re-checks on a schedule and tells you what's new, what changed (a price, a name...) and what's gone, on your phone ([ntfy](https://ntfy.sh)), a webhook (Discord, Slack...) or a desktop notification. `ghost-api watch schedule` keeps it running in the background on Windows. Dashboard: **Watch this for changes**, and the **Watches** page. |
|
|
599
|
+
| **Use it from Excel, scripts or any language** | `ghost-api serve turftown.in/chennai` gives every endpoint a clean local URL, e.g. `http://127.0.0.1:8900/turftown.in~chennai/get_nearby_venues?area=velachery&format=csv`, with interactive docs at `/docs`. |
|
|
600
|
+
| **Let an AI assistant use the site** | `claude mcp add ghost-turftown -- ghost-api mcp turftown.in/chennai` (after `pip install -e ".[mcp]"`). Claude can then answer "cheapest football turfs near Velachery?" by calling the site's endpoints itself. |
|
|
601
|
+
| **Check a site for personal-data leaks** | Every run looks for emails, phone numbers, PAN/GST/Aadhaar numbers, UPI IDs and bank details in the replies. They are **hidden** before anything is stored, and the report, the terminal and the dashboard say which endpoints hand them out, and whether a login is needed. Use it on your own site, or one you're allowed to test. |
|
|
602
|
+
| **Write code with it** | Use the generated, tested Python or TypeScript client (see [Output](#output)), or the examples in [`examples/`](examples). |
|
|
603
|
+
|
|
604
|
+
All of these only **read** data: they go through the same rules as the explorer (robots.txt,
|
|
605
|
+
one request per second, nothing that looks like it changes data unless you say
|
|
606
|
+
`generate --allow "POST /path"` or press "I checked: it only reads" in the dashboard), and
|
|
607
|
+
they keep personal data hidden unless you pass `--include-sensitive` for your own site.
|
|
608
|
+
|
|
609
|
+
---
|
|
610
|
+
|
|
611
|
+
## Three ways to see the results
|
|
612
|
+
|
|
613
|
+
**1. The terminal.** Type `ghost-api` and a session opens, like Claude Code or Gemini CLI.
|
|
614
|
+
Paste a website and what you want ("quotes.toscrape.com/scroll list quotes with their
|
|
615
|
+
authors"), watch each phase and agent step as it happens, and get a summary card with
|
|
616
|
+
**clickable links** to the report and the files (Ctrl+click in Windows Terminal or VS Code;
|
|
617
|
+
the full `file:///` link is shown either way). Then keep going: `/fetch` the data, `/watch
|
|
618
|
+
add` alerts, `/open` the report, or paste another site. The session stays open until you
|
|
619
|
+
type `/exit` or press **Ctrl+C twice**; a single Ctrl+C only stops what's running. `/help`
|
|
620
|
+
lists the commands, Tab completes them, and the arrow keys bring back earlier lines.
|
|
621
|
+
`ghost-api run ...` still does a single run, and `--plain` gives simple lines for logs.
|
|
622
|
+
|
|
623
|
+

|
|
624
|
+
|
|
625
|
+
**2. The web dashboard.** `ghost-api ui` opens it in your browser (local only, at
|
|
626
|
+
`http://127.0.0.1:8800`). Start a run, watch the agent's browser and reasoning live, then
|
|
627
|
+
browse everything it found. Every past run can be replayed.
|
|
628
|
+
|
|
629
|
+
| Start a run | Watch it live |
|
|
630
|
+
|---|---|
|
|
631
|
+
|  |  |
|
|
632
|
+
| **Endpoints and their fields** | **"Try it": call an endpoint with your own parameters** |
|
|
633
|
+
|  |  |
|
|
634
|
+
| **The generated client** | **On a phone** |
|
|
635
|
+
|  | <img src="https://raw.githubusercontent.com/Danielraj5605/Ghost-api/main/docs/images/dashboard-phone.png" alt="The site page on a phone" width="260"> |
|
|
636
|
+
|
|
637
|
+
"Try it" only calls endpoints that read data. Anything that looks like it changes data
|
|
638
|
+
(add to cart, delete, update...) is refused.
|
|
639
|
+
|
|
640
|
+
**3. The shareable report.** Every run writes `output/<site>/report.html`: one file with
|
|
641
|
+
the endpoints, the run's activity, the generated code, the OpenAPI spec and the summary. It
|
|
642
|
+
works offline and needs no server, so you can email it or attach it to an issue. Example
|
|
643
|
+
values of sensitive parameters (keys, tokens) are left out.
|
|
644
|
+
|
|
645
|
+

|
|
646
|
+
|
|
647
|
+
---
|
|
648
|
+
|
|
649
|
+
## Usage
|
|
650
|
+
|
|
651
|
+
```bash
|
|
652
|
+
# Basic run
|
|
653
|
+
ghost-api run https://quotes.toscrape.com/scroll --goal "list quotes with their authors and tags"
|
|
654
|
+
|
|
655
|
+
# Watch the browser while it works
|
|
656
|
+
ghost-api run https://quotes.toscrape.com/scroll --goal "list quotes" --headed
|
|
657
|
+
|
|
658
|
+
# Tighter budget
|
|
659
|
+
ghost-api run https://example.com --goal "search products" --max-llm-calls 30 --max-steps 25
|
|
660
|
+
|
|
661
|
+
# Re-check a known site from memory: replay first, browse only if needed
|
|
662
|
+
ghost-api refresh quotes.toscrape.com
|
|
663
|
+
ghost-api refresh quotes.toscrape.com --no-llm # never call the LLM
|
|
664
|
+
|
|
665
|
+
# Show what's stored for a site, or replay one run step by step
|
|
666
|
+
ghost-api inspect quotes.toscrape.com
|
|
667
|
+
ghost-api inspect --run 12
|
|
668
|
+
|
|
669
|
+
# Write report.md, report.html and openapi.yaml from stored data
|
|
670
|
+
ghost-api report quotes.toscrape.com
|
|
671
|
+
|
|
672
|
+
# Regenerate the client from stored data (no browser; --no-llm skips the naming call)
|
|
673
|
+
ghost-api generate quotes.toscrape.com
|
|
674
|
+
ghost-api generate quotes.toscrape.com --lang typescript # TypeScript instead
|
|
675
|
+
# Include a POST endpoint you checked only reads data (Ghost API skips those by itself)
|
|
676
|
+
ghost-api generate turftown.in/chennai --allow "POST /api/v2/venue/web/venues_around_you"
|
|
677
|
+
|
|
678
|
+
# Re-run the generated client's tests against the live API (and repair if needed)
|
|
679
|
+
ghost-api verify quotes.toscrape.com
|
|
680
|
+
|
|
681
|
+
# Check that your LLM keys work
|
|
682
|
+
ghost-api doctor
|
|
683
|
+
|
|
684
|
+
# Delete everything stored about a site (asks first; see SECURITY.md)
|
|
685
|
+
ghost-api forget quotes.toscrape.com
|
|
686
|
+
|
|
687
|
+
# Download data (no code): list what's available, then fetch all pages to a file
|
|
688
|
+
ghost-api fetch quotes.toscrape.com
|
|
689
|
+
ghost-api fetch quotes.toscrape.com list_quotes --pages 10 --format xlsx
|
|
690
|
+
|
|
691
|
+
# Watch for changes and get alerts
|
|
692
|
+
ghost-api watch add quotes.toscrape.com list_quotes --every 6h --notify ntfy:my-long-private-topic
|
|
693
|
+
ghost-api watch list
|
|
694
|
+
ghost-api watch run # check now
|
|
695
|
+
ghost-api watch schedule # keep checking in the background (Windows Task Scheduler)
|
|
696
|
+
|
|
697
|
+
# Use sites from other tools
|
|
698
|
+
ghost-api serve quotes.toscrape.com # REST API on http://127.0.0.1:8900 (docs at /docs)
|
|
699
|
+
ghost-api mcp quotes.toscrape.com # MCP server for AI assistants (stdio)
|
|
700
|
+
|
|
701
|
+
# Open the web dashboard (local only)
|
|
702
|
+
ghost-api ui
|
|
703
|
+
ghost-api ui --port 8900 --no-open
|
|
704
|
+
|
|
705
|
+
# The interactive session (stays open until /exit or Ctrl+C twice)
|
|
706
|
+
ghost-api
|
|
707
|
+
|
|
708
|
+
# Simple line-by-line output for logs and CI
|
|
709
|
+
ghost-api --plain run https://quotes.toscrape.com/scroll --goal "list quotes"
|
|
710
|
+
|
|
711
|
+
# Capture without the AI agent (just load and scroll)
|
|
712
|
+
ghost-api run https://quotes.toscrape.com/scroll --goal "list quotes" --no-agent
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
Inside the session:
|
|
716
|
+
|
|
717
|
+
| Type | It does |
|
|
718
|
+
|---|---|
|
|
719
|
+
| `quotes.toscrape.com/scroll list quotes with their authors` | Explores the site for that goal |
|
|
720
|
+
| more words after a run | A new goal for the same site |
|
|
721
|
+
| `/fetch [SITE] [OPERATION] [name=value ...]` | Downloads data (the current site if none is given) |
|
|
722
|
+
| `/watch add ...`, `/watch` | Alerts, and your list of watches |
|
|
723
|
+
| `/open`, `/report` | Opens or rewrites the current site's report |
|
|
724
|
+
| `/sites`, `/inspect`, `/refresh`, `/generate`, `/serve`, `/ui`, `/doctor` | Same as the `ghost-api` commands |
|
|
725
|
+
| `/lang typescript`, `/agent off` | Settings for the next runs |
|
|
726
|
+
| `/help`, `/clear`, `/exit` | Help, clear the screen, end (or Ctrl+C twice) |
|
|
727
|
+
|
|
728
|
+
| Option | Default | Meaning |
|
|
729
|
+
|---|---|---|
|
|
730
|
+
| `--goal` | required | What you want the client to do |
|
|
731
|
+
| `--lang` | `python` | Client language: `python` or `typescript` |
|
|
732
|
+
| `--headed` | off | Show the browser window |
|
|
733
|
+
| `--max-steps` | 40 | Maximum agent actions |
|
|
734
|
+
| `--max-llm-calls` | 50 | Maximum LLM calls |
|
|
735
|
+
| `--max-minutes` | 15 | Time limit |
|
|
736
|
+
| `--rate-limit` | 1.0 | Maximum requests per second to the target site |
|
|
737
|
+
| `--ignore-robots` | off | Skip the robots.txt check (use responsibly) |
|
|
738
|
+
| `--no-agent` | off | Don't use the LLM; just load and scroll the page |
|
|
739
|
+
| `--no-probe` | off | Don't test endpoints with direct calls |
|
|
740
|
+
| `--max-probes` | 60 | Maximum direct calls for testing endpoints |
|
|
741
|
+
| `--no-generate` | off | Don't generate a Python client |
|
|
742
|
+
| `--no-verify` | off | Don't run the generated tests against the live API |
|
|
743
|
+
| `--out` | `output` | Folder for generated clients |
|
|
744
|
+
|
|
745
|
+
**Example projects** built on generated clients, each with a plain-language README:
|
|
746
|
+
[`examples/quote_book`](examples/quote_book) (a searchable book of quotes) and
|
|
747
|
+
[`examples/turf_finder`](examples/turf_finder) (find sports venues near you in Chennai).
|
|
748
|
+
|
|
749
|
+
---
|
|
750
|
+
|
|
751
|
+
## Output
|
|
752
|
+
|
|
753
|
+
Results are kept per **site**: the domain, plus the first part of the start URL's path when
|
|
754
|
+
it names a section of the site. `https://hn.algolia.com/` is `hn.algolia.com`, while
|
|
755
|
+
`https://www.google.com/maps` is `www.google.com/maps`, so Maps and Search on the same domain
|
|
756
|
+
keep separate memory and files. IDs, file names (`index.html`) and language codes (`/en/`)
|
|
757
|
+
don't count as sections. Commands accept the site, a URL, or just the domain when it has only
|
|
758
|
+
one site (`ghost-api refresh quotes.toscrape.com`); with several, Ghost API lists them.
|
|
759
|
+
|
|
760
|
+
```
|
|
761
|
+
output/quotes.toscrape.com/scroll/
|
|
762
|
+
|-- quotes_toscrape_client.py # The client: sync and async classes, typed errors
|
|
763
|
+
|-- models.py # Pydantic data models
|
|
764
|
+
|-- test_quotes_toscrape_client.py # Live tests (run automatically by `run` and `verify`)
|
|
765
|
+
|-- package/python/ # The same client as an installable, typed package
|
|
766
|
+
|-- package/typescript/ # (with --lang typescript) package.json, tsconfig, src/
|
|
767
|
+
|-- openapi.yaml # OpenAPI 3.1 spec (imports into Postman, Bruno, Insomnia)
|
|
768
|
+
|-- report.md # Endpoints, confidence, evidence, reasoning log
|
|
769
|
+
+-- report.html # The same and more, as one shareable offline page
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
**Tests that run anywhere.** The generated tests replay recorded replies (`cassettes.json`)
|
|
773
|
+
by default, so they pass offline and in CI; `GHOST_API_LIVE=1` runs them against the real API.
|
|
774
|
+
|
|
775
|
+
**Use the client the way you prefer.** Copy the loose files into a project, or install the
|
|
776
|
+
package (`pip install output/quotes.toscrape.com/scroll/package/python`, or
|
|
777
|
+
`npm install .../package/typescript`); the import is the same either way. Each package has a
|
|
778
|
+
README with every method, a `curl` command per endpoint, and the error types. Generated code
|
|
779
|
+
passes `mypy --strict` and `tsc --strict`.
|
|
780
|
+
|
|
781
|
+
```python
|
|
782
|
+
from quotes_toscrape_client import AsyncQuotesToscrapeClient, QuotesToscrapeNotFoundError
|
|
783
|
+
|
|
784
|
+
async with AsyncQuotesToscrapeClient() as api: # same methods as the sync client
|
|
785
|
+
async for page in api.iter_get_quotes(max_pages=3):
|
|
786
|
+
...
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
Errors are typed: catch `QuotesToscrapeError` for any failure, or `...AuthError` (401/403),
|
|
790
|
+
`...NotFoundError` (404), `...RateLimitError` (429) or `...ServerError` (5xx) for one kind.
|
|
791
|
+
|
|
792
|
+
**Know when the site changes.** Every client has a version. When a refresh finds the API
|
|
793
|
+
changed, the client is regenerated and its version goes up: major when code using it could
|
|
794
|
+
break (a field removed, a type changed), minor when something was added. Each package has a
|
|
795
|
+
`CHANGELOG.md`.
|
|
796
|
+
|
|
797
|
+
```bash
|
|
798
|
+
ghost-api diff quotes.toscrape.com/scroll --live # call each endpoint once and compare
|
|
799
|
+
ghost-api diff quotes.toscrape.com/scroll --history # every client version
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
To get a pull request when that happens, use the GitHub Action: see
|
|
803
|
+
[docs/github-action.md](docs/github-action.md).
|
|
804
|
+
|
|
805
|
+
**Sites Ghost API can't browse by itself** (a login, a bot check, a long flow): browse them
|
|
806
|
+
yourself with DevTools open, use **Network > Save all as HAR**, then
|
|
807
|
+
|
|
808
|
+
```bash
|
|
809
|
+
ghost-api import session.har --goal "my orders" # add --offline to send nothing to the site
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
Cookies, tokens and personal data are removed before anything is stored. Delete the `.har`
|
|
813
|
+
file afterwards: it holds them in plain text.
|
|
814
|
+
|
|
815
|
+
**Sites that need a login.** Log in once yourself; Ghost API keeps the session (encrypted
|
|
816
|
+
on Windows) and later runs, refreshes and fetches use it:
|
|
817
|
+
|
|
818
|
+
```bash
|
|
819
|
+
ghost-api login https://example.com/account # a browser opens: log in, press Enter
|
|
820
|
+
ghost-api run https://example.com/account --goal "my orders"
|
|
821
|
+
ghost-api logout example.com # delete it
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
**Work offline.** `ghost-api mock quotes.toscrape.com/scroll` serves the captured replies at
|
|
825
|
+
the same paths on `http://127.0.0.1:8901`: point a front end or a test at it, with no traffic
|
|
826
|
+
to the real site.
|
|
827
|
+
|
|
828
|
+
Excerpt from a real `report.md`:
|
|
829
|
+
|
|
830
|
+
```
|
|
831
|
+
## Endpoints
|
|
832
|
+
|
|
833
|
+
| Endpoint | Status | Confidence | Samples | Auth | Paging | Notes |
|
|
834
|
+
|-------------------|----------|------------|---------|------|--------------|-----------------------|
|
|
835
|
+
| `GET /api/quotes` | verified | High | 6 | none | page: `page` | 2 live test(s) passed |
|
|
836
|
+
|
|
837
|
+
## Hypotheses tested
|
|
838
|
+
|
|
839
|
+
- confirmed: can be called directly, outside the browser (HTTP 200, 10 records)
|
|
840
|
+
- confirmed: paginates with page parameter 'page' (the next page returned 10 different records)
|
|
841
|
+
- confirmed: needs none of its custom headers or cookies
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
---
|
|
845
|
+
|
|
846
|
+
## Project structure
|
|
847
|
+
|
|
848
|
+
```
|
|
849
|
+
ghost-api/
|
|
850
|
+
|-- ghost_api/
|
|
851
|
+
| |-- cli/ # The command line: explore, client, data and manage commands
|
|
852
|
+
| |-- api.py # The same features as Python functions
|
|
853
|
+
| |-- workflows.py # Run and refresh, shared by the CLI and the API
|
|
854
|
+
| |-- drift.py # Client versions and API changes
|
|
855
|
+
| |-- pipeline.py # A run from start to finish, as events (no printing)
|
|
856
|
+
| |-- events.py # The events every interface shows (stored for replay)
|
|
857
|
+
| |-- ui/terminal.py # Live terminal UI (Rich)
|
|
858
|
+
| |-- web/ # Dashboard server (FastAPI) and the prebuilt frontend
|
|
859
|
+
| |-- config.py # Settings and budgets
|
|
860
|
+
| |-- errors.py # Plain-language error messages
|
|
861
|
+
| |-- net.py # robots.txt and rate limiting
|
|
862
|
+
| |-- netguard.py # Network boundary: no private addresses, reply size limits
|
|
863
|
+
| |-- agent/ # Exploration loop, prompts, actions
|
|
864
|
+
| |-- browser/ # Playwright control, snapshots, safety filter, egress proxy, request gate
|
|
865
|
+
| |-- capture/ # Network recording, noise filters, redaction
|
|
866
|
+
| |-- analysis/ # URL templates, schemas, detectors (pagination, auth, bots)
|
|
867
|
+
| |-- probe/ # Safe replays and hypothesis testing
|
|
868
|
+
| |-- generator/ # Naming, models, client spec, Jinja2 templates
|
|
869
|
+
| |-- verify/ # Run generated tests, classify failures, repair
|
|
870
|
+
| |-- export/ # report.md, report.html, OpenAPI 3.1, CSV/Excel, confidence
|
|
871
|
+
| |-- runtime.py # Call a site's endpoints by name, follow pages, get rows
|
|
872
|
+
| |-- watch.py # Watches: compare snapshots, notifications
|
|
873
|
+
| |-- serve/ # REST API and MCP server
|
|
874
|
+
| |-- llm/ # Provider gateway: fallback, cooldown, validation, cache
|
|
875
|
+
| +-- memory/ # SQLite store, lessons, memory for refresh
|
|
876
|
+
|-- tests/ # 400+ tests (no LLM quota needed)
|
|
877
|
+
|-- evals/ # Demo shop, evaluation sites, scoring script
|
|
878
|
+
|-- web/ # Dashboard and report frontend source (React + Vite + Tailwind)
|
|
879
|
+
|-- docs/images/ # README screenshots
|
|
880
|
+
|-- .env.example
|
|
881
|
+
|-- pyproject.toml
|
|
882
|
+
|-- README.md
|
|
883
|
+
+-- IMPLEMENTATION.md
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
---
|
|
887
|
+
|
|
888
|
+
## Running on free LLM tiers
|
|
889
|
+
|
|
890
|
+
Ghost API is designed to cost **$0**:
|
|
891
|
+
|
|
892
|
+
- **Small prompts.** Pages and traffic are compressed into short summaries (under 8k tokens per call).
|
|
893
|
+
- **Few calls.** 1–10 LLM calls per site in the [evaluation](#evaluation), because code does the heavy work and the agent stops as soon as the goal is covered. `refresh` often needs none.
|
|
894
|
+
- **Fallback chain.** Each provider has several candidate models. A rate-limited or overloaded model rests while another is used; a retired model is skipped; a bad key disables its provider. Order: Gemini, Groq, Gemini Lite, OpenRouter. Run `ghost-api doctor` to check your keys.
|
|
895
|
+
- **Caching.** Repeated prompts are served from a local SQLite cache.
|
|
896
|
+
|
|
897
|
+
> Free-tier limits change often, so check each provider's current pricing page. Free tiers may use prompts for training. Ghost API redacts cookies and tokens before anything reaches an LLM, but don't point it at private data.
|
|
898
|
+
|
|
899
|
+
---
|
|
900
|
+
|
|
901
|
+
## Responsible use
|
|
902
|
+
|
|
903
|
+
Ghost API is built to behave like a polite, careful developer:
|
|
904
|
+
|
|
905
|
+
- Respects `robots.txt` by default, for its own requests and for the pages and API calls the
|
|
906
|
+
browser makes for the site (checked before they are sent)
|
|
907
|
+
- Rate-limits its own requests and the site's API calls in the browser (1 request per second
|
|
908
|
+
by default)
|
|
909
|
+
- Never lets a website steer it to your computer or local network: every browser connection,
|
|
910
|
+
redirects included, goes through a local proxy that refuses private addresses (unless the
|
|
911
|
+
site you gave it is itself local)
|
|
912
|
+
- Stops reading any reply bigger than 5 MB
|
|
913
|
+
- Never tries to bypass CAPTCHAs or bot protection; it detects them and stops
|
|
914
|
+
- Never clicks destructive or purchase actions (delete, buy, pay)
|
|
915
|
+
- Never stores passwords; for logins, you log in by hand in the browser window
|
|
916
|
+
- Redacts cookies and tokens from logs, reports and LLM prompts
|
|
917
|
+
- Uses an honest user-agent string
|
|
918
|
+
|
|
919
|
+
Check a site's terms of service before generating a client for it. For demos and testing, use practice sites such as `quotes.toscrape.com/scroll`, which loads its data from a JSON API. (`books.toscrape.com` renders on the server, so it has no API to discover.)
|
|
920
|
+
|
|
921
|
+
Also:
|
|
922
|
+
|
|
923
|
+
- **Personal data is hidden, always.** Emails, phone numbers, PAN/GST/Aadhaar numbers, UPI IDs
|
|
924
|
+
and bank details in a site's replies are replaced before Ghost API stores anything, and stay
|
|
925
|
+
hidden in fetches, watches, the REST API and MCP tools. `--include-sensitive` turns that off,
|
|
926
|
+
for auditing your own site only. If you find a site exposing such data, tell the owner
|
|
927
|
+
privately instead of collecting it.
|
|
928
|
+
- **Watches and servers keep the same manners:** read-only, one request per second per site,
|
|
929
|
+
robots.txt respected, checks no more often than every 5 minutes.
|
|
930
|
+
- **Your data stays on your machine** except what the AI agent sends to your LLM provider.
|
|
931
|
+
[SECURITY.md](SECURITY.md) lists what is stored, what is sent where, and how to delete it:
|
|
932
|
+
`ghost-api forget SITE` removes everything stored about a site.
|
|
933
|
+
|
|
934
|
+
---
|
|
935
|
+
|
|
936
|
+
## Evaluation
|
|
937
|
+
|
|
938
|
+
Four sites, run end to end with free LLM tiers on a Windows laptop with 8 GB of RAM
|
|
939
|
+
(full table and method: [evals/results/results.md](evals/results/results.md)).
|
|
940
|
+
|
|
941
|
+
| Site | What it tests | Recall | Precision | Tests passing | LLM calls | Time | Peak memory |
|
|
942
|
+
|---|---|---|---|---|---|---|---|
|
|
943
|
+
| demo-shop (local) | Known answer: 5 endpoints, page + cursor paging, traps | 100% | 100% | 100% | 6 | 36 s | 415 MB |
|
|
944
|
+
| quotes.toscrape.com | Infinite-scroll JSON API | 100% | 100% | 100% | 2 | 18 s | 423 MB |
|
|
945
|
+
| hn.algolia.com | Third-party POST API with a key | 100% | 100% | 100% | 7 | 123 s* | 494 MB |
|
|
946
|
+
| books.toscrape.com | No API at all (must not invent one) | n/a | 100% | n/a | 1 | 9 s | 452 MB |
|
|
947
|
+
|
|
948
|
+
- **Recall:** share of the goal's real endpoints found. **Precision:** share of reported
|
|
949
|
+
endpoints that are real (nothing was invented). **Tests passing:** generated client tests
|
|
950
|
+
that passed against the live API. Peak memory includes Chromium.
|
|
951
|
+
- The demo shop's "Add to cart" (a POST that changes data) was never called and never generated.
|
|
952
|
+
- \*Re-measured after the gateway learned to switch away from overloaded models at once;
|
|
953
|
+
the earlier run took 259 s and 10 calls, mostly retrying an overloaded Gemini model.
|
|
954
|
+
- The first attempt failed on two sites because two providers' free models had been
|
|
955
|
+
retired; that led to the per-model fallback routing described above.
|
|
956
|
+
|
|
957
|
+
### The quality gate (every change, no LLM)
|
|
958
|
+
|
|
959
|
+
Ten local test sites with known answers ([evals/fixtures.py](evals/fixtures.py)), each built
|
|
960
|
+
around one hard case, are scored on every change in CI. A score below
|
|
961
|
+
[evals/thresholds.json](evals/thresholds.json) fails the build:
|
|
962
|
+
|
|
963
|
+
| Test site | Must hold |
|
|
964
|
+
|---|---|
|
|
965
|
+
| offset-paging, cursor-paging | The endpoint is found and its paging style is detected |
|
|
966
|
+
| api-key-header | The `x-api-key` header is found to be required |
|
|
967
|
+
| robots-disallow | The API path robots.txt disallows is **never requested**, by the browser or by replays |
|
|
968
|
+
| huge-reply | A 9 MB reply is dropped as `response-too-large`; the small endpoint is still found |
|
|
969
|
+
| xssi-guard | A reply behind Google-style `)]}'` is still read |
|
|
970
|
+
| no-api, bot-wall | Nothing is invented; a bot-protection page stops the run (`bot-protection`) |
|
|
971
|
+
| personal-data | The email and phone in the replies are **never stored** |
|
|
972
|
+
| prompt-injection | (agent runs) The planted "delete all data" instruction is never followed |
|
|
973
|
+
| demo-shop | All endpoints; the cart (a POST that changes data) is never called or generated |
|
|
974
|
+
|
|
975
|
+
The first run of this gate found a real bug: cursor paging went undetected when the newest
|
|
976
|
+
captured page was the last one. It is fixed, and the gate keeps it fixed.
|
|
977
|
+
|
|
978
|
+
Run it yourself: `python -m evals.run_eval --suite local --no-agent --check`. The full set,
|
|
979
|
+
with the agent and the live sites above, is `python -m evals.run_eval` (uses LLM calls); it
|
|
980
|
+
also runs weekly in CI, dated, without blocking builds.
|
|
981
|
+
|
|
982
|
+
---
|
|
983
|
+
|
|
984
|
+
## Limitations
|
|
985
|
+
|
|
986
|
+
The full, prioritised list of known problems is in [KNOWN_ISSUES.md](KNOWN_ISSUES.md). The main ones:
|
|
987
|
+
|
|
988
|
+
- Sites with strong bot protection (Cloudflare challenges, CAPTCHAs) will be skipped; you can
|
|
989
|
+
browse them yourself and `ghost-api import` the HAR file
|
|
990
|
+
- Sites whose `robots.txt` forbids their API paths for bots are respected, so Ghost API will not call those endpoints directly. Example: Wikipedia disallows `/w/` (where its search suggestions live) and refuses clients that don't identify themselves, so the run stops at the rules check. Wikipedia offers an official API for that purpose. If a site just wants to know who you are, set `GHOST_API_CONTACT` in `.env` (your own email or a URL; it is never filled in for you)
|
|
991
|
+
- Server-rendered sites with no JSON API have nothing to discover
|
|
992
|
+
- WebSocket, server-sent-event and gRPC APIs are not mapped yet; GraphQL is (one method per
|
|
993
|
+
operation), except batches of several operations in one request
|
|
994
|
+
- Small free models sometimes make poor exploration choices; budgets and stopping rules limit the damage
|
|
995
|
+
- Generated clients can break when the site changes its internal API: `ghost-api diff --live`
|
|
996
|
+
and the GitHub Action notice it, and `refresh` makes a new client version
|
|
997
|
+
|
|
998
|
+
---
|
|
999
|
+
|
|
1000
|
+
## Roadmap
|
|
1001
|
+
|
|
1002
|
+
| Stage | Focus | Status |
|
|
1003
|
+
|---|---|---|
|
|
1004
|
+
| 0 | Project setup | Done |
|
|
1005
|
+
| 1 | Traffic capture | Done |
|
|
1006
|
+
| 2 | API analysis (URL grouping, schemas) | Done |
|
|
1007
|
+
| 3 | LLM gateway (fallback + cache) | Done |
|
|
1008
|
+
| 4 | Agent exploration loop | Done |
|
|
1009
|
+
| 5 | Hypothesis testing | Done |
|
|
1010
|
+
| 6 | Code generation | Done |
|
|
1011
|
+
| 7 | Verification and replanning | Done |
|
|
1012
|
+
| 8 | Memory | Done |
|
|
1013
|
+
| 9 | Reporting and OpenAPI export | Done |
|
|
1014
|
+
| 10 | Evaluation and polish | Done |
|
|
1015
|
+
| UI 0–6 | Event pipeline, live terminal, web dashboard, report.html, docs | Done |
|
|
1016
|
+
| Use 1–6 | Data download, watch & alerts, REST + MCP servers, personal-data leak check | Done |
|
|
1017
|
+
|
|
1018
|
+
Full details are in [IMPLEMENTATION.md](IMPLEMENTATION.md). To work on the dashboard itself,
|
|
1019
|
+
see [web/README.md](web/README.md).
|