API Reference
Orchard exposes a REST API for programmatic management of groves.
Base URL
http://<your-orchard-host>:8080/api
When running locally via trowel dev-server start, the core API listens on port 7778 instead (http://localhost:7778/api).
Authentication
By default, authentication is disabled — all requests are accepted for local development. Pass your cultivator UUID via the X-Cultivator-Id header to identify yourself:
X-Cultivator-Id: <your-cultivator-uuid>
Requests without this header return 401. In production deployments with OAuth2 enabled, a JWT token is used instead. See the Authentication page for details.
Current Cultivator
GET /api/meReturns the cultivator identified by the request's credentials — used by Canopy and the VS Code extension to show who you are signed in as.
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"username": "octocat",
"email": "octocat@example.com"
}Groves
List Groves
GET /api/grovesHeaders: X-Cultivator-Id: <uuid>
Query params: all=true to include CLEARED groves.
Response:
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "my-workspace",
"repositoryUrl": "https://github.com/your-org/your-repo",
"branch": "main",
"commitSha": "a1b2c3d4e5f6",
"state": "FLOURISHING",
"sshConnectionString": "ssh -p 22 dev@203.0.113.10",
"seedling": {
"id": "661f9511-f30c-52e5-b827-557766551111",
"state": "SAPLING",
"ipAddress": "203.0.113.10",
"sshPort": 22,
"cpuCores": 2,
"memoryMb": 2048,
"diskGb": 20
},
"fruits": [
{
"id": "772a0622-041d-63f6-c938-668877662222",
"state": "RIPENING",
"containerId": "abc123def456",
"containerName": "my-workspace_app_1",
"serviceName": "app"
}
],
"plantedAt": "2026-05-01T12:00:00Z",
"lastAccessedAt": "2026-05-01T13:00:00Z"
}
]Plant Grove
POST /api/grovesHeaders: X-Cultivator-Id: <uuid>, Content-Type: application/json
Request body:
{
"repositoryUrl": "https://github.com/your-org/your-repo",
"branch": "main",
"name": "my-workspace",
"machineSize": "small"
}| Field | Required | Description |
|---|---|---|
repositoryUrl | Yes | Git repository URL |
branch | No | Branch to check out (default: main) |
name | No | Friendly name for the grove |
machineSize | No | small, medium, or large (default: small) |
Returns 201 Created with the grove object.
Get Grove
GET /api/groves/{groveId}Clear Grove
DELETE /api/groves/{groveId}Returns 204 No Content.
Get SSH Config
GET /api/groves/{groveId}/ssh-configReturns a plain-text SSH config block for the grove's VM. Only available when the grove is in FLOURISHING state with an active seedling.
Stream Grove Events
GET /api/groves/{groveId}/eventsA Server-Sent Events stream (text/event-stream) that emits a grove-state-changed event whenever the grove transitions between states. Canopy and the VS Code extension use this for live status updates.
event: grove-state-changed
data: {"groveId":"...","previousState":"GROWING","newState":"FLOURISHING"}
Stop Grove
POST /api/groves/{groveId}/actions/stopStops a grove by tearing down its containers and VM, then transitioning it to DORMANT state. Returns 200 OK with the updated grove object.
Start Grove
POST /api/groves/{groveId}/actions/startStarts a dormant grove by re-provisioning its VM and containers. Returns 200 OK with the updated grove object. The grove must be in DORMANT state.
CLI subcommands for stop/start (trowel grove stop / trowel grove start) are coming soon.
Prebuilds
Prebuilds (Greenhouse) cache a repository's container image ahead of time so groves plant faster. This subsystem is still maturing.
POST /api/prebuilds # body: { "repositoryUrl": "...", "branch": "main" }
GET /api/prebuilds # list prebuilds
GET /api/prebuilds/{id} # get a single prebuildGrove States
| State | Description |
|---|---|
PREPARING | Initial setup |
PLANTING | VM and container provisioning in progress |
GROWING | Environment starting up |
FLOURISHING | Ready — SSH access available |
DORMANT | Suspended |
CLEARING | Teardown in progress |
CLEARED | Deleted |
BLIGHTED | Error state |
Health
GET /api/health{
"status": "healthy",
"name": "Orchard",
"version": "0.3.0"
}GET /api/health/readyReturns 200 when the configured seedling provider (QEMU, AWS, etc.) is available, 503 otherwise.
Error Responses
The API returns standard HTTP status codes. Error bodies follow Spring's default error format:
{
"status": 404,
"error": "Not Found",
"message": "..."
}