1896 lines
82 KiB
YAML
1896 lines
82 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: byre
|
|
version: 0.0.0
|
|
paths:
|
|
/api/me:
|
|
get:
|
|
operationId: getMe
|
|
responses:
|
|
"200":
|
|
description: The calling user.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/User" }
|
|
put:
|
|
operationId: updateMe
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/UserUpdate" }
|
|
responses:
|
|
"200":
|
|
description: The updated user.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/User" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/me/notifications:
|
|
put:
|
|
operationId: updateNotificationPrefs
|
|
description: Sets which new inbox items notify the calling user in their open byre pages.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/NotificationPrefs" }
|
|
responses:
|
|
"200":
|
|
description: The updated user.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/User" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/me/default-model:
|
|
put:
|
|
operationId: updateDefaultModel
|
|
description: Sets the model the calling user's app starts new tasks on.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/DefaultModel" }
|
|
responses:
|
|
"200":
|
|
description: The updated user.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/User" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/me/lead/sessions:
|
|
get:
|
|
operationId: listLeadSessions
|
|
description: The calling user's lead agent sessions, oldest first. A compaction completes one and starts the next.
|
|
responses:
|
|
"200":
|
|
description: The sessions.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AgentSession" }
|
|
|
|
/api/me/lead/events:
|
|
get:
|
|
operationId: listLeadEvents
|
|
description: >
|
|
The calling user's lead events, oldest first, a page of whole turns: those after the turns+1'th turn.ended
|
|
before the before seq (or before the latest event when before is absent). Page back by passing the first
|
|
event's seq as before.
|
|
parameters:
|
|
- { name: before, in: query, required: false, schema: { type: integer, format: int64 } }
|
|
- { name: turns, in: query, required: false, schema: { type: integer, minimum: 1, maximum: 500 } }
|
|
responses:
|
|
"200":
|
|
description: Up to turns turns (default 50), plus any turn still running when before is absent.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/EventPage" }
|
|
|
|
/api/me/lead/messages:
|
|
post:
|
|
operationId: messageLead
|
|
description: >
|
|
Sends a message to the calling user's lead agent, starting a lead session when there is none.
|
|
While the lead is mid-turn the message is held and sent as its next turn.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/MessageCreate" }
|
|
responses:
|
|
"202":
|
|
description: The lead session the message went to or is held for.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/me/lead/notes:
|
|
get:
|
|
operationId: listLeadNotes
|
|
description: What the calling user's lead agent has noted about how they work, oldest first. The lead keeps them with its remember and forget tools.
|
|
responses:
|
|
"200":
|
|
description: The notes.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/LeadNote" }
|
|
|
|
/api/me/lead/notes/{noteId}:
|
|
parameters:
|
|
- { name: noteId, in: path, required: true, schema: { type: string } }
|
|
delete:
|
|
operationId: deleteLeadNote
|
|
responses:
|
|
"204":
|
|
description: Deleted.
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/me/focus:
|
|
get:
|
|
operationId: getFocus
|
|
responses:
|
|
"200":
|
|
description: What the calling user's right pane shows.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Focus" }
|
|
put:
|
|
operationId: setFocus
|
|
description: Records the human switching the right pane's project, task or tab.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Focus" }
|
|
responses:
|
|
"200":
|
|
description: The stored focus.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Focus" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/me/summary-reads:
|
|
get:
|
|
operationId: getSummaryReads
|
|
responses:
|
|
"200":
|
|
description: For each active task the calling user has read a turn summary of, the highest seq read.
|
|
content:
|
|
application/json:
|
|
schema: { type: object, additionalProperties: { type: integer, format: int64 } }
|
|
|
|
/api/me/pane-focus:
|
|
put:
|
|
operationId: setPaneFocus
|
|
description: Records whether the human is working in the right pane, and whether they have unsent text there. While they are working in it, the lead agent can move it only in the cases its show tool describes.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/PaneFocus" }
|
|
responses:
|
|
"204":
|
|
description: Recorded.
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/projects:
|
|
get:
|
|
operationId: listProjects
|
|
responses:
|
|
"200":
|
|
description: All projects.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Project" }
|
|
post:
|
|
operationId: createProject
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/ProjectCreate" }
|
|
responses:
|
|
"201":
|
|
description: The new project.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Project" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/projects/{projectId}:
|
|
parameters:
|
|
- { name: projectId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getProject
|
|
responses:
|
|
"200":
|
|
description: The project.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Project" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/projects/{projectId}/tasks:
|
|
parameters:
|
|
- { name: projectId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listTasks
|
|
responses:
|
|
"200":
|
|
description: The project's tasks, newest first.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Task" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
post:
|
|
operationId: createTask
|
|
description: >
|
|
Creates the task's branch and worktree from the project's default branch, and with prompt starts its agent, or
|
|
with workflow, starts a run of that workflow from it.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TaskCreate" }
|
|
responses:
|
|
"201":
|
|
description: The new task.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/projects/{projectId}/todo:
|
|
parameters:
|
|
- { name: projectId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTodo
|
|
description: The items of TODO.md at the root of the project's default branch, in file order.
|
|
responses:
|
|
"200":
|
|
description: The items; exists is false when the default branch has no TODO.md.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Todo" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/projects/{projectId}/todo/tasks:
|
|
parameters:
|
|
- { name: projectId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: startTodoItem
|
|
description: >
|
|
Creates a task for a TODO.md item, recording the item as its todo_item, and starts its agent with the item as
|
|
the first message. Refused while another active task has the same item.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TodoStart" }
|
|
responses:
|
|
"201":
|
|
description: The new task.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTask
|
|
responses:
|
|
"200":
|
|
description: The task.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/workflow:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskWorkflow
|
|
description: >
|
|
The workflow the task froze when it was created, as it was then. Later edits and deletes of the workflow
|
|
don't change it.
|
|
responses:
|
|
"200":
|
|
description: The frozen workflow.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TaskWorkflow" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/summary-read:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
put:
|
|
operationId: markSummaryRead
|
|
description: Records that the calling user has read the task's turn summaries up to seq. A seq at or below the one already recorded changes nothing; a higher one emits summary.read, owned by the user.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/SummaryRead" }
|
|
responses:
|
|
"204":
|
|
description: Recorded.
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/workflow/run:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getWorkflowRun
|
|
description: >
|
|
The progress of the workflow run the task belongs to: the definition the task froze, and for each stage its
|
|
state and every task that attempted it, with the attempts whose outputs each one started from.
|
|
responses:
|
|
"200":
|
|
description: The run's progress.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/WorkflowRun" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/unmerged:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getUnmerged
|
|
description: What the task's worktree holds that its project's default branch doesn't.
|
|
responses:
|
|
"200":
|
|
description: The unmerged changes.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Unmerged" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/co-authors:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getCoAuthors
|
|
description: >
|
|
The humans other than the caller with a message in the task's transcript (sent its agent a message, or had
|
|
an inbox answer delivered under their name), in order of their first message. A merge by the caller gives each one with a git identity a
|
|
Co-authored-by trailer.
|
|
responses:
|
|
"200":
|
|
description: The co-authors.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Participant" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/merge:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: mergeTask
|
|
description: >
|
|
Sets the task's merge_title to the confirmed title, then starts the same agent turn as merge-in, without
|
|
its invitation to revise the title. When that turn ends normally, byre squashes the task's worktree
|
|
into one commit titled with the task's merge_title on the project's default branch, authored by the caller with
|
|
a Co-authored-by trailer for each of the task's co-authors, pushes it to origin, fast-forwards the project's
|
|
checkout to it, then removes the worktree and branch and marks the task merged. While another task in the
|
|
project is merging, the merge is held instead (merge_queued_at is set) and starts when no merge is in progress
|
|
in the project and the task's session is idle, oldest first. The title is fixed from here until the task
|
|
closes. Refused while a turn is running, or the merge is already held. With target parent, for a subtask
|
|
only, the subtask's branch is merged into its parent task's branch instead: the parent's agent is asked to
|
|
merge it (queued if it is mid-turn), and the subtask closes as merged once its branch is in the parent's
|
|
HEAD at the end of one of the parent's turns (merging_into_parent is set until then). Refused while the
|
|
subtask's turn is running or it is already merging into its parent. Either target is refused while the
|
|
task has active subtasks of its own. With after_review, nothing starts yet: the request is recorded
|
|
(merge_after_review is set) and made, as this caller and with this target, when the review of the
|
|
task's latest snapshot finishes with no findings, that snapshot is still the latest and no turn is
|
|
running; otherwise it is dropped with a transcript note. Refused (409) unless that review is running.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
properties:
|
|
merge_title: { type: string, description: "The squash commit's title: one line, at most 72 characters. Required for target main." }
|
|
target:
|
|
type: string
|
|
enum: [main, parent]
|
|
x-enum-varnames: [MergeTargetMain, MergeTargetParent]
|
|
description: "main (the default): squash onto the project's default branch. parent: merge into the parent task's branch; only for a subtask."
|
|
after_review: { type: boolean, description: "Merge once the running review of the latest snapshot finishes with no findings, instead of now." }
|
|
responses:
|
|
"202":
|
|
description: The merge was started, held, or set to start after the review.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/merge-after-review:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
delete:
|
|
operationId: cancelMergeAfterReview
|
|
description: Withdraws a Merge with after_review that is still waiting for its review; nothing is merged.
|
|
responses:
|
|
"200":
|
|
description: The request was withdrawn.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/merge-in:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: mergeIn
|
|
description: >
|
|
Asks the task's agent to merge the project's default branch into the task branch, resolving any conflicts
|
|
and regenerating generated files. Sent to the task's idle session, or starts a session when it has none.
|
|
Refused while a turn is running.
|
|
responses:
|
|
"202":
|
|
description: The merge turn was started.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/discard:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: discardTask
|
|
description: >
|
|
Gives the task's agent one dedicated turn to write the task summary, started at once when its session is
|
|
idle (or in a new session when it has none) and otherwise as soon as the running turn ends, with no other
|
|
turn admitted meanwhile; drops any held merge; and when that turn ends however it ends, removes the task's
|
|
worktree and branch without merging and marks the task discarded. The task's record, summary and events
|
|
remain. Refused while the task is merging, already being discarded, or has active subtasks; on a task whose
|
|
cleanup failed, retries the cleanup.
|
|
responses:
|
|
"202":
|
|
description: The task, still active, whose discard was started.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/board:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: postToBoard
|
|
description: >
|
|
Posts to a team task's board as the caller: records a board.posted event and sends the post to every agent of
|
|
the team, starting a turn for an idle one and reaching a working one after its next tool call.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/BoardPostCreate" }
|
|
responses:
|
|
"204": { description: The post was recorded and sent. }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/events:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listTaskEvents
|
|
description: The task's events after a seq, oldest first. Page by passing the last seq back as after.
|
|
parameters:
|
|
- { name: after, in: query, required: false, schema: { type: integer, format: int64 } }
|
|
- { name: limit, in: query, required: false, schema: { type: integer, minimum: 1, maximum: 1000 } }
|
|
responses:
|
|
"200":
|
|
description: Up to limit events (default 500).
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Event" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/changes:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskChanges
|
|
description: >
|
|
Everything in the task's worktree (committed, staged, unstaged and untracked, respecting .gitignore) as a tree,
|
|
compared with the merge-base of the task branch and the project's default branch, or with since when given.
|
|
The worktree's own index is not touched. With snapshot, the tree is that snapshot's instead, compared with the
|
|
merge-base of its commit and the default branch, or with the previous snapshot's tree when step is true.
|
|
parameters:
|
|
- { name: since, in: query, required: false, schema: { type: string }, description: "A commit to compare with instead of the merge-base, such as a user.message event's head. Not allowed with snapshot." }
|
|
- { name: snapshot, in: query, required: false, schema: { type: integer }, description: "A snapshot's n: show the task as it was in that snapshot rather than the live worktree." }
|
|
- { name: step, in: query, required: false, schema: { type: boolean }, description: "With snapshot: compare with the previous snapshot (the snapshot commit's parent for the first one)." }
|
|
responses:
|
|
"200":
|
|
description: Per-file stats.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TaskChanges" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/image:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskImage
|
|
description: >
|
|
An image file from the task's worktree, for Markdown images and image attachments. path is absolute or relative
|
|
to the worktree; after resolving symlinks it must be inside the worktree. PNG, JPEG, GIF, WebP and SVG, chosen by extension.
|
|
parameters:
|
|
- { name: path, in: query, required: true, schema: { type: string } }
|
|
responses:
|
|
"200":
|
|
description: The file's bytes.
|
|
content:
|
|
image/png: { schema: { type: string, format: binary } }
|
|
image/jpeg: { schema: { type: string, format: binary } }
|
|
image/gif: { schema: { type: string, format: binary } }
|
|
image/webp: { schema: { type: string, format: binary } }
|
|
image/svg+xml: { schema: { type: string, format: binary } }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"403": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/diff:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskDiff
|
|
description: The unified diff of one file between a base and tree from getTaskChanges.
|
|
parameters:
|
|
- { name: base, in: query, required: true, schema: { type: string } }
|
|
- { name: tree, in: query, required: true, schema: { type: string } }
|
|
- { name: path, in: query, required: true, schema: { type: string } }
|
|
- { name: old_path, in: query, required: false, schema: { type: string } }
|
|
responses:
|
|
"200":
|
|
description: The patch.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/FileDiff" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/dir:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskDir
|
|
description: >
|
|
One directory of the task's worktree, directories first, then by name. Entries named .git are left out;
|
|
gitignored entries are included and marked.
|
|
A path that leaves the worktree, through .. or a symlink, is refused.
|
|
parameters:
|
|
- { name: path, in: query, required: false, schema: { type: string }, description: "Slash-separated, relative to the worktree root; empty or absent for the root." }
|
|
responses:
|
|
"200":
|
|
description: The directory's entries.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/DirListing" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/file:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskFile
|
|
description: >
|
|
A regular file in the task's worktree. Text is returned up to a size limit; binary files return no content.
|
|
A path that leaves the worktree, through .. or a symlink, is refused.
|
|
parameters:
|
|
- { name: path, in: query, required: true, schema: { type: string }, description: "Slash-separated, relative to the worktree root." }
|
|
responses:
|
|
"200":
|
|
description: The file.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/FileContent" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/terminal:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskTerminal
|
|
description: >
|
|
A WebSocket attached to the task's terminal, a login shell in its worktree, started at cols by rows if none is
|
|
running. The server first sends what the terminal has recently printed, then its output as it comes, all as
|
|
binary messages. The client sends input as binary messages and resizes as text messages holding a
|
|
TerminalSize. When the shell exits the server closes with code 4000 and the exit status as the reason.
|
|
parameters:
|
|
- { name: cols, in: query, required: true, schema: { type: integer, minimum: 1 } }
|
|
- { name: rows, in: query, required: true, schema: { type: integer, minimum: 1 } }
|
|
responses:
|
|
"101":
|
|
description: Switched to the WebSocket protocol.
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/previews:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listPreviews
|
|
description: >
|
|
The ports the task's agent exposed with expose_port, by name. Each is served by tailscale serve on the same
|
|
port number of byre's host, over HTTPS, until the task is merged or discarded.
|
|
responses:
|
|
"200":
|
|
description: The previews.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Preview" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/snapshots:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listSnapshots
|
|
description: >
|
|
The task's snapshots, oldest first. Each is a commit of the worktree as if everything were staged, kept at
|
|
refs/byre/tasks/{taskId}/snap/{n} until the task is merged or discarded; the rows remain after that.
|
|
responses:
|
|
"200":
|
|
description: The snapshots.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Snapshot" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/reviews:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listReviews
|
|
description: The task's reviews, one per snapshot, oldest first.
|
|
responses:
|
|
"200":
|
|
description: The reviews.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Review" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/reviews/{reviewId}/findings/{index}:
|
|
parameters:
|
|
- { name: reviewId, in: path, required: true, schema: { type: string } }
|
|
- { name: index, in: path, required: true, schema: { type: integer }, description: "The finding's position in the review's findings, from 0." }
|
|
put:
|
|
operationId: setFindingState
|
|
description: Records that the human addressed a finding of a done review, by sending it to the agent to fix or by ignoring it.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/FindingStateUpdate" }
|
|
responses:
|
|
"200":
|
|
description: The review.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Review" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/reviews/{reviewId}/stop:
|
|
parameters:
|
|
- { name: reviewId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: stopReview
|
|
description: Ends a running review's reviewer and records the review as failed. Refused unless the review is running.
|
|
responses:
|
|
"200":
|
|
description: The review.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Review" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/snapshots/{n}/fork:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
- { name: n, in: path, required: true, schema: { type: integer } }
|
|
post:
|
|
operationId: forkSnapshot
|
|
description: >
|
|
Creates a new task whose branch and worktree start from the snapshot's commit, with an idle agent session that
|
|
continues the snapshot's agent conversation as it stood at the snapshot (the vendor's own session fork). The
|
|
new session's first turn is the first message sent to it. Refused while the task is closed, and for a snapshot
|
|
with no recorded agent message at or before it.
|
|
responses:
|
|
"201":
|
|
description: The new task.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/sessions:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listSessions
|
|
responses:
|
|
"200":
|
|
description: The task's agent sessions, oldest first.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AgentSession" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
post:
|
|
operationId: createSession
|
|
description: Starts an agent session in the task's worktree and sends it the prompt as its first turn.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/SessionCreate" }
|
|
responses:
|
|
"201":
|
|
description: The new session.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/queue/{inputId}:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
- { name: inputId, in: path, required: true, schema: { type: integer, format: int64 } }
|
|
delete:
|
|
operationId: withdrawMessage
|
|
description: >
|
|
Takes back a queued message (the id from its user.queued event) before the agent gets it, and records a
|
|
user.unqueued event. Refused once the message has been handed over.
|
|
responses:
|
|
"204": { description: The message was withdrawn. }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/sessions/{sessionId}:
|
|
parameters:
|
|
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getSession
|
|
responses:
|
|
"200":
|
|
description: The session.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/sessions/{sessionId}/messages:
|
|
parameters:
|
|
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: sendMessage
|
|
description: Starts a new turn with this message when the session is idle. While a task session's turn is running, the message is queued and reaches the agent after its next tool call, or as the next turn.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/MessageCreate" }
|
|
responses:
|
|
"202":
|
|
description: The turn has started.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/sessions/{sessionId}/compact:
|
|
parameters:
|
|
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: compactSession
|
|
description: >
|
|
Asks the idle session's agent for a handoff (goal, decisions, state, dead ends, open questions, files). When that turn ends,
|
|
the session is completed and a new session on the same task starts with the handoff as its first message, on the requested model
|
|
or else the old session's.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/CompactCreate" }
|
|
responses:
|
|
"202":
|
|
description: The handoff turn was started.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/sessions/{sessionId}/interrupt:
|
|
parameters:
|
|
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: interruptSession
|
|
description: Ends the current turn.
|
|
responses:
|
|
"202":
|
|
description: The interrupt was delivered.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/blobs:
|
|
post:
|
|
operationId: uploadBlob
|
|
description: >
|
|
Stores an image for use in a message. The body is the raw image; its type is detected from the bytes
|
|
and must be PNG, JPEG, GIF or WebP. At most 5 MiB.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
image/png: { schema: { type: string, format: binary } }
|
|
image/jpeg: { schema: { type: string, format: binary } }
|
|
image/gif: { schema: { type: string, format: binary } }
|
|
image/webp: { schema: { type: string, format: binary } }
|
|
responses:
|
|
"201":
|
|
description: The stored blob.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Blob" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"413": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/blobs/{blobId}:
|
|
parameters:
|
|
- { name: blobId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getBlob
|
|
responses:
|
|
"200":
|
|
description: The blob's bytes, with its content type.
|
|
content:
|
|
image/png: { schema: { type: string, format: binary } }
|
|
image/jpeg: { schema: { type: string, format: binary } }
|
|
image/gif: { schema: { type: string, format: binary } }
|
|
image/webp: { schema: { type: string, format: binary } }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/inbox:
|
|
get:
|
|
operationId: listInbox
|
|
description: >
|
|
Inbox items, oldest first.
|
|
Filters narrow the one query to a project's or a task's view.
|
|
parameters:
|
|
- { name: project_id, in: query, required: false, schema: { type: string } }
|
|
- { name: task_id, in: query, required: false, schema: { type: string } }
|
|
- { name: state, in: query, required: false, schema: { $ref: "#/components/schemas/InboxState" } }
|
|
responses:
|
|
"200":
|
|
description: Matching items with their responses. Defaults to open items.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/InboxItem" }
|
|
|
|
/api/inbox/{itemId}:
|
|
parameters:
|
|
- { name: itemId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getInboxItem
|
|
responses:
|
|
"200":
|
|
description: The item with its responses.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/InboxItem" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/clients/connect:
|
|
get:
|
|
operationId: connectClient
|
|
description: >
|
|
A WebSocket over which task agents use this Mac: the server sends ClientRequest text messages and the client
|
|
answers each with a ClientReply text message carrying the same id, in any order. The Byre-Host header names
|
|
the client; a newer connection from the same host replaces the older one.
|
|
responses:
|
|
"101":
|
|
description: Switched to the WebSocket protocol.
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/clients/transfers/{transferId}:
|
|
parameters:
|
|
- { name: transferId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getClientTransfer
|
|
description: The file or directory an upload ClientRequest sends, as a gzipped tar holding it under its own name. Served while the request is waiting for its reply.
|
|
responses:
|
|
"200":
|
|
description: The archive.
|
|
content:
|
|
application/gzip: { schema: { type: string, format: binary } }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
put:
|
|
operationId: putClientTransfer
|
|
description: The file or directory a download ClientRequest asks for, as a gzipped tar holding it under its own name. Accepted once, while the request is waiting for its reply.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/gzip: { schema: { type: string, format: binary } }
|
|
responses:
|
|
"204":
|
|
description: Received.
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/inbox/responses:
|
|
post:
|
|
operationId: respondInbox
|
|
description: >
|
|
Answers one or more items in one submission. Answers reach the agent as one message once
|
|
it is idle and none of its questions are unanswered.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/InboxRespond" }
|
|
responses:
|
|
"200":
|
|
description: The updated items.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/InboxItem" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/events:
|
|
get:
|
|
operationId: streamEvents
|
|
description: >
|
|
Server-sent events. Each event's id is its seq; data is the Event as JSON.
|
|
Events after Last-Event-ID (or the after query parameter) are replayed before live events.
|
|
With task_id, only that task's events are sent; with lead=true, only the events of the caller's lead agent.
|
|
Events with an owner go only to that user.
|
|
parameters:
|
|
- { name: Last-Event-ID, in: header, required: false, schema: { type: integer, format: int64 } }
|
|
- { name: after, in: query, required: false, schema: { type: integer, format: int64 } }
|
|
- { name: task_id, in: query, required: false, schema: { type: string } }
|
|
- { name: lead, in: query, required: false, schema: { type: boolean } }
|
|
responses:
|
|
"200":
|
|
description: Event stream.
|
|
content:
|
|
text/event-stream:
|
|
schema: { type: string }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/admin/status:
|
|
get:
|
|
operationId: getStatus
|
|
responses:
|
|
"200":
|
|
description: Server health and usage.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Status" }
|
|
|
|
/api/workflows:
|
|
get:
|
|
operationId: listWorkflows
|
|
responses:
|
|
"200":
|
|
description: Every workflow's name and description, by name.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/WorkflowSummary" }
|
|
|
|
/api/workflows/{name}:
|
|
parameters:
|
|
- { name: name, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getWorkflow
|
|
responses:
|
|
"200":
|
|
description: "The workflow's file: its WorkflowDefinition as YAML, as an attachment named after it."
|
|
content:
|
|
application/yaml:
|
|
schema: { type: string }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
put:
|
|
operationId: putWorkflow
|
|
description: >
|
|
Creates or replaces the workflow from its file, a WorkflowDefinition as YAML (or JSON). The name is one line
|
|
of 1 to 100 characters. Tasks that already froze the workflow keep their copy.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/yaml:
|
|
schema: { type: string }
|
|
responses:
|
|
"200":
|
|
description: The stored workflow.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/WorkflowSummary" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
delete:
|
|
operationId: deleteWorkflow
|
|
responses:
|
|
"204":
|
|
description: Deleted. Tasks that froze it keep their copy.
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
components:
|
|
responses:
|
|
Error:
|
|
description: Error.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Error" }
|
|
|
|
schemas:
|
|
Error:
|
|
type: object
|
|
required: [message]
|
|
properties:
|
|
message: { type: string }
|
|
|
|
User:
|
|
type: object
|
|
required: [login, display_name, git_name, git_email, notification_prefs, default_model]
|
|
properties:
|
|
login: { type: string }
|
|
display_name: { type: string }
|
|
git_name: { type: string }
|
|
git_email: { type: string }
|
|
notification_prefs: { $ref: "#/components/schemas/NotificationPrefs" }
|
|
default_model: { type: string, description: The model the app starts new tasks on. }
|
|
|
|
DefaultModel:
|
|
type: object
|
|
required: [model]
|
|
properties:
|
|
model: { type: string }
|
|
|
|
NotificationPrefs:
|
|
type: object
|
|
description: Which new inbox items and finished turns notify this user in their open byre pages.
|
|
required: [questions, reports, errors, rate_limits]
|
|
properties:
|
|
questions: { type: boolean, description: Questions. On by default. }
|
|
reports: { type: boolean, description: "Task turns that end with a summary (turn.ended with summary: true)." }
|
|
errors: { type: boolean, description: session_error items. }
|
|
rate_limits: { type: boolean, description: rate_limited items. }
|
|
|
|
UserUpdate:
|
|
type: object
|
|
required: [git_name, git_email]
|
|
properties:
|
|
git_name: { type: string }
|
|
git_email: { type: string }
|
|
|
|
Project:
|
|
type: object
|
|
required: [id, name, repo_path, default_branch, remote, created_by, created_at]
|
|
properties:
|
|
id: { type: string }
|
|
name: { type: string }
|
|
repo_path: { type: string }
|
|
default_branch: { type: string }
|
|
remote: { type: string }
|
|
created_by: { type: string }
|
|
created_at: { type: string, format: date-time }
|
|
|
|
ProjectCreate:
|
|
type: object
|
|
required: [name, repo_path]
|
|
properties:
|
|
name: { type: string }
|
|
repo_path: { type: string }
|
|
|
|
Task:
|
|
type: object
|
|
required: [id, project_id, title, merge_title, branch, worktree_path, base_ref, port_base, color, status, created_by, created_at, state, merging, discarding, merging_into_parent, merge_after_review, summary_seq]
|
|
properties:
|
|
id: { type: string }
|
|
project_id: { type: string }
|
|
title: { type: string }
|
|
merge_title: { type: string, description: "The title of the squash commit Merge makes: the task title until the agent sets another with set_merge_title." }
|
|
branch: { type: string }
|
|
worktree_path: { type: string }
|
|
base_ref: { type: string }
|
|
port_base: { type: integer, description: "The first of the task's block of ports (port_base to port_base+9), passed to its agent and terminal as PORT." }
|
|
color: { type: integer, description: "Index into the UI's task palette, assigned at creation: a colour no active task holds, the one given out longest ago." }
|
|
status:
|
|
type: string
|
|
enum: [active, merged, discarded]
|
|
x-enum-varnames: [TaskStatusActive, TaskStatusMerged, TaskStatusDiscarded]
|
|
created_by: { type: string }
|
|
created_at: { type: string, format: date-time }
|
|
closed_at: { type: string, format: date-time, description: When the task was merged or discarded. }
|
|
merge_commit: { type: string, description: "merged: the squash commit on the default branch; empty when there was nothing to merge." }
|
|
todo_item: { type: string, description: "The title of the TODO.md item the task was started from; absent for other tasks." }
|
|
forked_from: { type: string, description: "The task this one was forked from; absent for other tasks." }
|
|
forked_at: { type: integer, description: "With forked_from: the n of the snapshot it was forked at." }
|
|
merge_queued_at: { type: string, format: date-time, description: "When Merge was requested while another task in the project was merging; absent once the merge starts or when none is held." }
|
|
workflow: { type: string, description: "The name of the workflow the task froze at creation (getTaskWorkflow has its copy); absent for a task without one." }
|
|
workflow_run: { type: string, description: "With workflow: the id every task of one run of the workflow shares." }
|
|
workflow_stage: { type: string, description: "With workflow: the name of the stage this task runs." }
|
|
state:
|
|
type: string
|
|
description: "What the task is doing, kept by the store in the same transaction as every change to it (a task.state event carries each change): merged or discarded once closed, else discarding, merging, the state of its agent's latest live session when that isn't idle, reviewing while a review runs, review_pending between a turn's end and its snapshot's review starting or being skipped, idle, or no_agent."
|
|
enum: [running, idle, review_pending, reviewing, merging, discarding, merged, discarded, no_agent]
|
|
x-enum-varnames: [TaskStateRunning, TaskStateIdle, TaskStateReviewPending, TaskStateReviewing, TaskStateMerging, TaskStateDiscarding, TaskStateMerged, TaskStateDiscarded, TaskStateNoAgent]
|
|
merging: { type: boolean, description: "Whether a Merge was started and hasn't finished: its turn is running, or the turn ended and byre is squashing, pushing and closing the task." }
|
|
discarding: { type: boolean, description: "Whether a Discard was started and the task isn't closed yet: its summary turn is waiting for the running turn, running, or done and the task is being removed." }
|
|
parent_task_id: { type: string, description: "The task whose agent created this one as its subtask; absent for other tasks." }
|
|
merging_into_parent: { type: boolean, description: "Whether a merge of this subtask into its parent was requested and the parent hasn't merged it yet." }
|
|
merge_after_review: { type: boolean, description: "Whether a Merge with after_review is waiting for the running review of the latest snapshot to finish." }
|
|
summary_seq: { type: integer, format: int64, description: "The seq of the task's latest turn.ended event with summary: true; 0 when it has none." }
|
|
|
|
Todo:
|
|
type: object
|
|
required: [exists, items]
|
|
properties:
|
|
exists: { type: boolean, description: Whether the default branch has a TODO.md at its root. }
|
|
items:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/TodoItem" }
|
|
|
|
TodoItem:
|
|
type: object
|
|
required: [title, body, section]
|
|
properties:
|
|
title: { type: string, description: "The item's first line, without its list marker: the item's identity." }
|
|
body: { type: string, description: The item's further lines, as Markdown with the item's indentation removed. }
|
|
section: { type: string, description: The text of the nearest heading above the item; empty when there is none. }
|
|
|
|
TodoStart:
|
|
type: object
|
|
required: [title]
|
|
properties:
|
|
title: { type: string, description: The title of the item to start. }
|
|
model: { type: string }
|
|
discuss: { type: boolean, description: "Tell the agent the human wants to discuss the item in chat before anything is built." }
|
|
|
|
Unmerged:
|
|
type: object
|
|
required: [commits, files, insertions, deletions, uncommitted]
|
|
properties:
|
|
commits: { type: integer, description: Commits on the task branch that aren't on the default branch. }
|
|
files: { type: integer, description: Files that differ from the merge base, uncommitted changes included. }
|
|
insertions: { type: integer }
|
|
deletions: { type: integer }
|
|
uncommitted: { type: integer, description: Paths with uncommitted changes in the worktree. }
|
|
|
|
Participant:
|
|
type: object
|
|
required: [login, display_name, git_name, git_email]
|
|
properties:
|
|
login: { type: string }
|
|
display_name: { type: string }
|
|
git_name: { type: string, description: Empty when the user hasn't set a git identity; they then get no trailer. }
|
|
git_email: { type: string }
|
|
|
|
TaskCreate:
|
|
type: object
|
|
required: [title]
|
|
properties:
|
|
title: { type: string }
|
|
prompt:
|
|
type: string
|
|
description: Starts the task's agent with this as its first message, in the same request. Not with workflow.
|
|
model: { type: string, description: The agent's model when prompt is given. }
|
|
workflow:
|
|
type: string
|
|
description: >
|
|
The name of a saved workflow to run instead of creating one task with no agent: each stage with no after
|
|
stages becomes its own task, titled "<title>: <stage>", with the title as the run's brief. The response is
|
|
the first of those tasks.
|
|
|
|
WorkflowSummary:
|
|
type: object
|
|
required: [name, description]
|
|
properties:
|
|
name: { type: string }
|
|
description: { type: string }
|
|
|
|
WorkflowDefinition:
|
|
type: object
|
|
description: >
|
|
A workflow's file, which holds everything but its name: its stages, each run as its own task once the stages
|
|
it comes after have finished. Sent and returned as YAML.
|
|
required: [stages]
|
|
properties:
|
|
description: { type: string, x-go-type-skip-optional-pointer: true }
|
|
stages:
|
|
type: array
|
|
minItems: 1
|
|
items: { $ref: "#/components/schemas/Stage" }
|
|
|
|
Stage:
|
|
type: object
|
|
required: [name, prompt]
|
|
properties:
|
|
name: { type: string, description: "One line of 1 to 100 characters, unique within the workflow." }
|
|
after:
|
|
type: array
|
|
items: { type: string }
|
|
description: >
|
|
The stages whose outputs this stage gets, by name; it starts once all of them have finished. Absent means
|
|
the previous stage in the list (for the first stage, none); empty means it starts from the brief.
|
|
base:
|
|
type: string
|
|
enum: [parent, main]
|
|
x-enum-varnames: [StageBaseParent, StageBaseMain]
|
|
description: >
|
|
Where the stage's task branches from. parent (the default): the commit its one after stage finished at, or
|
|
for a stage with none, where the workflow was started from. main: the project's default branch. Refused on
|
|
a stage with more than one after stage, which always branches from the default branch.
|
|
model: { type: string, x-go-type-skip-optional-pointer: true, description: "The stage agent's model, which also picks its vendor: gpt-* models run on Codex, every other model on Claude Code. Required without agents, refused with them." }
|
|
prompt: { type: string, description: "The stage agent's instructions; with agents, the instructions every agent of the team gets before its own." }
|
|
agents:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/TeamMember" }
|
|
description: >
|
|
Runs the stage as a team: several agents in the stage's one task and worktree, each on its own model, sharing a
|
|
board. The first agent finishes the stage.
|
|
|
|
TeamMember:
|
|
type: object
|
|
required: [name, model, prompt]
|
|
properties:
|
|
name: { type: string, description: "The agent's name in the team, one line of 1 to 100 characters, unique within the team." }
|
|
model: { type: string, description: "The agent's model, which also picks its vendor." }
|
|
prompt: { type: string, description: "This agent's own instructions: its role in the team." }
|
|
|
|
TaskWorkflow:
|
|
type: object
|
|
description: The workflow a task froze when it was created, as it was then.
|
|
required: [name, definition]
|
|
properties:
|
|
name: { type: string }
|
|
definition: { type: string, description: The WorkflowDefinition as YAML. }
|
|
|
|
WorkflowRun:
|
|
type: object
|
|
required: [name, run, title, brief, definition, finished, stages]
|
|
properties:
|
|
name: { type: string }
|
|
run: { type: string }
|
|
title: { type: string }
|
|
brief: { type: string }
|
|
definition: { $ref: "#/components/schemas/WorkflowDefinition" }
|
|
finished: { type: boolean, description: "Whether the final stage finished, which ends the run." }
|
|
stages:
|
|
type: array
|
|
description: In the definition's order.
|
|
items: { $ref: "#/components/schemas/WorkflowRunStage" }
|
|
|
|
WorkflowRunStage:
|
|
type: object
|
|
required: [name, after, state, waiting_on, attempts]
|
|
properties:
|
|
name: { type: string }
|
|
after:
|
|
type: array
|
|
description: The stages it comes after, with the definition's defaults applied.
|
|
items: { type: string }
|
|
state:
|
|
type: string
|
|
enum: [waiting, running, idle, finished, merged, discarded, cleaned_up]
|
|
x-enum-varnames: [StageStateWaiting, StageStateRunning, StageStateIdle, StageStateFinished, StageStateMerged, StageStateDiscarded, StageStateCleanedUp]
|
|
description: >
|
|
waiting: no task yet. Otherwise the state of its latest finished attempt, or of its latest attempt when
|
|
none has finished.
|
|
waiting_on:
|
|
type: array
|
|
description: The after stages with no finished attempt yet.
|
|
items: { type: string }
|
|
attempts:
|
|
type: array
|
|
description: The tasks that ran the stage (the first, and forks of it), oldest first.
|
|
items: { $ref: "#/components/schemas/StageAttempt" }
|
|
|
|
StageAttempt:
|
|
type: object
|
|
required: [task_id, title, state, discarding, inputs]
|
|
properties:
|
|
task_id: { type: string }
|
|
title: { type: string }
|
|
state:
|
|
type: string
|
|
enum: [running, idle, finished, merged, discarded, cleaned_up]
|
|
x-enum-varnames: [AttemptStateRunning, AttemptStateIdle, AttemptStateFinished, AttemptStateMerged, AttemptStateDiscarded, AttemptStateCleanedUp]
|
|
description: >
|
|
running: its agent is mid-turn. idle: active, and finish_stage hasn't taken. finished: active, its output
|
|
recorded. merged. discarded: discarded before finishing. cleaned_up: discarded after finishing, as byre
|
|
does to the run's other tasks when the final stage finishes.
|
|
discarding: { type: boolean, description: "Whether a Discard was started and the task isn't closed yet." }
|
|
forked_from: { type: string, description: "The task this attempt was forked from; absent for the stage's first attempt." }
|
|
output: { type: string, description: "The finish_stage output the stages after it get; absent until it finishes." }
|
|
commit: { type: string, description: "With output: the commit the stage finished at." }
|
|
discarded_by: { type: string, description: "discarded and cleaned_up: who discarded it; byre for the cleanup." }
|
|
inputs:
|
|
type: array
|
|
description: "The attempts whose outputs it started from, one per after stage; a fork has its source's."
|
|
items: { $ref: "#/components/schemas/StageInput" }
|
|
|
|
StageInput:
|
|
type: object
|
|
required: [stage, task_id]
|
|
properties:
|
|
stage: { type: string }
|
|
task_id: { type: string }
|
|
|
|
TaskChanges:
|
|
type: object
|
|
required: [base, tree, files]
|
|
properties:
|
|
base: { type: string, description: "The commit or tree compared with: the merge-base of the task branch and the default branch, since, or the previous snapshot's tree." }
|
|
tree: { type: string, description: "Tree of the worktree as if everything were staged, or the snapshot's tree." }
|
|
files:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/FileChange" }
|
|
|
|
FileChange:
|
|
type: object
|
|
required: [path, status, additions, deletions, binary]
|
|
properties:
|
|
path: { type: string }
|
|
old_path: { type: string, description: "renamed: the path before the rename." }
|
|
status: { type: string, enum: [added, modified, deleted, renamed, type_changed] }
|
|
additions: { type: integer }
|
|
deletions: { type: integer }
|
|
binary: { type: boolean }
|
|
|
|
FileDiff:
|
|
type: object
|
|
required: [path, patch]
|
|
properties:
|
|
path: { type: string }
|
|
patch: { type: string }
|
|
|
|
DirListing:
|
|
type: object
|
|
required: [path, entries, truncated]
|
|
properties:
|
|
path: { type: string, description: "The directory, relative to the worktree root; empty for the root." }
|
|
entries:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/DirEntry" }
|
|
truncated: { type: boolean, description: The directory has more entries than were returned. }
|
|
|
|
DirEntry:
|
|
type: object
|
|
required: [name, type, symlink, size, ignored]
|
|
properties:
|
|
name: { type: string }
|
|
ignored: { type: boolean, description: "git ignores the entry: .gitignore and the other exclude files match it or a directory above it." }
|
|
type:
|
|
type: string
|
|
enum: [dir, file, other]
|
|
x-enum-varnames: [DirEntryTypeDir, DirEntryTypeFile, DirEntryTypeOther]
|
|
description: "What the entry is, following a symlink that stays in the worktree. other: a symlink that leaves the worktree or points nowhere, or a device, socket or pipe."
|
|
symlink: { type: boolean }
|
|
size: { type: integer, format: int64, description: "file: its size in bytes." }
|
|
|
|
FileContent:
|
|
type: object
|
|
required: [path, size, binary, truncated, text]
|
|
properties:
|
|
path: { type: string }
|
|
size: { type: integer, format: int64 }
|
|
binary: { type: boolean, description: The file isn't UTF-8 text; text is empty. }
|
|
truncated: { type: boolean, description: "text holds only the start of the file." }
|
|
text: { type: string }
|
|
|
|
Snapshot:
|
|
type: object
|
|
required: [id, task_id, agent_session_id, n, commit_sha, tree_sha, event_seq, trigger, created_at]
|
|
properties:
|
|
id: { type: string }
|
|
task_id: { type: string }
|
|
agent_session_id: { type: string }
|
|
n: { type: integer, description: "Position in the task's snapshots, from 1; the ref is refs/byre/tasks/{task_id}/snap/{n}." }
|
|
commit_sha: { type: string, description: A commit of tree_sha whose parent is the worktree's HEAD when it was taken. }
|
|
tree_sha: { type: string }
|
|
event_seq: { type: integer, format: int64, description: "The task's latest event when the snapshot was started: the tree holds at least the work up to it." }
|
|
trigger:
|
|
type: string
|
|
enum: [message, turn_end, tool_call, ask_human, timer, requested]
|
|
x-enum-varnames: [SnapshotTriggerMessage, SnapshotTriggerTurnEnd, SnapshotTriggerToolCall, SnapshotTriggerAskHuman, SnapshotTriggerTimer, SnapshotTriggerRequested]
|
|
description: "turn_end: after byre's end-of-turn commit. requested: a task's agent or the lead asked for it with take_snapshot. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds."
|
|
created_at: { type: string, format: date-time }
|
|
|
|
Preview:
|
|
type: object
|
|
required: [task_id, name, port, created_at]
|
|
properties:
|
|
task_id: { type: string }
|
|
name: { type: string }
|
|
port: { type: integer, description: "A port in the task's block, served at https://<byre's host>:<port>/." }
|
|
created_at: { type: string, format: date-time }
|
|
|
|
Review:
|
|
type: object
|
|
description: An agent session on the vendor the task's agent doesn't use, reviewing one snapshot's change.
|
|
required: [id, task_id, snapshot_n, agent_session_id, vendor, model, state, error, created_at, finding_states]
|
|
properties:
|
|
id: { type: string }
|
|
task_id: { type: string }
|
|
snapshot_n: { type: integer }
|
|
agent_session_id: { type: string, description: "The reviewer's session; empty when skipped." }
|
|
vendor: { type: string, description: "Empty when skipped." }
|
|
model: { type: string, description: "Empty when skipped." }
|
|
state:
|
|
type: string
|
|
enum: [running, done, failed, skipped]
|
|
x-enum-varnames: [ReviewStateRunning, ReviewStateDone, ReviewStateFailed, ReviewStateSkipped]
|
|
description: "skipped: the snapshot's step changed no files, so no reviewer ran."
|
|
result: { type: object, description: "done: the reviewer's submit_review arguments: summary (Markdown) and findings, each with severity, category, title, detail, path and line." }
|
|
error: { type: string, description: "failed: why." }
|
|
created_at: { type: string, format: date-time }
|
|
finished_at: { type: string, format: date-time }
|
|
finding_states:
|
|
type: object
|
|
description: "How the human addressed each finding, keyed by its index in result.findings; a finding not listed is open."
|
|
additionalProperties: { $ref: "#/components/schemas/FindingState" }
|
|
|
|
FindingState:
|
|
type: string
|
|
enum: [fixed, ignored]
|
|
x-enum-varnames: [FindingFixed, FindingIgnored]
|
|
description: "fixed: sent to the task's agent to fix. ignored: dismissed, and left out of the Merge warning."
|
|
|
|
FindingStateUpdate:
|
|
type: object
|
|
required: [state]
|
|
properties:
|
|
state: { $ref: "#/components/schemas/FindingState" }
|
|
|
|
AgentSession:
|
|
type: object
|
|
required: [id, task_id, owner, vendor, model, vendor_session_id, state, role, member, created_by, created_at, subagents]
|
|
properties:
|
|
id: { type: string }
|
|
task_id: { type: string, description: Empty for a lead session. }
|
|
member: { type: string, description: "The agent's name in its task's team; empty on a task with one agent, and for leads and reviewers." }
|
|
owner: { type: string, description: "The login whose lead agent this is; empty for a task's session." }
|
|
vendor: { type: string, enum: [claude, codex], description: "Follows from the model the session was created with: gpt-* models run on Codex, every other model on Claude Code." }
|
|
model: { type: string, description: "Requested model; empty means the vendor's default. A session only switches between its own vendor's models." }
|
|
vendor_session_id: { type: string, description: "Claude Code's session id, chosen by byre; or the Codex thread id, empty until the session's first turn starts its thread." }
|
|
state:
|
|
type: string
|
|
enum: [idle, running, completed]
|
|
x-enum-varnames: [AgentSessionStateIdle, AgentSessionStateRunning, AgentSessionStateCompleted]
|
|
role: { type: string, enum: [implementer, lead, reviewer], description: "reviewer: a review's session (see Review); a task's sessions list leaves these out." }
|
|
created_by: { type: string }
|
|
created_at: { type: string, format: date-time }
|
|
forked_from: { type: string, description: "A fork's first start resumes this vendor session, cut at forked_at, under a new vendor_session_id; absent for other sessions." }
|
|
forked_at: { type: string, description: "With forked_from: the vendor's id of the last thing the fork keeps, a message for Claude Code, a turn for Codex." }
|
|
subagents: { type: integer, description: "How many of the agent's subagents are running, background ones included after the turn that started them has ended." }
|
|
SessionCreate:
|
|
type: object
|
|
required: [prompt]
|
|
properties:
|
|
prompt: { type: string }
|
|
model: { type: string }
|
|
images:
|
|
type: array
|
|
items: { type: string }
|
|
description: Blob ids from uploadBlob, sent to the agent as images alongside the prompt.
|
|
|
|
MessageCreate:
|
|
type: object
|
|
required: [text]
|
|
properties:
|
|
text: { type: string, description: May be empty when images are given. }
|
|
images:
|
|
type: array
|
|
items: { type: string }
|
|
description: Blob ids from uploadBlob, sent to the agent as images alongside the text.
|
|
model:
|
|
type: string
|
|
description: Model for this turn and later ones. When it differs from the session's model, the session switches before the message is sent.
|
|
|
|
BoardPostCreate:
|
|
type: object
|
|
required: [text]
|
|
properties:
|
|
text: { type: string }
|
|
|
|
CompactCreate:
|
|
type: object
|
|
properties:
|
|
model:
|
|
type: string
|
|
description: Model for the new session, on either vendor. The old session still writes the handoff. Defaults to the old session's model.
|
|
|
|
Blob:
|
|
type: object
|
|
required: [id, content_type, created_by, created_at]
|
|
properties:
|
|
id: { type: string }
|
|
content_type: { type: string }
|
|
created_by: { type: string }
|
|
created_at: { type: string, format: date-time }
|
|
|
|
Attachment:
|
|
type: object
|
|
required: [kind]
|
|
properties:
|
|
kind: { type: string, enum: [file, diff, image, diagram, task, snapshot, url] }
|
|
path: { type: string, description: "file: repo-relative path. image: an image file in the task's worktree, absolute or relative to it." }
|
|
start_line: { type: integer }
|
|
end_line: { type: integer }
|
|
ref: { type: string, description: "diff: git revision range." }
|
|
url: { type: string }
|
|
mermaid: { type: string, description: "diagram: Mermaid source." }
|
|
image: { type: string, description: "image: data URL." }
|
|
task_id: { type: string }
|
|
snapshot_id: { type: string }
|
|
caption: { type: string }
|
|
|
|
InboxState:
|
|
type: string
|
|
enum: [open, answered, dismissed, superseded]
|
|
|
|
InboxItem:
|
|
type: object
|
|
required: [id, project_id, task_id, agent_session_id, thread_id, kind, payload, state, created_at, responses]
|
|
properties:
|
|
id: { type: string }
|
|
project_id: { type: string }
|
|
task_id: { type: string }
|
|
agent_session_id: { type: string }
|
|
thread_id: { type: string }
|
|
kind: { type: string, enum: [question, session_error, rate_limited] }
|
|
payload:
|
|
type: object
|
|
description: >
|
|
question: context (Markdown with the choices inline as `- ( ) text` / `- (*) text` pick-one or `- [ ] text` / `- [x] text` pick-any list items),
|
|
question, why_blocked, options (each choice's text, in order), multiple (true for pick-any), recommended (the marked choices' text), attachments.
|
|
session_error: error.
|
|
rate_limited: vendor, rate_limit (the vendor's rate-limit status), error.
|
|
state: { $ref: "#/components/schemas/InboxState" }
|
|
created_at: { type: string, format: date-time }
|
|
resolved_by: { type: string }
|
|
resolved_at: { type: string, format: date-time }
|
|
responses:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/InboxResponse" }
|
|
|
|
InboxResponseType:
|
|
type: string
|
|
enum: [option, other, dismiss]
|
|
|
|
InboxResponse:
|
|
type: object
|
|
required: [id, item_id, user, type, images, attachments, created_at]
|
|
properties:
|
|
id: { type: string }
|
|
item_id: { type: string }
|
|
user: { type: string }
|
|
type: { $ref: "#/components/schemas/InboxResponseType" }
|
|
options:
|
|
type: array
|
|
items: { type: string }
|
|
text: { type: string }
|
|
images:
|
|
type: array
|
|
items: { type: string }
|
|
description: Blob ids sent to the agent as images alongside the response.
|
|
attachments:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Attachment" }
|
|
created_at: { type: string, format: date-time }
|
|
delivered_at: { type: string, format: date-time }
|
|
|
|
InboxResponseCreate:
|
|
type: object
|
|
required: [item_id, type]
|
|
properties:
|
|
item_id: { type: string }
|
|
type: { $ref: "#/components/schemas/InboxResponseType" }
|
|
options:
|
|
type: array
|
|
items: { type: string }
|
|
description: "option: the chosen options; exactly one for a pick-one question, one or more for a pick-any question."
|
|
text: { type: string, description: "other: the text sent to the agent, which may be empty when images are given. option on a pick-any question: optional text sent along with the checked options." }
|
|
images:
|
|
type: array
|
|
items: { type: string }
|
|
description: "other, or option on a pick-any question: blob ids from uploadBlob, sent to the agent as images alongside the response."
|
|
attachments:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Attachment" }
|
|
|
|
InboxRespond:
|
|
type: object
|
|
required: [responses]
|
|
properties:
|
|
responses:
|
|
type: array
|
|
minItems: 1
|
|
items: { $ref: "#/components/schemas/InboxResponseCreate" }
|
|
|
|
Event:
|
|
type: object
|
|
required: [seq, kind, actor, payload, created_at]
|
|
properties:
|
|
seq: { type: integer, format: int64 }
|
|
kind: { type: string }
|
|
project_id: { type: string }
|
|
task_id: { type: string }
|
|
agent_session_id: { type: string }
|
|
owner: { type: string, description: "Set on a lead agent's events and a user's focus.updated: the login they belong to. Only that user is sent them." }
|
|
actor: { type: string }
|
|
payload: { type: object }
|
|
created_at: { type: string, format: date-time }
|
|
|
|
EventPage:
|
|
type: object
|
|
required: [events, more]
|
|
properties:
|
|
events:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Event" }
|
|
more: { type: boolean, description: "Whether there are earlier events than this page." }
|
|
|
|
Focus:
|
|
type: object
|
|
required: [tabs, tab]
|
|
properties:
|
|
project_id: { type: string, description: The project the right pane shows; the task's project when task_id is set, absent for none. }
|
|
task_id: { type: string, description: The task the right pane shows; absent for none. }
|
|
tabs:
|
|
type: array
|
|
description: The tabs the lead put first, in order. The other task tabs follow them.
|
|
items: { $ref: "#/components/schemas/TaskTab" }
|
|
tab: { $ref: "#/components/schemas/TaskTab" }
|
|
|
|
LeadNote:
|
|
type: object
|
|
required: [id, text, created_at, updated_at]
|
|
properties:
|
|
id: { type: string }
|
|
text: { type: string }
|
|
project_id: { type: string, description: "The project the note applies to; absent for a note that applies to every project." }
|
|
created_at: { type: string, format: date-time }
|
|
updated_at: { type: string, format: date-time }
|
|
|
|
SummaryRead:
|
|
type: object
|
|
required: [seq]
|
|
properties:
|
|
seq: { type: integer, format: int64, description: "The seq of the turn.ended event whose summary was shown." }
|
|
|
|
PaneFocus:
|
|
type: object
|
|
required: [focused, drafting]
|
|
properties:
|
|
focused: { type: boolean, description: True while the app's window has focus and the focused element is inside the right pane. }
|
|
drafting: { type: boolean, description: True while a text box in the right pane holds unsent text. }
|
|
|
|
TaskTab:
|
|
type: string
|
|
enum: [transcript, board, changes, files, terminal, inbox, reviews, workflow, project]
|
|
x-enum-varnames: [TabTranscript, TabBoard, TabChanges, TabFiles, TabTerminal, TabInbox, TabReviews, TabWorkflow, TabProject]
|
|
|
|
TerminalSize:
|
|
type: object
|
|
required: [cols, rows]
|
|
properties:
|
|
cols: { type: integer, minimum: 1 }
|
|
rows: { type: integer, minimum: 1 }
|
|
|
|
Status:
|
|
type: object
|
|
required: [started_at, db_bytes, last_event_seq, projects, active_tasks, sse_clients, clients, live_agents, running_turns, rate_limits, agent_processes, zombies, stuck_after_seconds, protocol_errors]
|
|
properties:
|
|
live_agents: { type: integer, description: Agent processes currently running. }
|
|
agent_processes:
|
|
type: array
|
|
description: Every agent process byre is tracking, idle sessions included.
|
|
items: { $ref: "#/components/schemas/AgentProcess" }
|
|
zombies:
|
|
type: array
|
|
description: Sessions marked running with no live process, and agent processes byre has no session for.
|
|
items: { $ref: "#/components/schemas/Zombie" }
|
|
stuck_after_seconds: { type: integer, description: How long a running turn may go without a stream event before it counts as stuck. }
|
|
protocol_errors: { $ref: "#/components/schemas/ProtocolErrors" }
|
|
running_turns:
|
|
type: array
|
|
description: Turns running now, oldest session first.
|
|
items: { $ref: "#/components/schemas/TurnRef" }
|
|
rate_limits:
|
|
type: object
|
|
description: The latest rate-limit status each vendor reported, keyed by vendor.
|
|
additionalProperties: { type: object }
|
|
started_at: { type: string, format: date-time }
|
|
db_bytes: { type: integer, format: int64 }
|
|
last_event_seq: { type: integer, format: int64 }
|
|
projects: { type: integer }
|
|
active_tasks: { type: integer }
|
|
sse_clients: { type: integer }
|
|
clients:
|
|
type: array
|
|
description: Each running app that holds its /api/clients/connect WebSocket, oldest connection first.
|
|
items: { $ref: "#/components/schemas/ConnectedClient" }
|
|
|
|
ConnectedClient:
|
|
type: object
|
|
required: [id, login, host, commit, connected_at]
|
|
properties:
|
|
id: { type: string, description: The ID the app made up when it started, from its Byre-Client header. }
|
|
login: { type: string }
|
|
host: { type: string, description: The Mac's name from its Byre-Host header. }
|
|
commit: { type: string, description: The git commit the app was built from, from its Byre-Commit header; empty when the client sent none. }
|
|
connected_at: { type: string, format: date-time, description: When the client's WebSocket connected. }
|
|
last_action_at: { type: string, format: date-time, description: When byre last received a request the human made from this client since byre started; absent when none. }
|
|
|
|
ClientRequest:
|
|
type: object
|
|
required: [id, op]
|
|
description: Work a task agent asks a connected Mac to do, sent over /api/clients/connect.
|
|
properties:
|
|
id: { type: string }
|
|
op: { type: string, enum: [bash, upload, download, read_file, write_file, hands] }
|
|
command: { type: string, description: "bash: run with zsh as a login shell in the home directory, in its own process group." }
|
|
timeout_ms: { type: integer, description: "bash: kill the process group after this long." }
|
|
transfer: { type: string, description: "upload: the transfer id to get from /api/clients/transfers/{transferId}. download: the transfer id to put the archive to." }
|
|
dest: { type: string, description: "upload: where the archive's one entry ends up, absolute or starting with ~/; whatever is there is replaced." }
|
|
path: { type: string, description: "download, read_file, write_file: the file (or, for download, file or directory) on the client, absolute or starting with ~/." }
|
|
data: { type: string, format: byte, description: "write_file: the file's new contents; parent directories are created." }
|
|
tool: { type: string, description: "hands: the byre-hands tool to call." }
|
|
arguments:
|
|
type: object
|
|
additionalProperties: true
|
|
description: "hands: the tool's arguments."
|
|
|
|
ClientReply:
|
|
type: object
|
|
required: [id]
|
|
properties:
|
|
id: { type: string, description: The request's id. }
|
|
error: { type: string, description: Set when the request couldn't be carried out. }
|
|
exit_code: { type: integer, description: "bash: the exit status, -1 when it was killed by its timeout." }
|
|
output: { type: string, description: "bash: stdout and stderr together, at most their last 64 KiB." }
|
|
data: { type: string, format: byte, description: "read_file: the file's contents." }
|
|
result:
|
|
type: object
|
|
additionalProperties: true
|
|
description: "hands: the tool's MCP CallToolResult."
|
|
|
|
TurnRef:
|
|
type: object
|
|
required: [session_id, task_id, vendor]
|
|
properties:
|
|
session_id: { type: string }
|
|
task_id: { type: string }
|
|
vendor: { type: string }
|
|
|
|
AgentProcess:
|
|
type: object
|
|
required: [session_id, task_id, vendor, pid, state, last_event_at, health]
|
|
properties:
|
|
session_id: { type: string }
|
|
task_id: { type: string }
|
|
vendor: { type: string }
|
|
pid: { type: integer }
|
|
state: { type: string, description: The session's state, as on AgentSession. }
|
|
last_event_at: { type: string, format: date-time, description: When the process last wrote a line to its stream, or when it started. }
|
|
health:
|
|
type: string
|
|
enum: [ok, stuck, exited]
|
|
x-enum-varnames: [HealthOk, HealthStuck, HealthExited]
|
|
description: stuck means a turn is running and no stream event has arrived for stuck_after_seconds; exited means the process is gone.
|
|
|
|
Zombie:
|
|
type: object
|
|
required: [kind, detail]
|
|
properties:
|
|
kind:
|
|
type: string
|
|
enum: [running_without_process, process_without_session]
|
|
detail: { type: string }
|
|
session_id: { type: string }
|
|
task_id: { type: string }
|
|
pid: { type: integer }
|
|
|
|
ProtocolErrors:
|
|
type: object
|
|
required: [counts, recent]
|
|
properties:
|
|
counts:
|
|
type: object
|
|
description: Stream lines the adapter couldn't parse or didn't recognise since byre started, keyed by vendor.
|
|
additionalProperties: { type: integer }
|
|
recent:
|
|
type: array
|
|
description: The most recent ones, newest first.
|
|
items: { $ref: "#/components/schemas/ProtocolError" }
|
|
|
|
ProtocolError:
|
|
type: object
|
|
required: [vendor, session_id, at, reason, raw, size]
|
|
properties:
|
|
vendor: { type: string }
|
|
session_id: { type: string }
|
|
at: { type: string, format: date-time }
|
|
reason: { type: string }
|
|
raw: { type: string, description: The line as received, cut to its first 4 KiB. }
|
|
size: { type: integer, description: The line's full length in bytes. }
|