The Graspable app talks to its agent over an HTTP API on your computer. Scripts and other programs can use the same API. It listens on 127.0.0.1 only.
For most uses the grasp command or the MCP server is simpler. Use the API when you want to build your own tool.
Address and access
grasp api
# http://127.0.0.1:51877
The port changes each time the agent starts, so ask for the address each time, or read it from ~/.graspable/agent/api.json.
Every request needs Authorization: Bearer <token>. Create a token in Settings → Plugins and connectors → Access tokens, or:
grasp token create "my script" --scope run
The token is shown once. Graspable stores only a hash of it.
| Level | May |
|---|---|
read |
Look at projects, files, runs and usage |
run |
Also create projects, edit files, start and steer runs, answer approvals, start previews, use memory |
admin |
Also change plugins, skills, components, sign-ins and tokens, move projects to the cloud, delete projects |
A request above the token's level is answered with 403.
Projects and files
| Request | Does |
|---|---|
GET /projects |
List projects |
POST /projects { "name", "template" } |
Create a project. Packages install in the background; install becomes done |
GET /projects/:id |
One project |
GET /projects/:id/files |
File paths |
GET /projects/:id/file?path=App.jsx |
{ "path", "content" } |
PUT /projects/:id/file { "path", "content" } |
Write a file |
POST /projects/:id/preview |
Start the preview: { "url", "port" } |
DELETE /projects/:id/preview |
Stop the preview |
POST /projects/:id/check |
Build and load in a headless browser: { "pass", "build", "browser" } |
Paths are relative to the project. Paths that leave the project are refused.
Runs
POST /runs starts a run and returns { "runId" }:
{
"projectId": "3f9a12bc",
"prompt": "Add a floor that reflects the planets.",
"engine": "claude-code",
"approvalPolicy": "guarded"
}
| Field | Meaning |
|---|---|
engine |
claude-code or codex (their own sign-in on this computer), or pi (the Graspable agent) |
provider |
For pi: { "provider": "anthropic", "modelId": "…", "apiKey": "…" }. For the others, optionally { "provider": "<engine>", "modelId": "…" } |
approvalPolicy |
auto, guarded (default) or strict |
budget |
{ "maxCostUsd", "maxTokens" }: the run stops when either is passed |
plugins |
Secret fields of switched-on plugins: { "<plugin>": { "<FIELD>": "…" } } |
| Request | Does |
|---|---|
GET /runs?projectId=:id |
Runs of a project |
GET /runs/:id |
{ "state", "events" } |
GET /runs/:id/events?since=<seq> |
The same events as a stream (server-sent events) until the run is finished |
POST /runs/:id/approve { "toolCallId", "approved" } |
Answer an approval request |
POST /runs/:id/steer { "text" } |
Send the agent a message while it works |
POST /runs/:id/cancel |
Stop the run |
POST /runs/:id/revert |
Undo the run's file changes |
A run's state is running, waiting_user, completed, failed or cancelled.
Events
Each event is { "runId", "seq", "ts", "event" }. The kinds you will use most:
event.type |
Meaning |
|---|---|
text |
The agent said something |
tool_call, tool_result |
A step and its result |
approval_required |
The run waits for an answer. Send toolCallId to /approve |
fragment_update |
A file was written: filePath, code |
verification |
A check finished: kind (build, smoke, xr), pass, summary |
completion |
The end: status (success, failure, cancelled) and summary |
An example
API=$(grasp api | head -1)
TOKEN=<your token>
curl -s -X POST "$API/runs" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"projectId":"3f9a12bc","prompt":"Make the sun pulse slowly.","engine":"codex"}'