Resolve a dependency
One external dependency, taken from whatever state it is in to resolved:
a chosen provider, a committed contract in its own directory, and the config
keys every consumer codes against. The instruction names the dependency, and
may carry the user's answer after the name — /resolve-dependency currency-converter Open Exchange Rates, or a document URL — which is the
provider they chose on the definition. /resolve-dependencies (plural, no name)
walks every dependency that is still open, one at a time, in the order the
Build drawer lists them, and ends with the list empty or with what is left
named plainly.
architecture owns the definition's shape and the research playbook; this
skill is the guided flow over it. grilling owns the question mechanics.
Everything you write goes to specs/design/dependencies/<name>/ — never to a
component's design.json, which only references the dependency by name.
Read the state first
Read specs/design/dependencies/<name>/dependency.json from the snapshot and
say, in one line, where it stands:
| On disk |
State |
This flow's job |
no provider (suggestions may be open) |
needs-input |
ask which provider, settle it |
provider + style, no contract (or no sdk for style sdk) |
needs-contract |
get the contract |
contract on disk, assumed absent, contract marked assumed |
needs-acceptance |
ask the user to accept |
| contract on disk |
resolved |
nothing — say so and stop |
source: "org" |
registered |
nothing — the org record owns it |
Do the steps below in order, skipping the ones the state has already passed.
Each step is at most one ask_question; a /resolve-dependencies walk asks
them per dependency, never as one batch across dependencies — the user
answers one system at a time.
1. Settle the provider — the user's choice, never yours
All research for an open dependency happens here, and the user chooses.
- No provider yet: ask the "Which provider?" card first. ONE
ask_question, before any research: the suggestions on file as the
options (label = the suggestion's name; description = its one-line
distinction for THIS product; mark at most one recommended only when a
real signal favours it), then ALWAYS these two, in this order —
{ "label": "Another provider", "freeText": true, "description": "Name a different provider, or paste a link to its API document." }
and { "label": "Find one for me", "description": "I research the options and come back with what fits." }.
Never write options back into the file — the question lives in this
conversation.
- A named provider settles
provider: find out how it is consumed
(style) and go on to step 2.
- A document URL settles both: fetch it through
slice_openapi_spec (the
URL plus the operations the design calls), take provider from the
document's info.title, and treat step 2's route 1 as taken.
- Find one for me: research the capability (
web_search) and come
back with ONE more card — the providers that genuinely fit, each with its
distinction, your recommendation marked, and Another provider as
free text. One fit is still a question ("Use Stripe?").
- The instruction already carries an answer (a name or a URL after the
dependency's name): treat it as the card's answer and skip the card.
- A Registered External resource fits. Say so and write only
{ "name", "source": "org" } — the platform fills the rest at save, and no
contract step follows.
Write the choice: provider and style set, suggestions removed. The
config keys come last (step 3), from the provider chosen — never before.
2. Get the contract
Four routes — a ladder, climbed in this order, and the user is told which
rung you took:
Find it. web_search for the provider's published OpenAPI or GraphQL
document. Name the operations the design actually calls (the flows and
the component's description say which) and call slice_openapi_spec with
the URL and those operations. It fetches the whole document outside your
context, cuts the slice, validates it, and returns the slice with its
provenance. addFile the slice as openapi.yaml in the dependency's
directory and record contract plus the provenance block the tool
returned. If you cannot name the operations, you do not understand the
dependency well enough to slice it — go back to the flows before asking
the user for anything.
Derive it from the provider's documentation. When no public document
exists but the provider's OWN developer reference does — pages that name
the operations the design calls, with their parameters and responses —
write the interface from those pages: the operations the design needs and
nothing more, as openapi.yaml in the dependency's directory, with
x-aep-derived: true at the document root and, on EVERY operation, an
x-aep-source: <page url> naming the page it came from. Record contract
and a provenance block with sourceUrl = the reference's root page. No
permission is needed: the dependency reads resolved, flagged derived.
The bar is the whole design, not part of it — if one operation the design
needs has no page, or the only pages are marketing, a blog, a third-party
tutorial or a partial reference, this rung does not apply: go to 3.
Ask for it. When neither a document nor documentation exists (most
couriers, most private APIs), ask ONE question — "How should I get its
interface?" — whose options are EXACTLY these three, action included
(the console runs the action when the user answers; an option without it
is a dead button):
[
{ "label": "Give a link", "freeText": true,
"description": "Paste a URL to the provider's published OpenAPI document." },
{ "label": "Upload one",
"action": { "kind": "upload-interface", "dependency": "<name>" },
"description": "Upload the document here; I read it once it lands." },
{ "label": "Proceed on your assumption", "recommended": true,
"action": { "kind": "accept-assumption", "dependency": "<name>" },
"description": "I write the interface from the provider's documentation, covering only what this design calls. Choosing this authorizes it — nothing further is asked; validation cannot check it against a published document." }
]
- Give a link → route 1 with that URL.
- Upload one → the answer arrives once the document is on disk; read
it from the snapshot and go on to step 3.
- Proceed on your assumption → the user's authorization is already
recorded on the definition when the answer reaches you; go on to route
- Never describe this option as needing a later acceptance.
Assume it — authorized by that answer, and only then. Write the
contract yourself from the provider's documentation pages and what you
know — the operations the design needs and nothing more — as
openapi.yaml in the dependency's directory, with x-aep-assumed: true
at the document root and, in the info.description, a short note of what
you are unsure about (auth scheme, pagination, error shapes). Record
contract and a provenance block with sourceUrl naming the
documentation you read. Re-read dependency.json from the snapshot
first: the user's assumed record is already on it — carry it over
exactly; you never write or alter it. Nothing further is asked of the
user: the dependency reads resolved (flagged assumed) the moment the
file lands.
An sdk style needs its manifest too: write sdk.json with a packages
entry for every implementation language the design's components use (the
ecosystem-prefixed identifier the provider publishes), the docs URL, and the
calls the design relies on; set "sdk": "sdk.json". Put the API slice beside
it when the provider has one — without it the dependency is SDK-only, and
you say so.
3. Settle the config keys
Derive config from the contract — a REST API's securitySchemes, an SDK's
constructor arguments — following the architecture skill's conventions
(SCREAMING_SNAKE_CASE, secret only for credentials, a description saying
where the user finds the value). Keys already on the file stay unless the
contract contradicts them.
Close
One line per dependency you touched: its name, the provider chosen, the state
it is in now, and the one thing (if any) still needed from the user. Nothing
else: the files carry the detail, and the Build drawer re-reads them.
1---2name: resolve-dependency3description: Use for taking one external dependency from open to resolved — `/resolve-dependency <name> [answer]` names it and may carry the provider the user chose; `/resolve-dependencies` walks every open one in turn. Ask which provider (their suggestions as options; never choose for them), get its interface on disk (found, uploaded from the card, or assumed under the authorization the card records), then derive the config keys.4---56# Resolve a dependency78One external dependency, taken from whatever state it is in to **resolved**:9a chosen provider, a committed contract in its own directory, and the config10keys every consumer codes against. The instruction names the dependency, and11may carry the user's answer after the name — `/resolve-dependency12currency-converter Open Exchange Rates`, or a document URL — which is the13provider they chose on the definition. `/resolve-dependencies` (plural, no name)14walks every dependency that is still open, one at a time, in the order the15Build drawer lists them, and ends with the list empty or with what is left16named plainly.1718`architecture` owns the definition's shape and the research playbook; this19skill is the guided flow over it. `grilling` owns the question mechanics.20Everything you write goes to `specs/design/dependencies/<name>/` — never to a21component's `design.json`, which only references the dependency by name.2223## Read the state first2425Read `specs/design/dependencies/<name>/dependency.json` from the snapshot and26say, in one line, where it stands:2728| On disk | State | This flow's job |29|---|---|---|30| no `provider` (`suggestions` may be open) | needs-input | ask which provider, settle it |31| `provider` + `style`, no `contract` (or no `sdk` for style `sdk`) | needs-contract | get the contract |32| contract on disk, `assumed` absent, contract marked assumed | needs-acceptance | ask the user to accept |33| contract on disk | resolved | nothing — say so and stop |34| `source: "org"` | registered | nothing — the org record owns it |3536Do the steps below in order, skipping the ones the state has already passed.37Each step is at most one `ask_question`; a `/resolve-dependencies` walk asks38them per dependency, never as one batch across dependencies — the user39answers one system at a time.4041## 1. Settle the provider — the user's choice, never yours4243All research for an open dependency happens here, and the user chooses.4445- **No provider yet: ask the "Which provider?" card first.** ONE46 `ask_question`, before any research: the `suggestions` on file as the47 options (label = the suggestion's name; description = its one-line48 distinction for THIS product; mark at most one recommended only when a49 real signal favours it), then ALWAYS these two, in this order —50 `{ "label": "Another provider", "freeText": true, "description": "Name a different provider, or paste a link to its API document." }`51 and `{ "label": "Find one for me", "description": "I research the options and come back with what fits." }`.52 Never write options back into the file — the question lives in this53 conversation.54 - A named provider settles `provider`: find out how it is consumed55 (`style`) and go on to step 2.56 - A document URL settles both: fetch it through `slice_openapi_spec` (the57 URL plus the operations the design calls), take `provider` from the58 document's `info.title`, and treat step 2's route 1 as taken.59 - **Find one for me**: research the capability (`web_search`) and come60 back with ONE more card — the providers that genuinely fit, each with its61 distinction, your recommendation marked, and **Another provider** as62 free text. One fit is still a question ("Use Stripe?").63- **The instruction already carries an answer** (a name or a URL after the64 dependency's name): treat it as the card's answer and skip the card.65- **A Registered External resource fits.** Say so and write only66 `{ "name", "source": "org" }` — the platform fills the rest at save, and no67 contract step follows.6869Write the choice: `provider` and `style` set, `suggestions` removed. The70config keys come last (step 3), from the provider chosen — never before.7172## 2. Get the contract7374Four routes — a ladder, climbed in this order, and the user is told which75rung you took:76771. **Find it.** `web_search` for the provider's published OpenAPI or GraphQL78 document. Name the operations the design actually calls (the flows and79 the component's description say which) and call `slice_openapi_spec` with80 the URL and those operations. It fetches the whole document outside your81 context, cuts the slice, validates it, and returns the slice with its82 provenance. `addFile` the slice as `openapi.yaml` in the dependency's83 directory and record `contract` plus the `provenance` block the tool84 returned. If you cannot name the operations, you do not understand the85 dependency well enough to slice it — go back to the flows before asking86 the user for anything.872. **Derive it from the provider's documentation.** When no public document88 exists but the provider's OWN developer reference does — pages that name89 the operations the design calls, with their parameters and responses —90 write the interface from those pages: the operations the design needs and91 nothing more, as `openapi.yaml` in the dependency's directory, with92 `x-aep-derived: true` at the document root and, on EVERY operation, an93 `x-aep-source: <page url>` naming the page it came from. Record `contract`94 and a `provenance` block with `sourceUrl` = the reference's root page. No95 permission is needed: the dependency reads resolved, flagged *derived*.96 The bar is the whole design, not part of it — if one operation the design97 needs has no page, or the only pages are marketing, a blog, a third-party98 tutorial or a partial reference, this rung does not apply: go to 3.993. **Ask for it.** When neither a document nor documentation exists (most100 couriers, most private APIs), ask ONE question — "How should I get its101 interface?" — whose `options` are EXACTLY these three, `action` included102 (the console runs the action when the user answers; an option without it103 is a dead button):104105 ```json106 [107 { "label": "Give a link", "freeText": true,108 "description": "Paste a URL to the provider's published OpenAPI document." },109 { "label": "Upload one",110 "action": { "kind": "upload-interface", "dependency": "<name>" },111 "description": "Upload the document here; I read it once it lands." },112 { "label": "Proceed on your assumption", "recommended": true,113 "action": { "kind": "accept-assumption", "dependency": "<name>" },114 "description": "I write the interface from the provider's documentation, covering only what this design calls. Choosing this authorizes it — nothing further is asked; validation cannot check it against a published document." }115 ]116 ```117118 - **Give a link** → route 1 with that URL.119 - **Upload one** → the answer arrives once the document is on disk; read120 it from the snapshot and go on to step 3.121 - **Proceed on your assumption** → the user's authorization is already122 recorded on the definition when the answer reaches you; go on to route123 4. Never describe this option as needing a later acceptance.1244. **Assume it — authorized by that answer, and only then.** Write the125 contract yourself from the provider's documentation pages and what you126 know — the operations the design needs and nothing more — as127 `openapi.yaml` in the dependency's directory, with `x-aep-assumed: true`128 at the document root and, in the `info.description`, a short note of what129 you are unsure about (auth scheme, pagination, error shapes). Record130 `contract` and a `provenance` block with `sourceUrl` naming the131 documentation you read. Re-read `dependency.json` from the snapshot132 first: the user's `assumed` record is already on it — carry it over133 exactly; you never write or alter it. Nothing further is asked of the134 user: the dependency reads resolved (flagged assumed) the moment the135 file lands.136137An `sdk` style needs its manifest too: write `sdk.json` with a `packages`138entry for every implementation language the design's components use (the139ecosystem-prefixed identifier the provider publishes), the docs URL, and the140calls the design relies on; set `"sdk": "sdk.json"`. Put the API slice beside141it when the provider has one — without it the dependency is SDK-only, and142you say so.143144## 3. Settle the config keys145146Derive `config` from the contract — a REST API's `securitySchemes`, an SDK's147constructor arguments — following the `architecture` skill's conventions148(SCREAMING_SNAKE_CASE, `secret` only for credentials, a `description` saying149where the user finds the value). Keys already on the file stay unless the150contract contradicts them.151152## Close153154One line per dependency you touched: its name, the provider chosen, the state155it is in now, and the one thing (if any) still needed from the user. Nothing156else: the files carry the detail, and the Build drawer re-reads them.