Download OpenAPI specification:
Trellis is a development environment control plane that unifies local development, parallel branches, remote terminals, and live production logs.
The API uses URL path versioning (/api/v1/...) for major versions. Within a major
version, Stripe-style date-based versioning is supported via the Trellis-Version
HTTP header (e.g., Trellis-Version: 2026-01-17).
By default, the latest behavior is used. Pin to a specific date version for stability when breaking changes are introduced within a major version. The version date represents when a particular API behavior was current.
An official Go client library is available at github.com/wingedpig/trellis/pkg/client.
It provides typed access to all endpoints and supports API versioning. See the
documentation for usage examples.
| Trellis-Version | string^\d{4}-\d{2}-\d{2}$ Example: 2026-01-17 API version date (e.g., 2026-01-17). This header can be sent with any API request. When omitted, the latest API behavior is used. Pin to a specific date for stability across API updates. The Go client library sets this automatically via WithVersion(). |
{- "data": [
- {
- "Name": "string",
- "Status": {
- "State": "stopped",
- "PID": 0,
- "ExitCode": 0,
- "StartedAt": "2019-08-24T14:15:22Z",
- "StoppedAt": "2019-08-24T14:15:22Z",
- "RestartCount": 0,
- "Error": "string"
}, - "Enabled": true,
- "ParserType": "string",
- "Layout": [
- { }
], - "TimestampField": "string",
- "LevelField": "string",
- "MessageField": "string"
}
], - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "Name": "string",
- "Status": {
- "State": "stopped",
- "PID": 0,
- "ExitCode": 0,
- "StartedAt": "2019-08-24T14:15:22Z",
- "StoppedAt": "2019-08-24T14:15:22Z",
- "RestartCount": 0,
- "Error": "string"
}, - "Enabled": true,
- "ParserType": "string",
- "Layout": [
- { }
], - "TimestampField": "string",
- "LevelField": "string",
- "MessageField": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "Name": "string",
- "Status": {
- "State": "stopped",
- "PID": 0,
- "ExitCode": 0,
- "StartedAt": "2019-08-24T14:15:22Z",
- "StoppedAt": "2019-08-24T14:15:22Z",
- "RestartCount": 0,
- "Error": "string"
}, - "Enabled": true,
- "ParserType": "string",
- "Layout": [
- { }
], - "TimestampField": "string",
- "LevelField": "string",
- "MessageField": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "Name": "string",
- "Status": {
- "State": "stopped",
- "PID": 0,
- "ExitCode": 0,
- "StartedAt": "2019-08-24T14:15:22Z",
- "StoppedAt": "2019-08-24T14:15:22Z",
- "RestartCount": 0,
- "Error": "string"
}, - "Enabled": true,
- "ParserType": "string",
- "Layout": [
- { }
], - "TimestampField": "string",
- "LevelField": "string",
- "MessageField": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "Name": "string",
- "Status": {
- "State": "stopped",
- "PID": 0,
- "ExitCode": 0,
- "StartedAt": "2019-08-24T14:15:22Z",
- "StoppedAt": "2019-08-24T14:15:22Z",
- "RestartCount": 0,
- "Error": "string"
}, - "Enabled": true,
- "ParserType": "string",
- "Layout": [
- { }
], - "TimestampField": "string",
- "LevelField": "string",
- "MessageField": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| name required | string Service name |
| lines | integer Default: 100 Number of log lines to return |
{- "data": {
- "service": "string",
- "entries": [
- {
- "timestamp": "2019-08-24T14:15:22Z",
- "level": "trace",
- "message": "string",
- "fields": { },
- "raw": "string",
- "source": "string",
- "offset": 0,
- "sequence": 0
}
], - "lines": [
- "string"
]
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| Trellis-Version | string^\d{4}-\d{2}-\d{2}$ Example: 2026-01-17 API version date (e.g., 2026-01-17). This header can be sent with any API request. When omitted, the latest API behavior is used. Pin to a specific date for stability across API updates. The Go client library sets this automatically via WithVersion(). |
{- "data": {
- "worktrees": [
- {
- "Path": "string",
- "Branch": "string",
- "Commit": "string",
- "Detached": true,
- "IsBare": true,
- "Dirty": true,
- "Ahead": 0,
- "Behind": 0,
- "Active": true
}
]
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| branch_name required | string Branch name to create worktree from |
| switch_to | boolean Default: false Whether to activate the new worktree |
{- "branch_name": "string",
- "switch_to": false
}{- "data": {
- "worktree": {
- "Path": "string",
- "Branch": "string",
- "Commit": "string",
- "Detached": true,
- "IsBare": true,
- "Dirty": true,
- "Ahead": 0,
- "Behind": 0,
- "Active": true
}
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "worktrees": [
- {
- "Path": "string",
- "Branch": "string",
- "Commit": "string",
- "Detached": true,
- "IsBare": true,
- "Dirty": true,
- "Ahead": 0,
- "Behind": 0,
- "Active": true
}
], - "project_name": "string",
- "binaries_dir": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "Path": "string",
- "Branch": "string",
- "Commit": "string",
- "Detached": true,
- "IsBare": true,
- "Dirty": true,
- "Ahead": 0,
- "Behind": 0,
- "Active": true
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| name required | string Worktree name |
| delete_branch | boolean Default: false Whether to delete the associated branch |
{- "data": {
- "removed": "string",
- "branch_deleted": true
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "worktree": {
- "Path": "string",
- "Branch": "string",
- "Commit": "string",
- "Detached": true,
- "IsBare": true,
- "Dirty": true,
- "Ahead": 0,
- "Behind": 0,
- "Active": true
}, - "hook_results": [
- {
- "name": "string",
- "success": true,
- "output": "string",
- "error": "string",
- "duration": "string"
}
], - "duration": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| Trellis-Version | string^\d{4}-\d{2}-\d{2}$ Example: 2026-01-17 API version date (e.g., 2026-01-17). This header can be sent with any API request. When omitted, the latest API behavior is used. Pin to a specific date for stability across API updates. The Go client library sets this automatically via WithVersion(). |
{- "data": [
- {
- "ID": "string",
- "Name": "string",
- "Description": "string",
- "Command": [
- "string"
], - "Commands": [
- [
- "string"
]
], - "Timeout": 0,
- "OutputParser": "string",
- "Confirm": true,
- "ConfirmMessage": "string",
- "RequiresStopped": [
- "string"
], - "RestartServices": true,
- "Inputs": [
- {
- "Name": "string",
- "Type": "text",
- "Label": "string",
- "Description": "string",
- "Placeholder": "string",
- "Options": [
- "string"
], - "AllowedValues": [
- "string"
], - "Pattern": "string",
- "Default": null,
- "Required": true
}
]
}
], - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "ID": "string",
- "Name": "string",
- "Description": "string",
- "Command": [
- "string"
], - "Commands": [
- [
- "string"
]
], - "Timeout": 0,
- "OutputParser": "string",
- "Confirm": true,
- "ConfirmMessage": "string",
- "RequiresStopped": [
- "string"
], - "RestartServices": true,
- "Inputs": [
- {
- "Name": "string",
- "Type": "text",
- "Label": "string",
- "Description": "string",
- "Placeholder": "string",
- "Options": [
- "string"
], - "AllowedValues": [
- "string"
], - "Pattern": "string",
- "Default": null,
- "Required": true
}
]
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| id required | string Workflow ID |
| worktree | string Worktree to run workflow in |
Workflow inputs
object Input values keyed by input name |
{- "inputs": { }
}{- "data": {
- "ID": "string",
- "Name": "string",
- "State": "pending",
- "StartedAt": "2019-08-24T14:15:22Z",
- "FinishedAt": "2019-08-24T14:15:22Z",
- "Duration": 0,
- "Success": true,
- "ExitCode": 0,
- "Output": "string",
- "OutputHTML": "string",
- "ParsedLines": [
- {
- "Type": "error",
- "File": "string",
- "Line": 0,
- "Column": 0,
- "Message": "string",
- "Package": "string",
- "TestName": "string",
- "RawOutput": "string",
- "StackTrace": [
- "string"
]
}
], - "Error": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "ID": "string",
- "Name": "string",
- "State": "pending",
- "StartedAt": "2019-08-24T14:15:22Z",
- "FinishedAt": "2019-08-24T14:15:22Z",
- "Duration": 0,
- "Success": true,
- "ExitCode": 0,
- "Output": "string",
- "OutputHTML": "string",
- "ParsedLines": [
- {
- "Type": "error",
- "File": "string",
- "Line": 0,
- "Column": 0,
- "Message": "string",
- "Package": "string",
- "TestName": "string",
- "RawOutput": "string",
- "StackTrace": [
- "string"
]
}
], - "Error": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| type | Array of strings Event types to filter (supports wildcards) |
| worktree | string Filter by worktree name |
| limit | integer Maximum events to return |
| since | string <date-time> Events after this time |
| until | string <date-time> Events before this time |
{- "data": [
- {
- "id": "string",
- "version": "string",
- "type": "string",
- "timestamp": "2019-08-24T14:15:22Z",
- "worktree": "string",
- "payload": { }
}
], - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| name required | string Log viewer name |
| filter | string Filter expression |
| limit | integer Default: 1000 Maximum entries to return |
| before | string <date-time> Only entries before this time |
| after | string <date-time> Only entries after this time |
{- "data": {
- "entries": [
- {
- "timestamp": "2019-08-24T14:15:22Z",
- "level": "trace",
- "message": "string",
- "fields": { },
- "raw": "string",
- "source": "string",
- "offset": 0,
- "sequence": 0
}
], - "count": 0,
- "sequence": 0
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| name required | string Log viewer name |
| start required | string <date-time> Start of time range |
| end required | string <date-time> End of time range |
| filter | string Filter expression |
| limit | integer Default: 10000 Maximum entries |
| grep | string Grep pattern for matching |
| before | integer Context lines before match |
| after | integer Context lines after match |
{- "data": {
- "entries": [
- {
- "timestamp": "2019-08-24T14:15:22Z",
- "level": "trace",
- "message": "string",
- "fields": { },
- "raw": "string",
- "source": "string",
- "offset": 0,
- "sequence": 0
}
], - "count": 0,
- "start": "2019-08-24T14:15:22Z",
- "end": "2019-08-24T14:15:22Z"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| name required | string Log viewer name |
| filter | string Initial filter expression |
{- "error": {
- "code": "string",
- "message": "string",
- "details": { }
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| id required | string Trace ID to search for |
| group required | string Trace group name |
| start required | string <date-time> Start of time range |
| end | string <date-time> End of time range (default now) |
| name | string Report name (auto-generated if empty) |
| expand_by_id | boolean Default: true Whether to expand by ID |
{- "id": "string",
- "group": "string",
- "start": "2019-08-24T14:15:22Z",
- "end": "2019-08-24T14:15:22Z",
- "name": "string",
- "expand_by_id": true
}{- "data": {
- "name": "string",
- "status": "completed",
- "total_entries": 0,
- "sources": {
- "property1": 0,
- "property2": 0
}, - "duration_ms": 0,
- "error": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "reports": [
- {
- "name": "string",
- "trace_id": "string",
- "group": "string",
- "status": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "entry_count": 0,
- "time_start": "2019-08-24T14:15:22Z",
- "time_end": "2019-08-24T14:15:22Z"
}
]
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "version": "string",
- "name": "string",
- "trace_id": "string",
- "group": "string",
- "status": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "time_range": {
- "start": "2019-08-24T14:15:22Z",
- "end": "2019-08-24T14:15:22Z"
}, - "summary": {
- "total_entries": 0,
- "by_source": {
- "property1": 0,
- "property2": 0
}, - "by_level": {
- "property1": 0,
- "property2": 0
}, - "duration_ms": 0
}, - "entries": [
- {
- "timestamp": "2019-08-24T14:15:22Z",
- "source": "string",
- "level": "string",
- "message": "string",
- "fields": { },
- "raw": "string",
- "is_context": true
}
], - "error": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "version": "string",
- "id": "string",
- "service": "string",
- "timestamp": "2019-08-24T14:15:22Z",
- "trace_id": "string",
- "exit_code": 0,
- "error": "string",
- "worktree": {
- "name": "string",
- "branch": "string",
- "path": "string"
}, - "summary": {
- "total_entries": 0,
- "by_source": {
- "property1": 0,
- "property2": 0
}, - "by_level": {
- "property1": 0,
- "property2": 0
}
}, - "entries": [
- {
- "timestamp": "2019-08-24T14:15:22Z",
- "source": "string",
- "level": "string",
- "message": "string",
- "fields": { },
- "raw": "string"
}
], - "trigger": "string"
}
}{- "data": {
- "version": "string",
- "id": "string",
- "service": "string",
- "timestamp": "2019-08-24T14:15:22Z",
- "trace_id": "string",
- "exit_code": 0,
- "error": "string",
- "worktree": {
- "name": "string",
- "branch": "string",
- "path": "string"
}, - "summary": {
- "total_entries": 0,
- "by_source": {
- "property1": 0,
- "property2": 0
}, - "by_level": {
- "property1": 0,
- "property2": 0
}
}, - "entries": [
- {
- "timestamp": "2019-08-24T14:15:22Z",
- "source": "string",
- "level": "string",
- "message": "string",
- "fields": { },
- "raw": "string"
}
], - "trigger": "string"
}
}| session required | string Session name |
| window required | string Window name |
| remote | integer Enum: 0 1 Whether this is a remote connection |
{- "error": {
- "code": "string",
- "message": "string",
- "details": { }
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| worktree required | string Worktree name |
| name | string Window name (auto-generated if omitted) |
| command | string Command to execute in the window |
{- "name": "string",
- "command": "string"
}{- "name": "string",
- "session": "string"
}| worktree required | string Worktree name |
| window required | string Window name |
| name required | string New window name |
{- "name": "string"
}{- "error": {
- "code": "string",
- "message": "string",
- "details": { }
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| message required | string Notification message |
| type | string Default: "done" Enum: "done" "blocked" "error" Notification type |
{- "message": "string",
- "type": "done"
}{- "data": {
- "id": "string",
- "type": "string",
- "timestamp": "2019-08-24T14:15:22Z"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| worktree required | string Worktree name |
| title required | string Case title |
| kind | string Default: "task" Enum: "task" "bug" "feature" "investigation" Case kind |
{- "title": "string",
- "kind": "task"
}{- "schema": "trellis.case.v1",
- "id": "string",
- "title": "string",
- "kind": "task",
- "status": "open",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "worktree": {
- "name": "string",
- "branch": "string",
- "base_commit": "string"
}, - "links": [
- {
- "title": "string",
- "url": "string"
}
], - "evidence": [
- {
- "title": "string",
- "filename": "string",
- "format": "string",
- "tags": [
- "string"
], - "added_at": "2019-08-24T14:15:22Z"
}
], - "claude": [
- {
- "id": "string",
- "title": "string",
- "filename": "string",
- "exported_at": "2019-08-24T14:15:22Z",
- "message_count": 0,
- "preview": "string",
- "source_session_id": "string"
}
], - "codex": [
- {
- "id": "string",
- "title": "string",
- "filename": "string",
- "exported_at": "2019-08-24T14:15:22Z",
- "message_count": 0,
- "preview": "string",
- "source_session_id": "string"
}
], - "commits": [
- {
- "sha": "string",
- "short_sha": "string",
- "committed_at": "2019-08-24T14:15:22Z",
- "message": "string",
- "description": "string",
- "files_changed": [
- "string"
]
}
], - "summary": {
- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
], - "generated_at": "2019-08-24T14:15:22Z",
- "model": "string"
}
}| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
{- "schema": "trellis.case.v1",
- "id": "string",
- "title": "string",
- "kind": "task",
- "status": "open",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "worktree": {
- "name": "string",
- "branch": "string",
- "base_commit": "string"
}, - "links": [
- {
- "title": "string",
- "url": "string"
}
], - "evidence": [
- {
- "title": "string",
- "filename": "string",
- "format": "string",
- "tags": [
- "string"
], - "added_at": "2019-08-24T14:15:22Z"
}
], - "claude": [
- {
- "id": "string",
- "title": "string",
- "filename": "string",
- "exported_at": "2019-08-24T14:15:22Z",
- "message_count": 0,
- "preview": "string",
- "source_session_id": "string"
}
], - "codex": [
- {
- "id": "string",
- "title": "string",
- "filename": "string",
- "exported_at": "2019-08-24T14:15:22Z",
- "message_count": 0,
- "preview": "string",
- "source_session_id": "string"
}
], - "commits": [
- {
- "sha": "string",
- "short_sha": "string",
- "committed_at": "2019-08-24T14:15:22Z",
- "message": "string",
- "description": "string",
- "files_changed": [
- "string"
]
}
], - "summary": {
- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
], - "generated_at": "2019-08-24T14:15:22Z",
- "model": "string"
}
}| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
| title | string |
| kind | string Enum: "task" "bug" "feature" "investigation" |
| status | string Enum: "open" "resolved" "wontfix" |
Array of objects (CaseLink) Full array replaces existing links | |
| notes | string Overwrites notes.md content |
{- "title": "string",
- "kind": "task",
- "status": "open",
- "links": [
- {
- "title": "string",
- "url": "string"
}
], - "notes": "string"
}{- "error": {
- "code": "string",
- "message": "string",
- "details": { }
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
{- "error": {
- "code": "string",
- "message": "string",
- "details": { }
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
| file required | string <binary> Evidence file to attach |
| title | string Title (defaults to filename) |
| tags | Array of strings Tags for the evidence |
{- "title": "string",
- "filename": "string",
- "format": "string",
- "tags": [
- "string"
], - "added_at": "2019-08-24T14:15:22Z"
}| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
| session_id required | string Claude session UUID |
| title | string Transcript title (defaults to session display name) |
{- "session_id": "string",
- "title": "string"
}{- "claude_ref_id": "string",
- "title": "string"
}| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
| claude_id required | string Claude transcript reference ID |
{- "claude_ref_id": "string",
- "message_count": 0
}| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
| claude_id required | string Claude transcript reference ID |
{- "id": "string",
- "worktree_name": "string",
- "display_name": "string",
- "last_user_input": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "trashed_at": "2019-08-24T14:15:22Z"
}| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
| report_name required | string Name of trace report to save |
{- "report_name": "string"
}{- "trace_ref_id": "string",
- "report_name": "string"
}| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
| trace_id required | string Trace reference ID |
{- "error": {
- "code": "string",
- "message": "string",
- "details": { }
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}Scans case.json files (title, summary fields, commit descriptions) and
notes.md for archived cases in the worktree, applying optional filters
and ranking. Keyword and component matches rank above title matches,
which rank above notes / commit-description matches.
| worktree required | string Worktree name |
| q | string Free-text query |
| kind | string Enum: "task" "bug" "feature" "investigation" |
| from | string Inclusive lower bound on created_at — accepts YYYY-MM-DD or RFC 3339 |
| to | string Inclusive upper bound on created_at — accepts YYYY-MM-DD or RFC 3339 |
| has_traces | string Set to "1" to require at least one linked trace |
| include_transcripts | string Set to "1" to also scan transcript previews (slower path) |
| sort | string Default: "date" Enum: "date" "kind" "duration" "worktree" Sort key (results are always grouped by score first) |
[- {
- "id": "string",
- "title": "string",
- "kind": "task",
- "status": "open",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "worktree": "string",
- "score": 0,
- "snippet": "string",
- "summary": {
- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
], - "generated_at": "2019-08-24T14:15:22Z",
- "model": "string"
}
}
]| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
| synopsis | string |
| symptoms | string |
| root_cause | string |
| resolution | string |
| components | Array of strings |
| keywords | Array of strings |
{- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
]
}{- "error": {
- "code": "string",
- "message": "string",
- "details": { }
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}Calls claude -p with the case's accumulated state (notes, commit
descriptions, attached transcripts, linked traces) and replaces the
stored summary. The client is expected to confirm before calling this
if hand-edits may exist.
| worktree required | string Worktree name |
| id required | string Case ID (e.g., 2026-02-19__fix-login-crash) |
{- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
], - "generated_at": "2019-08-24T14:15:22Z",
- "model": "string"
}[- {
- "id": "string",
- "worktree_name": "string",
- "display_name": "string",
- "last_user_input": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "trashed_at": "2019-08-24T14:15:22Z"
}
]| worktree required | string Worktree name |
| display_name | string Session display name (auto-generated if omitted) |
{- "display_name": "string"
}{- "id": "string",
- "worktree_name": "string",
- "display_name": "string",
- "last_user_input": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "trashed_at": "2019-08-24T14:15:22Z"
}| worktree required | string Worktree name |
| schema | string |
| exported_at | string <date-time> |
object | |
Array of objects (ClaudeMessage) | |
object |
{- "schema": "string",
- "exported_at": "2019-08-24T14:15:22Z",
- "source": {
- "trellis_session_id": "string",
- "claude_session_id": "string",
- "worktree": "string",
- "branch": "string",
- "display_name": "string",
- "project_path": "string",
- "created_at": "2019-08-24T14:15:22Z"
}, - "messages": [
- {
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": "string",
- "id": "string",
- "name": "string",
- "input": { },
- "tool_use_id": "string",
- "content": "string"
}
], - "timestamp": "2019-08-24T14:15:22Z"
}
], - "stats": {
- "message_count": 0,
- "user_turns": 0,
- "assistant_turns": 0,
- "tool_uses": 0
}
}{- "id": "string",
- "worktree_name": "string",
- "display_name": "string",
- "last_user_input": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "trashed_at": "2019-08-24T14:15:22Z"
}[- {
- "id": "string",
- "worktree_name": "string",
- "display_name": "string",
- "last_user_input": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "trashed_at": "2019-08-24T14:15:22Z"
}
]| session required | string Claude session UUID |
| display_name required | string New display name |
{- "display_name": "string"
}{- "error": {
- "code": "string",
- "message": "string",
- "details": { }
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| session required | string Claude session UUID |
| level | string Default: "full" Enum: "full" "summary" Export detail level |
{- "schema": "string",
- "exported_at": "2019-08-24T14:15:22Z",
- "source": {
- "trellis_session_id": "string",
- "claude_session_id": "string",
- "worktree": "string",
- "branch": "string",
- "display_name": "string",
- "project_path": "string",
- "created_at": "2019-08-24T14:15:22Z"
}, - "messages": [
- {
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": "string",
- "id": "string",
- "name": "string",
- "input": { },
- "tool_use_id": "string",
- "content": "string"
}
], - "timestamp": "2019-08-24T14:15:22Z"
}
], - "stats": {
- "message_count": 0,
- "user_turns": 0,
- "assistant_turns": 0,
- "tool_uses": 0
}
}Creates a new Claude session in the same worktree as the source,
pre-populated with the source session's messages[0..message_index]
(inclusive). The source session is untouched. The Claude CLI's JSONL
session file is rewritten for the new session so --resume continues
from exactly that point.
| session required | string Claude session UUID |
| message_index required | integer >= 0 0-based inclusive index of the last message to include in the fork |
| display_name required | string Display name for the new session |
{- "message_index": 0,
- "display_name": "string"
}{- "data": {
- "id": "string",
- "worktree_name": "string",
- "display_name": "string",
- "last_user_input": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "trashed_at": "2019-08-24T14:15:22Z"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}Creates a new git worktree on the given branch, copies the selected
uncommitted files from the source worktree into it, reverts those files
in the source (via git checkout -- for tracked files or delete for
untracked files), and rebinds the Claude session to the new worktree.
The running Claude process is stopped; it will restart in the new
working directory on the next message.
| session required | string Claude session UUID |
| branch required | string Branch name for the new worktree (must not already exist) |
| files | Array of strings Relative paths (from the source worktree root) of files to move. May include modified, added, or untracked files. Directories and symlinks are not supported. |
{- "branch": "string",
- "files": [
- "string"
]
}{- "data": {
- "session_id": "string",
- "worktree": "string",
- "branch": "string",
- "path": "string",
- "revert_errors": [
- "string"
]
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}{- "data": {
- "clean": true,
- "modified": [
- "string"
], - "added": [
- "string"
], - "deleted": [
- "string"
], - "renamed": [
- "string"
], - "untracked": [
- "string"
], - "branch": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| worktree required | string Worktree name |
| session_id required | string Claude session ID to look up |
{- "data": {
- "case_id": "string",
- "title": "string",
- "kind": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}Wrap Up is the shared commitToCase orchestrator with archive: true.
It generates a case summary via claude -p, archives the case directory
from cases/ to cases-archived/, includes the archived directory in
the git commit, and trashes the active session.
| worktree required | string Worktree name |
| session_id | string Active Claude/Codex session ID. Used to attach the session transcript when a case is being created. |
| case_id | string Explicit case ID. Omit to bind to the worktree's open case (or create one if none exists). |
| title | string New-case title — required only when no open case exists and no case_id is supplied. |
| kind | string Enum: "task" "bug" "feature" "investigation" New-case kind. Defaults to |
| commit_message required | string |
| description | string Per-commit case description (intermediate commits only — recorded on the CommitEntry). |
| files | Array of strings Files to git add. Paths under the live cases directory are rejected. |
Array of objects (CaseLink) (Wrap-up only) Links to merge into the case. | |
| traces | Array of strings (Wrap-up only) Trace report names to save into the case. |
Array of objects (Wrap-up only) Other-agent sessions to capture into the case and trash. | |
object (Wrap-up only) User-curated summary from the modal. When non-nil and
synopsis is non-empty, the server uses this summary verbatim
(with light normalization on components/keywords) and skips the
in-line |
{- "session_id": "string",
- "case_id": "string",
- "title": "string",
- "kind": "task",
- "commit_message": "string",
- "description": "string",
- "files": [
- "string"
], - "links": [
- {
- "title": "string",
- "url": "string"
}
], - "traces": [
- "string"
], - "related_sessions": [
- {
- "agent": "claude",
- "session_id": "string"
}
], - "summary": {
- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
], - "generated_at": "2019-08-24T14:15:22Z",
- "model": "string"
}
}{- "data": {
- "case_id": "string",
- "commit_hash": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}Same orchestrator as wrap-up but archive: false. Creates the case on
first commit if none exists; binds to the worktree's single open case
otherwise. Appends a CommitEntry to case.json and leaves the case open
and the session alive.
| worktree required | string Worktree name |
| session_id | string Active Claude/Codex session ID. Used to attach the session transcript when a case is being created. |
| case_id | string Explicit case ID. Omit to bind to the worktree's open case (or create one if none exists). |
| title | string New-case title — required only when no open case exists and no case_id is supplied. |
| kind | string Enum: "task" "bug" "feature" "investigation" New-case kind. Defaults to |
| commit_message required | string |
| description | string Per-commit case description (intermediate commits only — recorded on the CommitEntry). |
| files | Array of strings Files to git add. Paths under the live cases directory are rejected. |
Array of objects (CaseLink) (Wrap-up only) Links to merge into the case. | |
| traces | Array of strings (Wrap-up only) Trace report names to save into the case. |
Array of objects (Wrap-up only) Other-agent sessions to capture into the case and trash. | |
object (Wrap-up only) User-curated summary from the modal. When non-nil and
synopsis is non-empty, the server uses this summary verbatim
(with light normalization on components/keywords) and skips the
in-line |
{- "session_id": "string",
- "case_id": "string",
- "title": "string",
- "kind": "task",
- "commit_message": "string",
- "description": "string",
- "files": [
- "string"
], - "links": [
- {
- "title": "string",
- "url": "string"
}
], - "traces": [
- "string"
], - "related_sessions": [
- {
- "agent": "claude",
- "session_id": "string"
}
], - "summary": {
- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
], - "generated_at": "2019-08-24T14:15:22Z",
- "model": "string"
}
}{- "data": {
- "case_id": "string",
- "commit_hash": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}Shells out to claude -p --output-format json with a diff covering
exactly the files the caller passes in files (NOT git diff --staged
— the staging area may hold unrelated work; HEAD-vs-WT includes files
the user unchecked). Inputs also include the case manifest, notes, and
a few recent user messages from the session. Returns a freeform commit
message and a 1-2 sentence per-commit description (the "narrative
beat"). No Anthropic API key is required — uses the user's existing
Claude Code authentication.
| worktree required | string Worktree name |
| files required | Array of strings Files the user has selected for this commit. The generated message describes the diff of exactly these files. |
| session_id | string |
| case_id | string |
| title | string New-case title — used when no case yet exists |
| kind | string Enum: "task" "bug" "feature" "investigation" |
{- "files": [
- "string"
], - "session_id": "string",
- "case_id": "string",
- "title": "string",
- "kind": "task"
}{- "data": {
- "message": "string",
- "description": "string",
- "model": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}Runs the case summary generator (claude -p) against the supplied
case context without committing. Used by the wrap-up modal so the
user can review and prune the generated components and keywords
before confirming. The client is expected to send the (possibly
edited) summary back as summary on the wrap-up request.
| worktree required | string Worktree name |
| case_id | string Case to summarize. If omitted, the worktree's open case is used. |
| files | Array of strings Files selected for the wrap-up commit — scopes the diff input. |
{- "case_id": "string",
- "files": [
- "string"
]
}{- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
], - "generated_at": "2019-08-24T14:15:22Z",
- "model": "string"
}| worktree required | string Worktree name |
| session_id | string Active Claude/Codex session ID. Used to attach the session transcript when a case is being created. |
| case_id | string Explicit case ID. Omit to bind to the worktree's open case (or create one if none exists). |
| title | string New-case title — required only when no open case exists and no case_id is supplied. |
| kind | string Enum: "task" "bug" "feature" "investigation" New-case kind. Defaults to |
| commit_message required | string |
| description | string Per-commit case description (intermediate commits only — recorded on the CommitEntry). |
| files | Array of strings Files to git add. Paths under the live cases directory are rejected. |
Array of objects (CaseLink) (Wrap-up only) Links to merge into the case. | |
| traces | Array of strings (Wrap-up only) Trace report names to save into the case. |
Array of objects (Wrap-up only) Other-agent sessions to capture into the case and trash. | |
object (Wrap-up only) User-curated summary from the modal. When non-nil and
synopsis is non-empty, the server uses this summary verbatim
(with light normalization on components/keywords) and skips the
in-line |
{- "session_id": "string",
- "case_id": "string",
- "title": "string",
- "kind": "task",
- "commit_message": "string",
- "description": "string",
- "files": [
- "string"
], - "links": [
- {
- "title": "string",
- "url": "string"
}
], - "traces": [
- "string"
], - "related_sessions": [
- {
- "agent": "claude",
- "session_id": "string"
}
], - "summary": {
- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
], - "generated_at": "2019-08-24T14:15:22Z",
- "model": "string"
}
}{- "data": {
- "case_id": "string",
- "commit_hash": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| worktree required | string Worktree name |
| session_id | string Active Claude/Codex session ID. Used to attach the session transcript when a case is being created. |
| case_id | string Explicit case ID. Omit to bind to the worktree's open case (or create one if none exists). |
| title | string New-case title — required only when no open case exists and no case_id is supplied. |
| kind | string Enum: "task" "bug" "feature" "investigation" New-case kind. Defaults to |
| commit_message required | string |
| description | string Per-commit case description (intermediate commits only — recorded on the CommitEntry). |
| files | Array of strings Files to git add. Paths under the live cases directory are rejected. |
Array of objects (CaseLink) (Wrap-up only) Links to merge into the case. | |
| traces | Array of strings (Wrap-up only) Trace report names to save into the case. |
Array of objects (Wrap-up only) Other-agent sessions to capture into the case and trash. | |
object (Wrap-up only) User-curated summary from the modal. When non-nil and
synopsis is non-empty, the server uses this summary verbatim
(with light normalization on components/keywords) and skips the
in-line |
{- "session_id": "string",
- "case_id": "string",
- "title": "string",
- "kind": "task",
- "commit_message": "string",
- "description": "string",
- "files": [
- "string"
], - "links": [
- {
- "title": "string",
- "url": "string"
}
], - "traces": [
- "string"
], - "related_sessions": [
- {
- "agent": "claude",
- "session_id": "string"
}
], - "summary": {
- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
], - "generated_at": "2019-08-24T14:15:22Z",
- "model": "string"
}
}{- "data": {
- "case_id": "string",
- "commit_hash": "string"
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}| worktree required | string Worktree name |
| case_id | string |
| files | Array of strings |
{- "case_id": "string",
- "files": [
- "string"
]
}{- "synopsis": "string",
- "symptoms": "string",
- "root_cause": "string",
- "resolution": "string",
- "components": [
- "string"
], - "keywords": [
- "string"
], - "generated_at": "2019-08-24T14:15:22Z",
- "model": "string"
}| worktree required | string Worktree name |
| files required | Array of strings Files the user has selected for this commit. |
| session_id | string |
| case_id | string |
| title | string |
| kind | string Enum: "task" "bug" "feature" "investigation" |
{- "files": [
- "string"
], - "session_id": "string",
- "case_id": "string",
- "title": "string",
- "kind": "task"
}{- "data": {
- "message": "string",
- "description": "string",
- "model": "string"
}
}Returns every active Claude and Codex session across all worktrees,
with a coarse running / needs_you state and the timestamp of the
last state transition. The inbox popup uses this for its initial
render; thereafter it relies on the session.state_changed events
delivered over the inbox WebSocket.
[- {
- "id": "string",
- "agent": "claude",
- "worktree": "string",
- "display_name": "string",
- "state": "running",
- "trashed": true,
- "last_state_change_at": "2019-08-24T14:15:22Z"
}
]Single WebSocket endpoint that serves two roles via the role
query parameter:
role=inbox — opened by the floating inbox popup. Receives
state_changed events; can send {type:"navigate", path:"..."}
commands which the server forwards to every connected role=main.
If no main window is connected, the server replies to the popup
with navigate_failed.
role=main — opened by every regular Trellis page via
inbox_main_ws.js. Receives {type:"navigate", path:"..."}
commands and acts on them by setting window.location.href.
Reads are drained for close detection only; clients never send
application messages.
| role required | string Enum: "inbox" "main" |
{- "error": {
- "code": "string",
- "message": "string",
- "details": { }
}, - "meta": {
- "timestamp": "2019-08-24T14:15:22Z"
}
}