Audit of 4626015
This commit is contained in:
@@ -12,7 +12,7 @@ A server and macOS app for running many coding agents (Claude Code, Codex and An
|
||||
- **Merge.** One click: the agent merges main in and resolves conflicts, then byre squashes, pushes and closes the task, with co-author trailers and a git note recording the task. Merge after review, and one merge per project at a time with a queue.
|
||||
- **Subtasks and teams.** Agents can spawn subtasks on their own branches and merge them back, or several agents can share one worktree and talk through a board.
|
||||
- **Workflows.** Named graphs of stages, each run as its own task, with fan-out and fan-in.
|
||||
- **TODO.md.** A project's `TODO.md` items show on its dashboard; start or discuss one in a click.
|
||||
- **TODO.md.** A project's `TODO.md` items show in the Project tab; start or discuss one in a click.
|
||||
- **Changes, Files and Terminal.** Per-task diff view with line comments sent to the agent, a read-only file browser, and a shell in the worktree.
|
||||
- **Previews.** Agents expose dev servers, and the app opens each at a local `*.localhost` address forwarded over the tailnet.
|
||||
- **Screen and app control.** Agents can see and drive the Mac byre runs on (screen capture, accessibility, Orion, Chrome DevTools) and the Macs you have the app open on (shell, files, the same screen tools).
|
||||
|
||||
+1
-3
@@ -1,6 +1,6 @@
|
||||
# Operations
|
||||
|
||||
What reading byre's code won't tell you: external setup, vendor and platform quirks seen live, and the intent behind rules. `api/openapi.yaml` is the API's source of truth; `go generate ./internal/api` regenerates `internal/api/api.gen.go`. The server serves only the API; it has no web pages. `mac/` is the client (`docs/macos.md`).
|
||||
What reading byre's code won't tell you: external setup, vendor and platform quirks seen live, and the intent behind rules. `api/openapi.yaml` is the API's source of truth; `go generate ./internal/api` regenerates `internal/api/api.gen.go`.
|
||||
|
||||
## Data
|
||||
|
||||
@@ -109,8 +109,6 @@ Task agents use the Macs the human has byre's app open on.
|
||||
|
||||
## Screen and app control
|
||||
|
||||
`byre-hands` (`hands/`) is the MCP server that lets agents see and drive a Mac. Its tool descriptions in `hands/Sources/byre-hands/Tools.swift` are what agents read.
|
||||
|
||||
- **One path per process.** replayd, the daemon behind ScreenCaptureKit, keys its clients by executable path: two processes run from one path keep canceling each other's connection, and every capture from that path hangs. replayd's log shows it as `accepted client connection PID: <a>` and `invalidated because the current process cancelled the connection` alternating between two pids, thousands of times a second. So each server session runs its own copy of `byre-hands` from its own file, and the app runs one shared by all its connections.
|
||||
- **Window server.** `NSApplication.shared` connects the process to the window server at startup, without which ScreenCaptureKit asserts. AppleScript needs the main thread with a run loop, so every script runs there.
|
||||
- **Busy apps.** An app in a menu-tracking loop or otherwise busy answers neither Apple events nor accessibility requests; scripts time out after 10s and accessibility requests after 3s, and the first timeout fails the whole call rather than waiting on every element.
|
||||
|
||||
@@ -689,7 +689,7 @@ private struct LineCommentBox: View {
|
||||
}
|
||||
.overlay(RoundedRectangle(cornerRadius: 6).stroke(focused ? Palette.accent : Palette.border))
|
||||
.imageInput(key)
|
||||
Button("remove") {
|
||||
Button("Remove") {
|
||||
_ = store.images.take(key)
|
||||
drafts.dropLineComment(taskId, anchor)
|
||||
}
|
||||
|
||||
@@ -1414,7 +1414,7 @@ private struct FindingResponseView: View {
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Spacer(minLength: 0)
|
||||
if let review = row.review, findings(review).indices.contains(index) {
|
||||
Button("show") {
|
||||
Button("Show") {
|
||||
model.showFinding(review.id, index)
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
@@ -1741,14 +1741,14 @@ private struct SnapshotRow: View {
|
||||
Rectangle().fill(Palette.border).frame(height: 1)
|
||||
Text("snapshot #\(snap.n)")
|
||||
if !inherited {
|
||||
Button("changes") {
|
||||
Button("Changes") {
|
||||
store.pinSnapshot(snap.n)
|
||||
store.focusTab(.changes)
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
.help("Show snapshot \(snap.n) in the Changes tab")
|
||||
}
|
||||
Button("fork") {
|
||||
Button("Fork") {
|
||||
guard let taskId else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ private struct NoteRow: View {
|
||||
.textSelection(.enabled)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Button("delete") {
|
||||
Button("Delete") {
|
||||
Task {
|
||||
if !(await overlays.showConfirm(["Delete this note? Your lead stops applying it.", note.text], action: "Delete", danger: true, anchor: frame)) {
|
||||
return
|
||||
|
||||
@@ -246,13 +246,13 @@ struct FindingActions: View {
|
||||
.foregroundStyle(Palette.muted)
|
||||
} else if response != .fixing {
|
||||
HStack(spacing: 6) {
|
||||
Button("fix") {
|
||||
Button("Fix") {
|
||||
fix()
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
.help(response == .ignoring ? "Overrule the agent: send this finding to it to fix" : "Send this finding to the task's agent to fix")
|
||||
if response == nil {
|
||||
Button("ignore") {
|
||||
Button("Ignore") {
|
||||
ignore()
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
|
||||
@@ -147,14 +147,14 @@ struct WorkflowEditor: View {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
HStack(spacing: 10) {
|
||||
Button("‹ workflows") {
|
||||
Button("‹ Workflows") {
|
||||
Task {
|
||||
await leave()
|
||||
}
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
Spacer()
|
||||
Button("save") {
|
||||
Button("Save") {
|
||||
Task {
|
||||
await save()
|
||||
}
|
||||
@@ -188,7 +188,7 @@ struct WorkflowEditor: View {
|
||||
}
|
||||
}
|
||||
.padding(.top, 12)
|
||||
Button("add stage") {
|
||||
Button("Add stage") {
|
||||
root.insert(newStage(root, store.defaultModel), at: root.children.count)
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
|
||||
@@ -28,7 +28,7 @@ struct WorkflowsView: View {
|
||||
.foregroundStyle(Palette.muted)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
Button("new") {
|
||||
Button("New") {
|
||||
editing = .new
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
@@ -125,17 +125,17 @@ private struct WorkflowRow: View {
|
||||
.textSelection(.enabled)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Button("edit") {
|
||||
Button("Edit") {
|
||||
edit()
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
.help("See and change this workflow's steps and prompts")
|
||||
Button("run") {
|
||||
Button("Run") {
|
||||
run()
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
.help("Open the Lead tab with a request to run this workflow in its composer")
|
||||
Button("delete") {
|
||||
Button("Delete") {
|
||||
Task {
|
||||
await delete()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user