Fix inconsistencies found by consistency audit of 395f76e

This commit is contained in:
Ian Gulliver
2026-10-23 11:48:42 -07:00
parent 836d3019ac
commit f1d3f9be61
17 changed files with 376 additions and 362 deletions
+7 -7
View File
@@ -96,10 +96,10 @@ func (m *Manager) clientTools(l *live) []mcp.Tool {
},
{
Name: "show_page",
Description: "Show the human a file from the Mac byre runs on, or a website, in byre's app on a client Mac, rendered in the page view beside this task's transcript, as a browser would show it: an HTML page (loading the stylesheets, scripts and images beside it), a PDF, an image, or (with url) a web page in a new tab. " +
Description: "Show the human a file from the Mac byre runs on, or a website, in byre's app on a client Mac, rendered in the Page view beside this task's transcript, as a browser would show it: an HTML page (loading the stylesheets, scripts and images beside it), a PDF, an image, or (with url) a web page in a new tab. " +
"A page loads other files only by relative paths (style.css, ../img/cat.png); absolute paths and file:// addresses don't load. " +
"Whenever you write or change a file the human should see as it looks (an HTML mockup or preview, a PDF, an image, an SVG), show it with this before your turn ends, without being asked or asking first. " +
"When work needs a website (a developer console, a dashboard, a settings page), open it with url and work in it with drive_page rather than asking the human to open it; the page view keeps its sign-ins, so ask the human only to sign in. " +
"When work needs a website (a developer console, a dashboard, a settings page), open it with url and work in it with drive_page rather than asking the human to open it; the Page view keeps its sign-ins, so ask the human only to sign in. " +
"Show it on the Mac the human's latest message was sent from.",
InputSchema: json.RawMessage(`{
"type": "object",
@@ -116,19 +116,19 @@ func (m *Manager) clientTools(l *live) []mcp.Tool {
},
{
Name: "drive_page",
Description: "Work in the tabs of this task's page view in byre's app on a client Mac, which show_page opened: the human sees each step there as it happens. " +
Description: "Work in the tabs of this task's Page view in byre's app on a client Mac, which show_page opened: the human sees each step there as it happens. " +
"It needs no mouse or keyboard, so it never disturbs the human. " +
"ops: tabs (list the tabs: number, title, address, and which one shows), navigate (load url in the tab and wait for it), " +
"js (run code in the tab's page: the body of an async function, so await works and return gives the result; strings come back as they are, other values as JSON; use it to read the DOM, click (element.click()) and fill fields (set value, then dispatch input and change events)), " +
"capture (see the tab as it's drawn; only the tab the page view shows can be captured, and only while the human has the page view open). " +
"Without tab, it acts on the tab the page view shows. Links that open a new window open as new tabs. " +
"capture (see the tab as it's drawn; only the tab the Page view shows can be captured, and only while the human has the Page view open). " +
"Without tab, it acts on the tab the Page view shows. Links that open a new window open as new tabs. " +
"A page's alert, confirm or prompt asks the human, and the js call waits for the answer; while the tab isn't showing, they answer Cancel at once.",
InputSchema: json.RawMessage(`{
"type": "object",
"properties": {
"client": {"type": "string", "description": "The client's name from list_clients, or its id when several are connected from that Mac."},
"op": {"type": "string", "enum": ["tabs", "navigate", "js", "capture"]},
"tab": {"type": "integer", "description": "The tab's number from tabs (default: the tab the page view shows)."},
"tab": {"type": "integer", "description": "The tab's number from tabs (default: the tab the Page view shows)."},
"url": {"type": "string", "description": "For navigate."},
"code": {"type": "string", "description": "For js."}
},
@@ -520,7 +520,7 @@ func (m *Manager) show(ctx context.Context, l *live, raw json.RawMessage, tool s
return "", err
}
if op == api.OpenPage && fi.IsDir() {
return "", fmt.Errorf("%s is a directory; the page view shows a file", args.Path)
return "", fmt.Errorf("%s is a directory; the Page view shows a file", args.Path)
}
shown := full
+1 -1
View File
@@ -47,7 +47,7 @@ func (m *Manager) askTool(l *live) mcp.Tool {
"so the human can compare them at a glance. " +
"End your turn after asking; the answer arrives as your next message. " +
"An answer of \"Use your judgment for this decision and continue within the existing task instructions.\" lets you settle that one decision yourself; " +
"it never grants an authorization the owner must give explicitly, such as to deploy, push or commit: ask for that on its own. " +
"it never grants an authorization the human must give explicitly, such as to deploy, push or commit: ask for that on its own. " +
"One call is one decision, answered by picking from its own choices. When you have several decisions, such as a design with several choices, " +
"never bundle them into one call that asks for approval of them all: call this once per decision, each with its own context and choices; they are answered together.",
InputSchema: json.RawMessage(`{
+1 -1
View File
@@ -2,7 +2,7 @@ How a script or plain shell runs a command on a client Mac without an agent (byr
# Running commands on a client Mac from a shell
`client_bash` needs an agent. For a script or plain shell on the machine byre runs on, such as a wrapper that fetches a token from the human's Mac, use:
`client_bash` needs an agent. For a script or plain shell on the Mac byre runs on, such as a wrapper that fetches a token from the human's Mac, use:
```
byre client-exec [--client NAME] [--timeout SECS] -- CMD...
+2 -2
View File
@@ -2,11 +2,11 @@ How byre signs merge commits on the merging user's Mac, and how to turn it on fo
# Signing merge commits
byre never signs with a key on the machine it runs on: its own end-of-turn and snapshot commits there are always unsigned. When a project checkout (or the server's global config) has `commit.gpgsign` true, the squash commit of a Merge or `merge_to_main` is signed on the merging user's most recently active connected Mac, so a key that never leaves that Mac (a Secure Enclave key behind Touch ID, say) works. The merge fails when that user has no app connected.
byre never signs with a key on the Mac it runs on: its own end-of-turn and snapshot commits there are always unsigned. When a project checkout (or the server's global config) has `commit.gpgsign` true, the squash commit of a Merge or `merge_to_main` is signed on the merging user's most recently active connected Mac, so a key that never leaves that Mac (a Secure Enclave key behind Touch ID, say) works. The merge fails when that user has no app connected.
## Turning it on
Run, on the machine byre runs on:
Run, on the Mac byre runs on:
```
byre signing <checkout>
+2 -2
View File
@@ -15,7 +15,7 @@ import (
)
const leadGuidance = `You are the human's lead agent in byre, shown in the left pane of byre's app. The human talks to you there, and you coordinate every task agent on their behalf. You don't do task work yourself: task agents work in their own worktrees, and you read, direct and report on them.
- Signals: byre sends you, as messages from byre, what happens across tasks: questions that task agents ask, errors and rate limits their sessions hit, turns they finish with their final message, a task's agent saying the task is ready to merge (with its overview of the whole task, which byre asks for once the review of its latest work has finished and its turn has ended) or suggesting the human discard it (with its reasoning), questions the human answered, tasks created, reviews started and finished, a merge held behind another task's or set to start after the review (and that canceled or dropped), starting to merge, merged or discarded, and every change of a task's state, as "<task> state: <before> → <now>." listed first among what happened at the same moment. State changes, reviews starting, and tasks the human created or started merging never wake you on their own; they arrive only alongside another signal. A task merged or discarded always wakes you, whoever closed it. The states are running, idle, finished (a workflow stage's task once its finish_stage has taken), review_pending, reviewing, merging, discarding, merged, discarded and no_agent. A finished turn arrives with its state change: review_pending when byre is about to review the turn's work, reviewing while the review runs; neither is done, since the review can still find problems, so don't treat a task's work as finished until its state goes to idle or finished. Several may arrive in one message, followed by the current task list (as list_tasks gives it) and what your right pane shows, so you rarely need to call list_tasks after a signal. The human doesn't see signals. Messages from the human arrive separately.
- Signals: byre sends you, as messages from byre, what happens across tasks: questions that task agents ask, errors and rate limits their sessions hit, turns they finish with their final message, a task's agent saying the task is ready to merge (with its overview of the whole task, which byre asks for once the review of its latest work has finished and its turn has ended) or suggesting the human discard it (with its reasoning), questions the human answered, tasks created, reviews started and finished, a merge held behind another task's or set to start after the review (and that canceled or dropped), starting to merge, merged or discarded, and every change of a task's state, as "<task> state: <before> → <now>." listed first among what happened at the same moment. State changes, reviews starting, and tasks the human created or started merging never wake you on their own; they arrive only alongside another signal. A task merged or discarded always wakes you, whoever closed it. The states are running, idle, finished (a workflow stage's task once its finish_stage has taken), review_pending, reviewing, asking (it has an open question), ready_to_merge and discard_suggested (the agent's ready_for_merge or suggest_discard still stands), merge_held (its Merge waits for another merge in the project), merge_after_review (its Merge waits for the running review), merging, pushing (byre is pushing the merge's squash commit), discarding, merged, discarded and no_agent (it has no live agent). A finished turn arrives with its state change: review_pending when byre is about to review the turn's work, reviewing while the review runs; neither is done, since the review can still find problems, so don't treat a task's work as finished until its state goes to idle or finished. Several may arrive in one message, followed by the current task list (as list_tasks gives it) and what your right pane shows, so you rarely need to call list_tasks after a signal. The human doesn't see signals. Messages from the human arrive separately.
- Don't respond to what the human just did. A signal about their own action (a question they answered, a task they created, merged, started merging or discarded) tells them nothing new: don't report, confirm or comment on it. Act on it only if it changes what you are doing, and then end the turn with one short line at most. When a batch of signals needs nothing from you to the human, make your final message exactly NO_REPLY and nothing else; byre folds that turn away so the human doesn't see it.
- "Your right pane is free" means the human finished what was in the right pane. When it says the human has watched an agent work for 10 seconds, byre sends it only while another task has something waiting on them, so something does. Show them the next thing that needs them, most urgent first (questions, then errors in the task's transcript, then finished turns, then tasks ready to merge or suggested for discarding), with one line saying what it is. If nothing needs them, show that project with no task, then post a short status: one line per active task (what it's doing or waiting on), then up to three TODO items you'd start next (from list_tasks), each with a one-line reason. Write each item as a link to #/todo/<project_id>/<title, URL-encoded with parentheses as %28 and %29>, for example [Fix login redirect](#/todo/prj3f2a9C1b7dQ/Fix%20login%20redirect): byre draws it with a Start button the human can click, and once the task exists, its state. Start one with start_todo only when the human picks it. If that says nothing new since your last status, make your final message NO_REPLY.
- Whenever you suggest new work that isn't in TODO.md (a task you think is worth doing, an improvement to byre or to your own role), write it as a link to #/suggest/<project_id>/<title>/<brief>, both URL-encoded with parentheses as %28 and %29, for example [Lead tool for admin status](#/suggest/prj3f2a9C1b7dQ/Lead%20tool%20for%20admin%20status/Add%20a%20lead%20tool%20that%20reads%20%2Fapi%2Fadmin%2Fstatus%20...). The brief is the new task agent's whole first message, so make it a complete brief, as for create_task. byre draws the link with two buttons: Start creates the task with that title and brief at once, without you, and Discuss sends you a message asking to talk the suggestion over. Once an active task has that title, it shows the task's state instead. Don't ask whether to start a suggestion; the buttons do that.
@@ -32,7 +32,7 @@ const leadGuidance = `You are the human's lead agent in byre, shown in the left
- 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.
- 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. Never restart byre with launchctl or tell the human to; the article says how.
- 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. When they only hint at where it is, find it yourself. When they ask for a new one, make a local-only repository (git init, no remote, an empty first commit) where they say, or in a sensible place if they don't, and add that.
- 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 Mac. When they only hint at where it is, find it yourself. When they ask for a new one, make a local-only repository (git init, no remote, an empty first commit) where they say, or in a sensible place if they don't, and add that.
- 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, a parallel or a random (one of its weighted steps, picked when the run starts); 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.
- Whenever you name a task in a message, link it as a Markdown link to #/task/<task_id>, for example [Fix login redirect](#/task/tskDa7e4K7305e). byre draws it in that task's color, and clicking it shows the task in the right pane. To also open one of its other views over the human's left pane, append it: #/task/<task_id>/<view>, where view is changes, files, terminal or board. To show a project's dashboard in the right pane, link to #/project/<project_id>.
+1 -1
View File
@@ -313,7 +313,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
}),
tool("create_project",
"Add a project to byre for the human: name it, and give the path of a git repository on this machine. "+
"Add a project to byre for the human: name it, and give the path of a git repository on this Mac. "+
"byre records the repository's root and default branch. Returns the project as JSON.",
`{"type": "object", "properties": {
"name": {"type": "string"},
+2 -1
View File
@@ -156,7 +156,8 @@ func (m *Manager) servePreview(port int) error {
upgrade.Method = http.MethodPost
check = &upgrade
}
if err := protection.Check(check); err != nil {
err := protection.Check(check)
if err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}