Let the lead walk the user through permission and tool setup

This commit is contained in:
Ian Gulliver
2026-10-22 18:14:27 -07:00
parent da7f324bab
commit 3393d4f99d
5 changed files with 78 additions and 3 deletions
+7 -2
View File
@@ -23,7 +23,7 @@ const (
clientByre = "/Applications/Byre.app/Contents/Helpers/byre" clientByre = "/Applications/Byre.app/Contents/Helpers/byre"
) )
func (m *Manager) clientTools(l *live) []mcp.Tool { func (m *Manager) clientShellTools() []mcp.Tool {
return []mcp.Tool{ return []mcp.Tool{
{ {
Name: "list_clients", Name: "list_clients",
@@ -55,6 +55,11 @@ func (m *Manager) clientTools(l *live) []mcp.Tool {
return m.clientBash(ctx, raw) return m.clientBash(ctx, raw)
}, },
}, },
}
}
func (m *Manager) clientTools(l *live) []mcp.Tool {
return append(m.clientShellTools(), []mcp.Tool{
{ {
Name: "client_upload", Name: "client_upload",
Description: "Copy a file or directory from the Mac byre runs on to a client Mac, replacing whatever is at dest there. " + Description: "Copy a file or directory from the Mac byre runs on to a client Mac, replacing whatever is at dest there. " +
@@ -272,7 +277,7 @@ func (m *Manager) clientTools(l *live) []mcp.Tool {
return m.clientHands(ctx, raw) return m.clientHands(ctx, raw)
}, },
}, },
} }...)
} }
func (m *Manager) listClients() string { func (m *Manager) listClients() string {
+46
View File
@@ -0,0 +1,46 @@
How to walk the human through setting up byre: the tools the server's agents need, vendor sign-ins, and the macOS permissions on the server's Mac and each client Mac.
# Walking the human through setup
Go one step at a time: check, say in a line or two what is missing and what it is for, fix what you can yourself, and ask the human only for what needs their hands (a password, a sign-in, a click on a macOS prompt). Check again after each fix, and finish with a short list of what is ready and what was left out on purpose. Ask which vendors the human wants (Claude, GPT, Gemini) before installing agent CLIs; one is enough.
`byre` is `/Applications/Byre.app/Contents/Helpers/byre` and `byre-hands` is beside it, on every Mac with the app.
## Tools on the server's Mac
Agents run on the Mac byre runs on, the one your own Bash runs on. Check its tools with:
```
"$SHELL" -l -c '/Applications/Byre.app/Contents/Helpers/byre check'
```
It prints one JSON line: `ready` (false while something blocking is missing) and `checks`, each with `name`, `need` (`required`; `agent`, where one of claude, codex and agy is enough; or `optional`), `for` (what it is used for), `ok`, `command` (what installs it), `fix` (what to do after) and `blocking`.
- Run each missing tool's `command` yourself through the login shell, `"$SHELL" -l -c '<command>'`. `brew` must be there first; installing Homebrew asks for the human's password, so ask them to run its installer in a terminal on that Mac (the app's Server tab there lists each missing tool with a Run in Terminal button). `xcode-select --install` opens a macOS dialog on that Mac's screen for the human to click Install.
- Sign-in needs the human at a terminal on that Mac: `claude`, `codex login` or `agy`, each run once. `claude auth status` (JSON, `loggedIn`) and `codex login status` show whether one is signed in; agy has no status command, so ask.
- The service's `PATH` is fixed when it is installed, and your own shell has the same one. When a tool is found through the login shell but not by `/Applications/Byre.app/Contents/Helpers/byre check` run directly, reinstall the service from the login shell so it picks the new `PATH` up: `"$SHELL" -l -c '/Applications/Byre.app/Contents/Helpers/byre install'`. That restarts byre and cuts your turn off; you resume with a restart message, so say before running it that you will carry on afterwards.
- Google Chrome, for agents' browser tools, asks "downloaded from the Internet" on its first launch, and can't be driven until the human answers Open.
## Permissions on the server's Mac
Agents see and control the server's Mac, and read its Desktop, Documents, Downloads and iCloud Drive folders, through macOS privacy grants that belong to byre. Check them with a copy of `byre-hands` (each run needs its own path):
```
d=$(mktemp -d) && cp /Applications/Byre.app/Contents/Helpers/byre-hands "$d/" && "$d/byre-hands" check; rm -rf "$d"
```
It prints a JSON array, one entry per grant: `name`, `status` (`granted`, `missing`, or `unchecked` when the test couldn't run, such as Automation of Orion while Orion isn't running), `detail` (what to switch on) and `settings`, the `x-apple.systempreferences` URL of its System Settings pane.
- A missing folder grant makes macOS show a prompt on that Mac's screen during the check, and the check waits until it is answered, so tell the human to be at that Mac before you run it, and give the call a timeout of a few minutes.
- For Screen Recording, Accessibility and Automation, open the pane for the human with `open '<settings>'` and tell them which switch to turn on. Accessibility can list byre switched off; only the switch being on counts.
- Check again after the human says they've done it.
## Client Macs
`list_clients` lists the human's Macs with the app open (and their iPhone, which needs nothing). Agents use a client Mac through `client_hands` and the client file tools, with grants that belong to byre's app there. Check them with `client_bash` on that Mac, running the same `byre-hands` command as above, and open a missing grant's pane there the same way with `open '<settings>'`. Ask before opening anything on a client Mac's screen, and only when the human is at it. The human can also run the check from the app's Settings tab on that Mac.
Client Macs need no agent CLIs. Google Chrome is optional there, for agents' `chrome` tool on that Mac; `"$SHELL" -l -c 'brew install --cask google-chrome'` through `client_bash` installs it when `brew` is there.
## What to leave alone
Don't change anything the check reports as found, and don't install optional tools the human doesn't want.
+1
View File
@@ -31,6 +31,7 @@ const leadGuidance = `You are the human's lead agent in byre, shown in the left
- Reviews: after each new snapshot of a task, the stages of its project's review workflow (a saved workflow whose stages are single agents, set per project with set_review_workflow) review the change, each a reviewer agent on its stage's model; a stage after others gets their reviews. A project with no review workflow isn't reviewed. Once every stage has reviewed the snapshot, the task's agent gets all their findings in one message. The results are in the task's transcript, where its agent answers each finding with respond_to_finding (fixing, or ignoring with a reason), and read_transcript shows each review's findings. They are for the human to look at when they want; mention one only when its findings matter to what the human is deciding. - Reviews: after each new snapshot of a task, the stages of its project's review workflow (a saved workflow whose stages are single agents, set per project with set_review_workflow) review the change, each a reviewer agent on its stage's model; a stage after others gets their reviews. A project with no review workflow isn't reviewed. Once every stage has reviewed the snapshot, the task's agent gets all their findings in one message. The results are in the task's transcript, where its agent answers each finding with respond_to_finding (fixing, or ignoring with a reason), and read_transcript shows each review's findings. They are for the human to look at when they want; mention one only when its findings matter to what the human is deciding.
- Dig into context with list_tasks, read_transcript, read_inbox and read_status (vendor rate limits and agent health), and with your own Read, Grep and Bash on a task's worktree path (from list_tasks). Don't edit files in task worktrees; ask the task's agent with send_message. - Dig into context with list_tasks, read_transcript, read_inbox and read_status (vendor rate limits and agent health), and with your own Read, Grep and Bash on a task's worktree path (from list_tasks). Don't edit files in task worktrees; ask the task's agent with send_message.
- You can create tasks, start TODO items, message, interrupt and compact task agents, and merge or discard tasks. Merge pushes to the default branch and Discard destroys work: do either only when the human asks for it. - You can create tasks, start TODO items, message, interrupt and compact task agents, and merge or discard tasks. Merge pushes to the default branch and Discard destroys work: do either only when the human asks for it.
- Setup: when the human asks you to set byre up, or about the tools or macOS permissions its agents need, read the setup knowledge-base article and walk them through it, running its checks and fixes yourself with your own Bash on this Mac and with list_clients and client_bash on their Macs.
- Projects: when the human asks you to add a project, create it with create_project from its name and the path of its git repository on this machine. - Projects: when the human asks you to add a project, create it with create_project from its name and the path of its git repository on this machine.
- Workflows: you manage the server's workflows with list_workflows, read_workflow, save_workflow and delete_workflow, and run one by giving its name to create_task or start_todo. A workflow is a tree of steps run in order, each a stage, an order or a parallel; every stage runs as its own task on the stage's model once the step before it has finished, so stages fan out (a parallel after a stage) and fan in (a stage after a parallel); a stage's agent calls finish_stage to hand its output to the stages after it, signals tell you when a stage starts and when the workflow finishes, and the workflow finishes once every stage has; byre then discards the run's other stage tasks, leaving the task of each last stage (one per branch when it ends in a parallel) to merge. Each last stage's agent is asked whether its task is ready to merge as soon as its own stage has finished and been reviewed, without waiting for the other last stages. Whenever you show or propose a workflow, draw it as a fenced diagram block (its format is the diagrams knowledge-base article) of its stage names only, with no models: one row per step, a parallel's stages side by side in one row, and an arrow into each stage from the stages before it. For example, rows holding Build; Review and Test; Fix, with the arrows "build -> review", "build -> test", "review -> fix" and "test -> fix". - Workflows: you manage the server's workflows with list_workflows, read_workflow, save_workflow and delete_workflow, and run one by giving its name to create_task or start_todo. A workflow is a tree of steps run in order, each a stage, an order or a parallel; every stage runs as its own task on the stage's model once the step before it has finished, so stages fan out (a parallel after a stage) and fan in (a stage after a parallel); a stage's agent calls finish_stage to hand its output to the stages after it, signals tell you when a stage starts and when the workflow finishes, and the workflow finishes once every stage has; byre then discards the run's other stage tasks, leaving the task of each last stage (one per branch when it ends in a parallel) to merge. Each last stage's agent is asked whether its task is ready to merge as soon as its own stage has finished and been reviewed, without waiting for the other last stages. Whenever you show or propose a workflow, draw it as a fenced diagram block (its format is the diagrams knowledge-base article) of its stage names only, with no models: one row per step, a parallel's stages side by side in one row, and an arrow into each stage from the stages before it. For example, rows holding Build; Review and Test; Fix, with the arrows "build -> review", "build -> test", "review -> fix" and "test -> fix".
- Schedules: when the human asks for work to run on a timer (every Monday, nightly), you manage it with list_schedules, save_schedule and delete_schedule; the human sees and edits the same schedules on the project's dashboard. Every schedule runs a saved workflow: for a one-agent chore, save a one-stage workflow with save_workflow first. On each run, byre starts the schedule's workflow as create_task with workflow would, created by byre, and you get its created signal; a run that fails to start reaches you as a signal. - Schedules: when the human asks for work to run on a timer (every Monday, nightly), you manage it with list_schedules, save_schedule and delete_schedule; the human sees and edits the same schedules on the project's dashboard. Every schedule runs a saved workflow: for a one-agent chore, save a one-stage workflow with save_workflow first. On each run, byre starts the schedule's workflow as create_task with workflow would, created by byre, and you get its created signal; a run that fails to start reaches you as a signal.
+1 -1
View File
@@ -914,7 +914,7 @@ func (m *Manager) startLive(ctx context.Context, sess api.AgentSession, task api
return nil, err return nil, err
} }
l.notes = "\n\n" + notes l.notes = "\n\n" + notes
tools = append(m.leadTools(l), m.readKnowledgeTool(), m.renderDiagramTool()) tools = append(append(m.leadTools(l), m.readKnowledgeTool(), m.renderDiagramTool()), m.clientShellTools()...)
} }
env := git.IdentityEnv(l.gitName, l.gitEmail) env := git.IdentityEnv(l.gitName, l.gitEmail)
servers := []*mcp.Server{{Name: "byre", Version: "0.0.0", Tools: tools}} servers := []*mcp.Server{{Name: "byre", Version: "0.0.0", Tools: tools}}
+23
View File
@@ -26,6 +26,8 @@ private let leadWelcome = """
Start in [Settings](byre-app://tab?name=settings): \(leadSettings) Start in [Settings](byre-app://tab?name=settings): \(leadSettings)
""" """
private let leadSetup = "Walk me through setting up byre: the tools its agents need, signing in to their vendors, and the macOS permissions on the server's Mac and on my Macs."
struct AttentionGroup: Identifiable { struct AttentionGroup: Identifiable {
let id: String let id: String
let label: String let label: String
@@ -501,6 +503,20 @@ final class ChatModel {
} }
} }
func askSetup(_ overlays: Overlays) {
let sendID = newID("snd")
let cancel = builder.showPending(leadSetup, [], sendID)
Task {
do {
try await send(sessionId: liveSession?.id, text: leadSetup, images: nil, model: nil, firstModel: store.defaultModel, sendID: sendID)
} catch {
if cancel() {
overlays.showAlert(errorText(error))
}
}
}
}
func withdraw(_ p: PendingSend, _ overlays: Overlays) async { func withdraw(_ p: PendingSend, _ overlays: Overlays) async {
guard let taskId, let inputId = p.inputId else { guard let taskId, let inputId = p.inputId else {
return return
@@ -802,6 +818,7 @@ private struct ScrollMetrics: Equatable {
private struct TranscriptScroll: View { private struct TranscriptScroll: View {
let model: ChatModel let model: ChatModel
@Environment(Store.self) private var store @Environment(Store.self) private var store
@Environment(Overlays.self) private var overlays
@Environment(\.paneAccent) private var accent @Environment(\.paneAccent) private var accent
@ViewState private var position = ScrollPosition(edge: .bottom) @ViewState private var position = ScrollPosition(edge: .bottom)
@ViewState private var scrolling = false @ViewState private var scrolling = false
@@ -835,6 +852,12 @@ private struct TranscriptScroll: View {
if model.welcome { if model.welcome {
MarkdownView(blocks: parseMarkdown(leadWelcome)) MarkdownView(blocks: parseMarkdown(leadWelcome))
.padding(.top, 12) .padding(.top, 12)
Button("Walk me through setup") {
model.askSetup(overlays)
}
.buttonStyle(WebButtonStyle())
.help("Ask your lead to check and set up the tools and permissions byre's agents need")
.padding(.top, 12)
} }
} }
} }