# Acquire

> The job in which Graft's model reads a vendor's documentation, writes a tool, proves it without changing anything, publishes it and promotes it.

Source: https://docs.getgraft.ai/graft/concepts/acquire

`acquire` is the front door. Your agent calls it with a connection, a goal in a sentence or two, and any hints it has, and Graft's model does the rest: it reads the vendor's documentation, writes the smallest module that makes the call, checks it, proves it with reads, publishes it with a test input, dry-runs it, fixes and republishes until the dry run passes, then promotes it into the agent's working set.

The code is written by a model inside Graft, not by the model driving your harness. Your agent decides what is needed; Graft's model writes and proves it; you enter secrets and answer approvals.

## The call

```json
{ "connectionId": "…", "goal": "List the open issues in a repository", "hints": "https://docs.github.com/en/rest/issues/issues" }
```

`connectionId` must be in the agent's scope; a connection outside it is refused and the answer points at `request_connection`. `goal` is what the tool must do, in your terms. `hints` is anything the agent already knows: an endpoint, a field name, and above all a documentation URL, which is the single most useful hint.

The answer comes back at once:

```json
{ "jobId": "…", "status": "queued", "progress": ["Queued: Graft's model will read the vendor's documentation, draft the tool, prove it with reads, publish and dry-run it, then promote it into your working set. Poll acquire_status with the jobId for progress."] }
```

Nothing has been built yet. The loop takes minutes, and an MCP tool call does not.

## Before it starts: the build approval

The first time an agent acquires against a connection, you are asked once: may this agent build against this connection? That is the moment Graft's model starts reading your data there through dry-run reads. The answer holds for that agent and that connection; later acquires against it ask nothing.

In Claude and ChatGPT the ask is a card in the chat with **Allow** and **Decline**; in Hermes it is Hermes's own approval card with allow and deny buttons. Elsewhere the agent relays a link and you answer under **Pending actions**. A decline records nothing, so the next `acquire` asks again.

## While it runs: `acquire_status`

`acquire` itself waits for the job for as long as the harness allows and answers with where it stands. Unfinished, the agent calls `acquire_status { jobId }`, which waits up to twenty seconds for a new line before answering, and gets `{ status, progress, attempts, result? }`. `status` is `queued`, `running`, `succeeded` or `failed`; `progress` is the list of lines Graft's model has reported so far, one per step, and the agent relays the newest to you in a sentence when it changes.

The steps, in order:

1. **Read the documentation.** Pages are fetched server-side and read as text. A cheap triage model decides whether to open the documentation URLs the goal and hints name, and condenses long pages; it never writes code.
2. **Write the module.** TypeScript, one call, the fields the goal needs.
3. **Check it.** A static pass: types against the input schema, no credential or host in the code, no import outside the module, any SDK bound to the proxy. The check also derives the tool's read-only and destructive annotations from the HTTP methods it uses.
4. **Prove it with reads.** The module runs against the live vendor with reads only, until a read returns what the documentation said it would.
5. **Publish with a test input.** The version is written to your toolbox, its packages installed under the package policy, and dry-run.
6. **Dry run.** Reads reach the vendor for real. Every other method stops at the proxy, which answers with a preview of the request that would have left. The model compares each preview against the documentation. A dry run never asks you anything and is never shown to you; it exists for the model.
7. **Fix and republish**, when the dry run fails, with a changed module. Each new draft is an attempt.
8. **Promote and notify.** The tool joins the agent's working set and `tools/list_changed` fires.

## When it ends

On `succeeded`, `result` names the tool:

```json
{ "tool": "github__list-issues", "toolId": "…", "version": 1, "annotations": { "readOnlyHint": true, "destructiveHint": false } }
```

The tool appears in the list when the harness re-reads it; until then `run_tool { vendor, name, input }` calls it by name. The first real use is your agent's, through the published tool, and that is where a write asks you.

On `failed`, `result.failure` is one word and `result.message` says why, with what was tried: `attempt_budget`, `token_ceiling` or `turn_budget` when a bound was reached, `model_gave_up` or `model_failed`, `connection_unavailable`, `build_approval_missing`, `sandbox_unavailable`, or `job_failed`. The agent says what happened in your words and what it will try next, usually a documentation URL as a hint or a different connection.

## The bounds

A job may draft at most four modules and spend at most 400,000 tokens across every model turn, and a job that reaches either bound ends with a result naming it. Every draft is an attempt, a draft the check refuses as much as one whose dry run fails. Self-hosted deployments set the two bounds with `GRAFT_ACQUIRE_MAX_ATTEMPTS` and `GRAFT_ACQUIRE_TOKEN_CEILING`.

## Which model

On Graft Cloud, `acquire` runs on a fixed model Graft chooses, with a cheap model for triage. Bring your own key under **Settings** and your jobs run on your provider instead, and the vendor documentation those jobs read goes to your provider rather than Graft's. Self-hosted Graft always authors with your own key: `GRAFT_MODEL_BACKEND=provider`, `GRAFT_MODEL_PROVIDER` (`anthropic` or `openai`) and `GRAFT_MODEL_API_KEY`, and it refuses to start without them.

- [How approvals work](https://docs.getgraft.ai/graft/approvals/how-approvals-work.md): The build approval, and what the published tool asks on first use.
- [Bring your own model key](https://docs.getgraft.ai/graft/cloud/bring-your-own-model-key.md): Route your acquire jobs through your own provider on Graft Cloud.

## Try it

```text
Build me a tool that fetches a Linear issue by its identifier. The docs are at https://developers.linear.app/docs.
```

```text
How is the tool you are building coming along?
```

```text
The acquire failed. Try again with this documentation page as a hint: https://…
```
