apilift 0.13.1__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.
- apilift-0.13.1/.agents/skills/apilift-discover/SKILL.md +87 -0
- apilift-0.13.1/.agents/skills/apilift-discover/agents/openai.yaml +4 -0
- apilift-0.13.1/.agents/skills/apilift-use/SKILL.md +96 -0
- apilift-0.13.1/.agents/skills/apilift-use/agents/openai.yaml +4 -0
- apilift-0.13.1/PKG-INFO +9 -0
- apilift-0.13.1/README.md +56 -0
- apilift-0.13.1/pyproject.toml +45 -0
- apilift-0.13.1/setup.cfg +4 -0
- apilift-0.13.1/src/apilift/__init__.py +3 -0
- apilift-0.13.1/src/apilift/agent_sessions.py +493 -0
- apilift-0.13.1/src/apilift/anonymize.py +1364 -0
- apilift-0.13.1/src/apilift/browser-adapters/claude-page.js +959 -0
- apilift-0.13.1/src/apilift/browser-adapters/codex-iab.mjs +186 -0
- apilift-0.13.1/src/apilift/capture_identity.py +91 -0
- apilift-0.13.1/src/apilift/catalog.py +1003 -0
- apilift-0.13.1/src/apilift/cli.py +1669 -0
- apilift-0.13.1/src/apilift/contracting.py +1960 -0
- apilift-0.13.1/src/apilift/contribution.py +367 -0
- apilift-0.13.1/src/apilift/documentation.py +302 -0
- apilift-0.13.1/src/apilift/harness.py +2476 -0
- apilift-0.13.1/src/apilift/identity.py +62 -0
- apilift-0.13.1/src/apilift/interface.schema.json +621 -0
- apilift-0.13.1/src/apilift/reconcile.py +995 -0
- apilift-0.13.1/src/apilift/registry_client.py +276 -0
- apilift-0.13.1/src/apilift/runtime.py +1857 -0
- apilift-0.13.1/src/apilift/traffic.py +14 -0
- apilift-0.13.1/src/apilift.egg-info/PKG-INFO +9 -0
- apilift-0.13.1/src/apilift.egg-info/SOURCES.txt +30 -0
- apilift-0.13.1/src/apilift.egg-info/dependency_links.txt +1 -0
- apilift-0.13.1/src/apilift.egg-info/entry_points.txt +2 -0
- apilift-0.13.1/src/apilift.egg-info/requires.txt +4 -0
- apilift-0.13.1/src/apilift.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apilift-discover
|
|
3
|
+
description: Create or extend a persistent Apilift interface for a logged-in UI-only web product from a natural-language outcome and observed main-frame HTTP behavior. Use for a new service, for missing CLI coverage, or when handed a written need to extend an interface. The active agent chooses product semantics and explicit request contracts; Apilift handles capture, redaction, exact sample round-trips, persistence and publication.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Discover or extend a service
|
|
7
|
+
|
|
8
|
+
Work only from the need you were given, the live product in the runtime's built-in Browser, and the installed `apilift` command. You are the one discovery subagent for it. Remain the sole discovery author and do not delegate browser actions, capture interpretation, contract authoring or cleanup further. Never inspect another run, a published target bundle, Apilift implementation code, repository-local scripts, credentials, cookies or tokens.
|
|
9
|
+
|
|
10
|
+
## What you own
|
|
11
|
+
|
|
12
|
+
You decide the consumer contract: product entities and verbs, each command's independent `read|create|update|delete|action` effect, which exact successful capture gid proves it, caller-visible arguments, the explicit request template, response paths, documentation, constraints supported by evidence, and honest gaps. Apilift does not infer these semantic decisions for you.
|
|
13
|
+
|
|
14
|
+
The installed CLI artifact is your only product result. Reasoning, notes and the final response cannot repair it. If a source, prerequisite, parameter shape, supported variant, fixed field, cost, limitation or example exists only in your thoughts or final prose, it does not exist for the next agent.
|
|
15
|
+
|
|
16
|
+
Apilift owns deterministic mechanics: capture identity and storage, secret redaction, typed template rendering, exact method/URL/query/body round-trip against each selected sample, manifest structure and lint, compatibility with an active revision, immutable candidates and atomic publication. A deterministic error is a concrete mismatch to repair; it is not an instruction to broaden product exploration.
|
|
17
|
+
|
|
18
|
+
## Acceptance criteria
|
|
19
|
+
|
|
20
|
+
Submit when the interface is useful for the requested outcome and every published command meets these criteria:
|
|
21
|
+
|
|
22
|
+
- Names and summaries use the product's own concepts and let a future agent choose the command without seeing raw traffic.
|
|
23
|
+
- Each command selects one completed capture with an HTTP response accepted by the mechanical gate, its explicit request template round-trips to that capture exactly when rendered with the documented argument samples, and the agent separately establishes the claimed product behavior from visible or downstream state.
|
|
24
|
+
- Caller arguments represent choices or identifiers a future caller can provide; captured session material and accidental object state are neither arguments nor constants.
|
|
25
|
+
- Every argument states where its value comes from. A caller-authored value such as a title may remain broadly typed and has a concrete `source`; a service entity reference points to a callable `valuesFrom`; a CLI-generated value specifies its generator. A service-derived object, array or JSON configuration may remain opaque instead of acquiring a brittle universal schema, but `valuesFrom` must return the usable value or template for the caller's selected product option. A structural schema is useful only when the caller composes the value and the observed shape is a stable product contract. Never relabel an identifier or configuration as caller-authored merely to satisfy validation.
|
|
26
|
+
- Repeated resource identifiers and other shared prerequisites are top-level `variables`, referenced by commands instead of copied as unrelated literals. Choose the scope deliberately: `scope: session` is a value the caller picks once for the whole service, which `apilift <service> context set` offers and every referencing command then inherits; `scope: shared-argument` shares only the definition for a value that has no service-wide meaning, and each command still takes it as an ordinary flag. Setting the id of one particular resource as session context is wrong even when several commands accept it. A command referencing a variable states its own captured `sample` and inherits the rest, so operations observed against different objects share one definition without repeating the scenario to make their identifiers match.
|
|
27
|
+
- Entity names avoid the words the service CLI answers itself — `compile`, `context`, `docs`, `gaps`, `help`, `lint`, `schema`, `search`, `version` — because such a name never reaches the entity and would publish every one of its commands unreachable. Publication rejects it; choose a different product noun.
|
|
28
|
+
- Every documented endpoint is complete at its own boundary: all caller-configurable request fields and every observed configuration variant are flags or collectively exhaustive product commands. A narrower command name never turns a model, mode, output schema, type, budget, optional behavior or other user-facing choice into a constant. The harness cross-checks request arguments against the template; internal `fixed` is only for protocol metadata and genuine operation discriminators. A server-required field can still contain a caller choice: defaults, collision-safe names and values generated by the UI are arguments unless product semantics establish that the value itself defines the command or is hidden protocol. Do not duplicate argument documentation in a separate completeness report. If you cannot support a known choice, do not publish that endpoint as callable coverage. Map every distinct clause of the original outcome in top-level `coverage`; creation and modification, for example, are separate needs even when they concern the same entity.
|
|
29
|
+
- The command result exposes the small set of fields a future agent needs to continue the task, including returned identifiers when applicable.
|
|
30
|
+
- Safety effect, cost, constraints, reversibility and terminal boundaries claim only what the observed product behavior establishes; uncertainty is omitted or recorded as a non-terminal gap.
|
|
31
|
+
- The requested outcome is covered, or the unresolved part is an explicit gap that accurately explains the concrete mechanical or product blocker. For every distinct need, top-level `coverage` states a consumer-visible functional acceptance result and the observed product result supporting it. A metadata-only update does not satisfy a requested behavioral or configuration change. A confirmed product boundary may be terminal, but an absent capture, browser failure, ambiguous UI or failed locator is not such evidence. Each published gap describes a boundary a consumer would walk into; a note that something was checked and needed no change, or that a command already exists, is this run's bookkeeping and belongs in what you return to the parent, never in `gaps`.
|
|
32
|
+
- Useful operations already observed while completing the coherent scenario are included when their meaning is clear; do not perform extra UI work merely to produce symmetric CRUD coverage or enumerate nearby controls.
|
|
33
|
+
- Discovery-created effects receive at most one practical cleanup attempt. Exact restoration and repeated post-cleanup confirmation are not acceptance requirements.
|
|
34
|
+
|
|
35
|
+
Commands are accepted independently. `contract build` retains valid commands and converts invalid authored commands into explicit gaps, so one unresolved operation must not erase a working interface. At least one valid command is required. The harness cross-checks the internal choice inventory, fixed-field classification and agent-authored functional assertions against captured state; it does not derive product meaning from status codes, response text or traffic shape. You remain responsible for choosing assertions that directly establish the promised behavior. An HTTP response proves only transport acceptance and may precede asynchronous completion. Every state-changing command has internal `functionalProof` with value assertions over returned or downstream observed state, and every action uses a separate downstream readback. This proof does not enter the final CLI. Never publish a capture whose observed result contradicted its command summary. A reusable example cannot rehabilitate a known-bad capture unless that corrected invocation was itself observed working; capture the corrected operation or record a gap.
|
|
36
|
+
|
|
37
|
+
## Working with the product
|
|
38
|
+
|
|
39
|
+
Start with `apilift discover open <service> --origin <url> --task '<outcome>'`, then follow the `next:` line each command prints. That one command opens the run, remembers it so nothing carries its id, and prints the browser bootstrap to run; the chain — `open`, `do` per operation, `write` per operation, `check`, `ship` — is the whole lifecycle. `connect` reprints the bootstrap and is for a page that navigated, not a step of its own. `apilift discover where` says where the run stands when the chain is lost, and `apilift discover --help` lists the surface underneath, still reachable directly or through `raw`.
|
|
40
|
+
|
|
41
|
+
Drive the product with your own browser tools. Apilift records; it does not click, type or read the page, and nothing is recorded outside a window, so explore freely. When you know the request a command should publish, record it: one operation is one `apilift discover do <entity>.<operation> --effect <e> 'METHOD /path [json]'`.
|
|
42
|
+
|
|
43
|
+
The request a command publishes is narrower than the one the UI sent — the UI carries the whole object where the caller supplies two fields — so sending the narrow one through the recording seam is the only way to establish it, and it is the page that supplies the session headers from the addresses it derived. Never read a session value out of the document to put it back on a request. Caller inputs are read off the body rather than declared a second time by hand. For an operation whose proof its own response cannot carry — an action or a delete — `--prove 'METHOD /path'` takes the readback in a second window, while the state it reads still exists; taken later it cannot be taken at all.
|
|
44
|
+
|
|
45
|
+
Where an operation has no reproducible request, `apilift discover record <entity>.<operation> --effect <e>` holds a window open across whatever you do, and `apilift discover stop` closes it. That is the exception, and the first real write of a run is one of them: the addresses of session headers are derived from watching the page send them.
|
|
46
|
+
|
|
47
|
+
Drive one coherent representative scenario shaped by the user's outcome and the product, naming each caller-relevant operation with product entity, product verb and independent safety effect. Keep incidental navigation outside labelled capture where practical. A capture window may contain fan-out; select only the request that implements the command you intend to expose. A capture that turned out to be worthless — a guessed route that 404ed, a request labelled as the wrong operation — is corrected with `apilift discover raw capture drop --gid <n> --why <text>` or `raw capture relabel --gid <n> --label <entity-operation>`; gid numbering never changes, so references already authored keep pointing where they did. When extending a service, `apilift discover raw routes --baseline` prints the exact method and URL template of every already-published command, so a published route is reproduced rather than guessed.
|
|
48
|
+
|
|
49
|
+
Use the Browser efficiently. Wire evidence establishes what was sent and returned, while the visible product state and relevant asynchronous follow-up establish what the action meant and whether it completed; neither surface alone overrides a concrete contradiction on the other. Read the page with the tools your runtime gives you; Apilift answers about traffic, not about what is on screen. When a Browser or capture call returns a running handle, wait for that same call rather than repeating the action. Repeat a product action only to resolve a named uncertainty that changes the consumer contract.
|
|
50
|
+
|
|
51
|
+
On a runtime whose adapter patches the page, capture lives inside the page, so any full page navigation ends it — including a navigation caused by the very action you are capturing, and including a new tab or window the product opens for you. Treat reconnection as part of the capture loop rather than as error recovery: re-run `apilift discover connect` and the single bootstrap line it prints whenever the page navigates, whenever the injected capture object is missing, and whenever a capture is refused as `capture-channel-disconnected`. That refusal means nothing was recording, so do not perform the product action until the page is reconnected; a mutation whose evidence is discarded still changed the user's account. Never assemble a reconnect by hand out of a port, a local capability and an eval — the setup command is the supported path and is idempotent.
|
|
52
|
+
|
|
53
|
+
After any action that navigated, read `apilift discover where` before authoring. An operation listed under `permitted-without-evidence` was permitted and then produced no captured request at all: its evidence was lost rather than never created, and it must be repeated inside a live capture window before you can treat it as covered. A capture count that simply stopped moving is the same symptom as a run that paused, so check the named condition instead of the counter.
|
|
54
|
+
|
|
55
|
+
Authentication is a runtime precondition, not a product limitation. If the session is logged out, redirected to login, returns unexpected HTML, or loses its broker connection, ask the user to sign in or reconnect and then continue the same run. Never store or inspect credentials.
|
|
56
|
+
|
|
57
|
+
## Authoring surface
|
|
58
|
+
|
|
59
|
+
Process evidence while the product action is still fresh. `do` and `stop` answer with every request the window caught, ranked, each carrying the gid the contract cites, so the usual next command is `apilift discover write <entity>.<operation>` and nothing has to be looked up in between. `apilift discover show` re-asks the same question after you have done something else, `show <n>` expands one candidate, and the flags below are for a named uncertainty. The label selects only the latest capture transaction. Default review is a small best-effort structural ranking: it shows request shapes, statuses, sizes and exact declared-input matches, but never declares product success, failure, blockers, endpoint meaning, prerequisites or asynchronous completion. You choose the command request from the product action, visible state and relevant follow-up behavior, then author that command slice before broad UI exploration continues. Use the returned `--details` command for one selected request; it adds bounded request leaves, earlier-response coincidences and a structural response outline. Use `--all` for every non-suppressed candidate, `--include-suppressed` only when you have a reason to challenge the filter, and exact `show` only when the bounded outline leaves a named wire uncertainty. Earlier-response scalar matches are weak search hints, never proof that an operation produces a prerequisite. Resolve a service-owned value only when product semantics and a callable source establish it; do not collect a large traffic backlog and match it later. Once the first useful action exists, initialize the contract and keep it current operation by operation.
|
|
60
|
+
|
|
61
|
+
Author with two commands:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
apilift discover write <entity>.<operation> what this command still needs, and the shape of each missing section
|
|
65
|
+
apilift discover write <entity>.<operation> --patch '<json>' apply, run the gates, and say what is still missing
|
|
66
|
+
apilift discover check round-trip everything authored so far
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`init`, `status`, `build` and `review` happen inside those; the surface underneath is unchanged and reachable as `apilift discover raw contract <init|guide|apply|status|show|build|review>` when a step has to be run on its own.
|
|
70
|
+
|
|
71
|
+
`contract.json` is the semantic source of truth. Run `write` with no patch once for the compact closed taxonomy and load a named guide section whenever it names a contract shape you have not used in this run; traffic cannot teach you authoring vocabulary such as `item|collection`, proof kinds or gap kinds. Its top level contains `service`, `transport`, `variables`, `entities`, and optional `gaps`. `entities` is keyed by entity name; each entity has a summary and a `commands` object keyed by arbitrary product verb. A command's consumer interface is `summary`, `effect`, `arguments`, optional `constraints`, `result`, `examples`, cost and reversibility. Its internal publication metadata is `capture`, `request`, `fixed` and, for state changes, `functionalProof`. The compiler excludes publication metadata from the final manifest except for the request template required at runtime. `functionalProof` names a proof capture, `returned-state|downstream-state` kind and RFC 6901 assertions; request acceptance, status and non-empty output alone do not prove behavior. A state-changing command whose cost is not known uses `costUnknown`; omission is not a synonym for free.
|
|
72
|
+
|
|
73
|
+
Choose result semantics from the response outline and the consumer task. `result.item` points to one observed JSON object; `result.collection` points to an observed JSON array of objects; `result.scalar` points to one bare value such as a returned id or count, printed unadorned so another command can consume it directly and `valuesFrom` can point at it; `.` selects the response root. `fields` are shallow keys on that item or on each collection row, and a scalar takes none. `pagination` belongs only to a collection. The deterministic gate checks the chosen path, runtime type and fields against the selected capture, so repair the selector instead of working around a type mismatch, dropping `result` altogether or telling the caller to post-process raw `--json`. When the response is too large for the capture transport and the gate reports it truncated, save the whole body outside the capture log with `apilift discover raw capture fetch-artifact <name> <url>` and name it as the command's `responseArtifact`; the selector is then checked against the real response while the CLI still prints only the declared projection, and `apilift discover raw artifact <name> --path ...` queries the saved body out of band so an enormous response never enters your context. An artifact is saved whole or not at all: if the body exceeds the artifact ceiling, or if less than the fetched body reaches disk, the fetch fails and names the size rather than leaving a prefix behind, so treat a reported failure as a missing observation and not as a saved artifact.
|
|
74
|
+
|
|
75
|
+
Each argument is keyed by its CLI flag and documents `type`, `summary`, captured `sample`, a separate reusable `example`, `valueOrigin`, `source`, whether it is required, and applicable enum/valuesFrom/schema/generator information. Keep the two kinds of default apart: `default` records what the service does when the field is absent, is never sent, and needs `defaultEvidence` naming the observation that established it; `clientDefault` is a value the CLI puts on the wire when the flag is omitted, and is the correct choice whenever omitting the field makes the request fail. A default and its evidence are published together and adopted together, so you are asked for the evidence exactly when a default appears or its value moves — editing anything else on the same command never asks, and a default an earlier revision published with no evidence is a `default unverified` lint warning to close on purpose rather than a justification to invent in passing. Capture input metadata improves exact matching in compact review but does not decide product semantics and its omission never requires repeating an otherwise sufficient action. You still identify only foreground caller choices as `user`; product resources and configurations are `service`. Reference a common value with `{"variable":"name"}`. Generate UUID values with `{"kind":"uuid"}` and prefixed identifiers with `{"kind":"random","prefix":"x_","alphabet":"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz","length":20}`; do not make a future caller invent an opaque service identifier. In a request body, a string exactly equal to `{$args.name}` preserves the argument's JSON type. In URL or surrounding text, `{{$args.name}}` interpolates and URL values are percent-encoded. A captured JSON body is authored as a structured object or array, never as serialized JSON text. The request may include only non-secret headers. Give every command at least one directly runnable `examples` invocation built from reusable values, not copied capture literals. Use `contract show` for the selected semantic slice and raw capture queries only for a specific unresolved wire question.
|
|
76
|
+
|
|
77
|
+
An extension inherits every entity and command the active revision publishes. Patching one it already publishes adopts that published slice first, so a partial patch refines the working definition and only what you are changing has to be written; a fresh capture is then required exactly where the patch changes what a capture is evidence of, meaning the bytes the request puts on the wire or the result projection. Re-mapping an already recorded request into a different CLI shape — promoting a constant leaf to a flag carrying that same value, fixing a flag back to its constant, renaming one — sends identical bytes, so it needs no new observation and no `sample`, only a `fixed` classification for any constant leaf it creates; wording, a `clientDefault`, a constraint and a cost need neither. `contract status` marks such a command `inherited` and lists the areas it re-evidences. Take a published name back only with `{"$delete": true}` in place of that entity or command, describing any replacement under its new name; this is how a published entity whose name the service CLI shadows is made reachable, and like any withdrawn promise it needs a matching `corrections` entry, which `contract status` asks for as soon as the patch lands. Apply semantic decisions in one or a few coherent patches. `contract apply` uses JSON Merge Patch: bare `null` deletes a key, so replacing one result selector with another sends the old one as null in the same patch, while `{"$literal":null}` stores a literal null captured in a request or contract value and `{"$literal":{...}}` around a whole command discards the published definition instead of refining it. Every list replaces wholesale except `gaps` and `corrections`, which merge by `what` and by `scope`: a later patch adds to what is already declared, patching one entry again refines it, `{"what": "...", "$delete": true}` withdraws a gap the active revision publishes, and `{"$literal": [...]}` replaces the whole list when that is what you mean. `contract status` reports global metadata separately from each command's mechanical errors. Build as soon as the requested commands are described. Do not edit the built manifest, runtime artifacts or harness files; `contract apply` is the only way to change what is published.
|
|
78
|
+
|
|
79
|
+
## Verification and publication
|
|
80
|
+
|
|
81
|
+
A completed captured mutation with an HTTP response plus an exact rendered request round-trip proves mechanics, not function. Point internal `functionalProof` at observed returned state when it directly settles the promised effect, or at a separate downstream readback when the effect is asynchronous or action-like. Assertions must check the actual consumer-visible values that make the scenario correct; existence, request status, run mode or a non-empty error-shaped result is insufficient. Live replay remains optional when the original scenario already produced this proof; use it only for a real unresolved question that captured state cannot settle.
|
|
82
|
+
|
|
83
|
+
After `contract build`, run `contract review` and read the exact service and operation documentation as a fresh CLI consumer. For every example, verify that a consumer starting with no copied IDs, URLs or JSON from discovery can obtain every service-owned prerequisite by following `context show`, `valuesFrom` and documented results using CLI alone. Browser interaction is allowed only for authentication. Repair the contract if this path breaks, if the artifact cannot answer what the operation does, where every input comes from, what shapes and variants are accepted, what it returns, its relevant constraints and cost, or if any worked example is not a command you have evidence will produce the stated result. Internal captures, fixed-field classifications, inventories, coverage evidence and functional assertions must not appear in this consumer documentation. Review is not a freeze: apply the repair, rebuild and review again. For each internal coverage row, compare its functional acceptance and evidence against the actual selector and proof: a shallow metadata mutation, fixed preset, accepted run or error-shaped output does not cover a requested behavior. A user-facing choice cannot be fixed merely because the command name includes its captured value; expose the complete choice or do not publish the endpoint. The review is hash-bound and submission rejects a missing or stale one.
|
|
84
|
+
|
|
85
|
+
The order is fixed: `write --patch` until nothing is reported missing, then `check`, then `ship`; a `write` after `check` invalidates it, so run `check` again. Run `apilift discover ship` only after a clean `check`. Submission reruns capture existence/success, redaction boundaries, template round-trips, manifest lint, artifact review and extension compatibility, freezes an immutable candidate, and returns its id. Compatibility protects what a published revision already promised, including a terminal `no-route` gap. When new evidence shows such a promise was wrong, withdraw it explicitly: patch top-level `corrections` with `{scope, reason, evidence, capture}`, naming the subject the error names — `command <entity>.<verb>`, `entity <name>`, `context variable <name>`, `transport`, `service meter`, `terminal service gap` — and pointing at the successful capture that refutes the earlier claim. `contract status` already lists each scope still missing one, so this is answered where the change was made rather than three commands later. That is the mechanism; publishing a second gap that contradicts the first is not. Publish that id with `apilift publish <candidate-id>`, reload the service help to confirm the revision is active, then return the published service/revision and any terminal boundary to the parent agent. The parent consumer continues the original user task through the resulting CLI; your prose cannot supplement missing product documentation.
|
|
86
|
+
|
|
87
|
+
Abort only when abandoning the workspace. Preserve the same run across ordinary capture, Browser and contract errors so already collected evidence remains usable.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apilift-use
|
|
3
|
+
description: Turn authenticated web-product UI work into a reusable local Apilift CLI, use already indexed services through progressive documentation, and delegate missing coverage to one discovery subagent. Use whenever a user asks an agent to read or change account data, settings or content in a SaaS or other logged-in web UI, even when Apilift was not mentioned; when inspecting indexed operations; or after missing coverage or browser authentication. Do not use for ordinary public-web research or one-page browsing with no product account state.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Use an indexed service
|
|
7
|
+
|
|
8
|
+
Treat `apilift` as the only interface to indexed services and the authoritative documentation for its commands. Do not inspect stored manifests, bundles, captures, generated files, or implementation code to discover how to call a service.
|
|
9
|
+
|
|
10
|
+
## Start narrow
|
|
11
|
+
|
|
12
|
+
When a request would otherwise require operating a logged-in product UI, tell the user concisely that you can turn the action into a reusable local CLI through Apilift, then inspect the catalog. That is an execution update, not a question: keep going when the user has already asked you to complete the product task. Stop and wait for an answer only when authentication needs them, when a newly discovered effect falls outside what they asked for, or when the capability is missing and extending it means running discovery through their account.
|
|
13
|
+
|
|
14
|
+
Run:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
apilift services
|
|
18
|
+
apilift <service> --help
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Use entity help when one entity is known, operation help before a mutation, batch `docs` for several known selectors, and `search` when product vocabulary is unknown. Prefer one `docs` call over walking several known branches. Use full `schema` only when progressive documentation cannot express a necessary machine-readable detail.
|
|
22
|
+
|
|
23
|
+
If service help lists common context, run `apilift <service> context show` before supplying repeated identifiers. Follow each variable's documented source and set it once with `context set`; commands consume it automatically unless an explicit flag overrides it. A value set this way belongs to your own session, so it cannot be changed by another agent and does not change theirs. Use `context set --shared` only for a value that is a property of the account rather than of your task, and say so when you do. Follow every parameter's `get one` command for service-owned identifiers or JSON configurations. Never scrape an identifier, URL or opaque JSON from an example, browser page, capture or unrelated result. If a required service-owned value has no callable source, coverage is missing even when the operation itself is documented; escalate it rather than opening the Browser.
|
|
24
|
+
|
|
25
|
+
Execute only commands and flags shown by the CLI:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
apilift <service> <entity> <verb> [documented flags]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Respect declared costs, side effects, constraints, and confirmation requirements. Never bypass a refusal with raw HTTP.
|
|
32
|
+
|
|
33
|
+
## Interpret outcomes
|
|
34
|
+
|
|
35
|
+
- Exit `2`: invocation is invalid; reread the relevant help.
|
|
36
|
+
- Exit `3`: local terminal refusal, `no-route`, `state-dependent-request`, or `user-action-required`; do not rediscover or bypass it.
|
|
37
|
+
- Exit `4`: upstream rejected or failed the request; preserve account state and report the diagnostic.
|
|
38
|
+
- Exit `5`: browser transport failed; run `apilift doctor` and repair only what it identifies.
|
|
39
|
+
- Exit `6`: browser authentication is required; reconnect as described below.
|
|
40
|
+
- Exit `7`: indexed coverage is missing; extend coverage as described below.
|
|
41
|
+
- Exit `8`: another agent's state-changing command on this service is still running. Nothing was sent. Retry the same command once; if it keeps refusing, report which session is holding the service instead of working around it.
|
|
42
|
+
|
|
43
|
+
## Work beside other agents
|
|
44
|
+
|
|
45
|
+
Another agent may be driving the same service at the same time. Apilift gives each agent its own session and tells you on your next command when one arrives or changes the shared defaults. Read those `notice [peer-session]` and `notice [shared-context]` lines as facts about the account you are working in:
|
|
46
|
+
|
|
47
|
+
- The browser and the signed-in account are shared. A peer's changes are real changes to the same product state, so state you did not create may appear or move between your own commands. Verify what you are about to change rather than assuming the product looks the way your last read left it.
|
|
48
|
+
- Your context values, and the mutation slot, are not shared. One state-changing command runs at a time per service; yours waits for a peer's and reports it.
|
|
49
|
+
- Do not try to coordinate with the other agent, adopt its context values, or undo its work. Report what you observed and finish your own task.
|
|
50
|
+
- `apilift sessions` lists the sessions on a service. `apilift disconnect <service>` ends yours when the user's task is done and leaves the browser connected for the rest.
|
|
51
|
+
|
|
52
|
+
## Restore authentication
|
|
53
|
+
|
|
54
|
+
On exit `6`, run `apilift connect <service> --provider codex|claude` and execute its bootstrap in that runtime's built-in Browser. Never use ordinary Chrome, install an extension, extract credentials, or ask the user to send credentials.
|
|
55
|
+
|
|
56
|
+
When `connect` reports that a signed-in browser is already connected, it printed no bootstrap on purpose: another agent's tab is the executor and yours joins it. In that case the session is signed out rather than absent, so ask the user to sign in there; only use `--force` when that browser is gone rather than busy.
|
|
57
|
+
|
|
58
|
+
Ask the user to sign in themselves only when the exact login-bearing built-in Browser tab is visible to them. After confirmation, prove one harmless authenticated read and retry the interrupted command. An action-specific identity challenge while harmless reads work is `user-action-required`, not expired authentication.
|
|
59
|
+
|
|
60
|
+
## Extend missing coverage
|
|
61
|
+
|
|
62
|
+
Coverage is missing when the service is absent, a needed operation is absent, a relevant gap is `not-checked`, `out-of-scope`, or frontier, or execution returns exit `7`. Evidence-backed `no-route`, `state-dependent-request`, and `user-action-required` are terminal boundaries for unattended execution, not missing coverage.
|
|
63
|
+
|
|
64
|
+
Stop and return to the user. Say which capability is missing, that a discovery run can add it by working through the product in a signed-in browser, and roughly what that costs in time and in account state it may create. Then ask whether to run it. A missing capability is never a reason to open the product UI yourself, assemble a URL, or call the API directly.
|
|
65
|
+
|
|
66
|
+
### Write the need yourself
|
|
67
|
+
|
|
68
|
+
You know more than the user did when they asked. You have read the service map, the entity relations and the gaps, and you found out exactly where the interface ran out. Forward that, not their original sentence.
|
|
69
|
+
|
|
70
|
+
State four things, in the product's own vocabulary:
|
|
71
|
+
|
|
72
|
+
- **Outcome.** What the user is trying to accomplish, as an observable change or answer in the product.
|
|
73
|
+
- **Scope.** The specific capabilities you found missing, named as entities and operations, plus the ones that already exist and must keep working. Say which parts of the outcome are already covered so the run does not re-discover them.
|
|
74
|
+
- **Done.** The consumer-visible result that means the capability works — what the caller can then do, and what they should see in the product afterwards.
|
|
75
|
+
- **Acceptance.** What the resulting CLI must expose for you to finish the original task: the arguments you must be able to set, the values you must be able to obtain from a documented source, and the fields you need back to continue. Name every prerequisite you could not resolve, because a value with no callable source is what stops the next agent even when the operation itself is documented.
|
|
76
|
+
|
|
77
|
+
Keep it about the product and the outcome. Do not specify routes, request shapes, capture ids or contract structure: choosing those is the discovery run's job, and prescribing them from a help page you read is a guess that will outrank its evidence.
|
|
78
|
+
|
|
79
|
+
### Hand it to one run
|
|
80
|
+
|
|
81
|
+
Launch exactly one subagent for the whole discovery or extension and give it the need, the original user outcome, and the instruction to activate `$apilift-discover`. The main agent must not open the Browser for discovery, inspect captures, author or repair the contract, publish catalog files manually, or split individual product actions across additional subagents. The discovery subagent owns one run continuously, publishes the resulting candidate through the installed CLI, and returns only the published service/revision and any terminal boundary. If it stops prematurely or encounters a recoverable error, continue the same subagent and run rather than taking over or launching another.
|
|
82
|
+
|
|
83
|
+
Wait for that subagent. Relay only genuine user authentication or authority questions while it works. Do not reproduce its discovery steps as an independent check: the deterministic gates are the check, and the installed CLI is its only deliverable.
|
|
84
|
+
|
|
85
|
+
The user's original request is the authority boundary throughout discovery. Do not ask again for an explicitly requested create, change, delete, spend, publish or exposure of named test state; seek confirmation only for a newly discovered effect or risk outside that scope.
|
|
86
|
+
|
|
87
|
+
The discovery subagent publishes with `apilift publish <candidate-id>`. Publication rechecks candidate and evidence hashes, selected capture existence and success, exact request-template round-trips, secret boundaries, manifest lint, compatibility, and active-baseline freshness under the service lock. There is no mandatory live replay or subjective semantic verdict in publication. A publication failure means the candidate failed a concrete deterministic check and must be repaired by the same discovery subagent and editable run when possible.
|
|
88
|
+
|
|
89
|
+
After publication, restart from `apilift <service> --help`, inspect the newly documented operation, and continue the user's original task. Publication is not completion of that task.
|
|
90
|
+
|
|
91
|
+
## Preserve boundaries
|
|
92
|
+
|
|
93
|
+
- Keep target captures, sessions, candidates, reports, and revisions in Apilift's user data directory, never in the product repository.
|
|
94
|
+
- Do not claim a service works outside its documented browser-owned transport.
|
|
95
|
+
- Do not claim permanent cleanup when objects remain recoverable in trash or archive.
|
|
96
|
+
- Do not publish by editing catalog files; use only `apilift publish`.
|
apilift-0.13.1/PKG-INFO
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: apilift
|
|
3
|
+
Version: 0.13.1
|
|
4
|
+
Summary: Persistent local CLI interfaces over authenticated web-product APIs
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: httpx>=0.28
|
|
7
|
+
Requires-Dist: jsonschema>=4.21
|
|
8
|
+
Requires-Dist: platformdirs>=4.2
|
|
9
|
+
Requires-Dist: PyYAML>=6.0
|
apilift-0.13.1/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Apilift
|
|
2
|
+
|
|
3
|
+
Turn a logged-in UI-only web service into a persistent local CLI an AI agent can drive and extend when coverage is missing.
|
|
4
|
+
|
|
5
|
+
Apilift captures main-frame HTTP traffic through the agent's built-in Browser, lets the discovery author define the product-semantic command contract, and deterministically checks each selected request against its captured sample before publishing a local command surface. Browser sessions remain the transport; credentials are neither extracted nor stored.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pipx install apilift
|
|
11
|
+
apilift agent install codex
|
|
12
|
+
apilift agent install claude
|
|
13
|
+
apilift doctor
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Use `apilift agent uninstall codex|claude|cursor` to remove only skills managed by Apilift. Re-run `install` after upgrading the package to atomically replace them. Set `APILIFT_HOME` to override the platform user-data catalog.
|
|
17
|
+
|
|
18
|
+
## Shared registry
|
|
19
|
+
|
|
20
|
+
Every published interface is anonymized, queued locally, and offered to the shared registry. Registry service snapshots are public in v1: `apilift services` includes remote coverage, and the first command for a remote service downloads it lazily. Before every later service command and before discovery, the CLI conditionally pulls the current revision; an unavailable registry never prevents cached execution or offline discovery.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
apilift sync [service] [--json]
|
|
24
|
+
apilift doctor [--json]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The first contribution creates a random installation credential stored separately from target-service browser sessions with file mode `0600`; the registry stores only its SHA-256 hash. `APILIFT_REGISTRY_URL` overrides the production default `https://registry.apilift.dev` for local development and self-hosting.
|
|
28
|
+
|
|
29
|
+
## Agent entrypoint
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
apilift services
|
|
33
|
+
apilift <service> --help
|
|
34
|
+
apilift <service> docs <entity> <entity.operation> --compact
|
|
35
|
+
apilift <service> search '<user intent>' --docs
|
|
36
|
+
apilift <service> <entity> <operation> --help
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The CLI is the documentation source: service help is a compact capability map, entity help explains relations and identifier sources, operation help discloses parameters and effects, and batch selectors reveal only the branches a scenario needs. Missing coverage exits with `7`; the agent then returns to the user, offers a discovery run, and writes the need it discovered. One discovery subagent owns conceptual completeness and publication; the parent agent reloads help and continues the original request through the installed CLI.
|
|
40
|
+
|
|
41
|
+
## Several agents at once
|
|
42
|
+
|
|
43
|
+
Agents working on one service at the same time each get their own session, recognized from the conversation the runtime is already running. Context values belong to the session that chose them, so one agent cannot redirect another's next command, and a peer arriving is reported on the next command rather than never. The signed-in browser and the account behind it are shared by design, so one state-changing command runs at a time per service and a second one waits for it, then exits `8` rather than racing.
|
|
44
|
+
|
|
45
|
+
## Layout
|
|
46
|
+
|
|
47
|
+
| Path | What it is |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `src/apilift/` | Installable catalog, documentation renderer, runtime, compiler, capture harness, and browser adapters |
|
|
50
|
+
| `server/` | FastAPI registry, PostgreSQL worker, Alembic migrations, integration tests, and deployment runbook |
|
|
51
|
+
| `.agents/skills/apilift-use/` | Consumer trajectory, isolated discovery hand-off, and deterministic publication |
|
|
52
|
+
| `.agents/skills/apilift-discover/` | Candidate authoring in an isolated user-data workspace |
|
|
53
|
+
| `.agents/apilift/tests/` | Generic helpdesk fixture and deterministic regression suite |
|
|
54
|
+
| `knowledge/` | Current business and product state |
|
|
55
|
+
|
|
56
|
+
Real-service captures, sessions, bundles, manifests, reports, and credentials never belong in this repository; the per-user catalog stores runtime state and immutable revisions outside the working tree.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "apilift"
|
|
7
|
+
version = "0.13.1"
|
|
8
|
+
description = "Persistent local CLI interfaces over authenticated web-product APIs"
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = ["httpx>=0.28", "jsonschema>=4.21", "platformdirs>=4.2", "PyYAML>=6.0"]
|
|
11
|
+
|
|
12
|
+
[project.scripts]
|
|
13
|
+
apilift = "apilift.cli:main"
|
|
14
|
+
|
|
15
|
+
[dependency-groups]
|
|
16
|
+
dev = ["pytest>=8.3", "pytest-timeout>=2.3"]
|
|
17
|
+
|
|
18
|
+
[tool.pytest.ini_options]
|
|
19
|
+
testpaths = [".agents/apilift/tests", ".agents/skills/evaluate-skill/tests"]
|
|
20
|
+
python_files = ["test_*.py"]
|
|
21
|
+
addopts = "-q --strict-markers --strict-config"
|
|
22
|
+
# Every test gets a deadline it never normally reaches. The suite drives real subprocesses and a
|
|
23
|
+
# real HTTP broker, and the failure mode that costs the most is not a wrong assertion — it is a
|
|
24
|
+
# test that waits forever and reports nothing.
|
|
25
|
+
timeout = 60
|
|
26
|
+
timeout_method = "signal"
|
|
27
|
+
markers = ["node: drives a browser adapter through the Node.js runtime"]
|
|
28
|
+
|
|
29
|
+
[tool.setuptools]
|
|
30
|
+
package-dir = {"" = "src"}
|
|
31
|
+
include-package-data = true
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.packages.find]
|
|
34
|
+
where = ["src"]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.package-data]
|
|
37
|
+
apilift = ["interface.schema.json", "browser-adapters/*.js", "browser-adapters/*.mjs"]
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.data-files]
|
|
40
|
+
"share/apilift/skills/apilift-discover" = [".agents/skills/apilift-discover/SKILL.md"]
|
|
41
|
+
"share/apilift/skills/apilift-discover/agents" = [".agents/skills/apilift-discover/agents/openai.yaml"]
|
|
42
|
+
"share/apilift/skills/apilift-use" = [".agents/skills/apilift-use/SKILL.md"]
|
|
43
|
+
"share/apilift/skills/apilift-use/agents" = [".agents/skills/apilift-use/agents/openai.yaml"]
|
|
44
|
+
[tool.uv.workspace]
|
|
45
|
+
members = ["server"]
|
apilift-0.13.1/setup.cfg
ADDED