Replace the Todo tab with a Project dashboard of tasks and TODO items

This commit is contained in:
Ian Gulliver
2026-10-15 10:36:32 -07:00
parent e0d292fd75
commit b6df27f085
23 changed files with 201 additions and 133 deletions
+2 -2
View File
@@ -17,9 +17,9 @@ import (
const leadGuidance = `You are the human's lead agent in byre, shown in the left pane of byre's web UI. 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, turn reports and errors that task agents file, questions the human answered, tasks created, merged or discarded. Several may arrive in one message. 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 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. Show them the next thing that needs them, most urgent first (blocked questions and errors, then reports, then tasks ready to merge), with one line saying what it is. If nothing needs them, show that project's todo tab and make your final message NO_REPLY.
- "Your right pane is free" means the human finished what was in the right pane. Show them the next thing that needs them, most urgent first (blocked questions and errors, then reports, then tasks ready to merge), with one line saying what it is. If nothing needs them, show that project's project tab and make your final message NO_REPLY.
- Steering the right pane is a core part of your job, as important as what you write. The right pane shows one task, or a project with no task; point it with show (the task or project, the tabs to put first, the tab to select). By default, keep it on whatever you and the human are discussing, so they can see it while they read your reply; don't make them go looking for it. Call show in the same turn you bring something up:
- Discussing, picking or starting TODO items: the project's todo tab (show with project_id when no task of that project is involved).
- Discussing, picking or starting TODO items, or a project's tasks as a whole: the project's project tab (show with project_id when no single task of that project is involved).
- A question or report that needs the human: that task's inbox tab, and say in a sentence or two what it is and what you recommend.
- Discussing a task's work, what its agent did or is doing, or whether it is ready to merge: its transcript tab. A specific file in its worktree: its files tab.
- The changes tab only when the human asks to see the diff; they rarely want it.
+3 -3
View File
@@ -107,7 +107,7 @@ func TestFocusProject(t *testing.T) {
e := newEnv(t)
m := e.manager()
err := m.SetFocus(e.ctx, login, api.Focus{ProjectId: &e.project.Id, Tabs: []api.TaskTab{api.TabTodo}, Tab: api.TabTodo}, login)
err := m.SetFocus(e.ctx, login, api.Focus{ProjectId: &e.project.Id, Tabs: []api.TaskTab{api.TabProject}, Tab: api.TabProject}, login)
if err != nil {
t.Fatalf("focus project: %v", err)
}
@@ -115,7 +115,7 @@ func TestFocusProject(t *testing.T) {
if err != nil {
t.Fatalf("get focus: %v", err)
}
if f.TaskId != nil || f.ProjectId == nil || *f.ProjectId != e.project.Id || f.Tab != api.TabTodo {
if f.TaskId != nil || f.ProjectId == nil || *f.ProjectId != e.project.Id || f.Tab != api.TabProject {
t.Fatalf("focus %+v", f)
}
@@ -132,7 +132,7 @@ func TestFocusProject(t *testing.T) {
t.Fatalf("focus %+v", f)
}
err = m.SetFocus(e.ctx, login, api.Focus{ProjectId: &other, Tabs: []api.TaskTab{}, Tab: api.TabTodo}, login)
err = m.SetFocus(e.ctx, login, api.Focus{ProjectId: &other, Tabs: []api.TaskTab{}, Tab: api.TabProject}, login)
if err == nil {
t.Fatal("focus on an unknown project was accepted")
}
+3 -3
View File
@@ -293,14 +293,14 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
tool("show",
"Point the human's right pane at a task, or at a project with no task: tabs are the tabs to put first, in order (the rest follow), and tab is the one to select. "+
"Tabs: transcript, changes, files, inbox (the task's open items), todo (the project's TODO.md); with only project_id, only todo shows anything. "+
"Tabs: transcript, changes, files, inbox (the task's open items), project (the project's dashboard: its active tasks and its TODO.md items); with only project_id, only project shows anything. "+
"Omit both task_id and project_id to clear the pane. "+
"Refused while the human is working in the right pane, unless what it shows is finished (a merged or discarded task, or an inbox tab with nothing left).",
`{"type": "object", "properties": {
"task_id": {"type": "string"},
"project_id": {"type": "string", "description": "Ignored when task_id is given."},
"tabs": {"type": "array", "items": {"type": "string", "enum": ["transcript", "changes", "files", "inbox", "todo"]}},
"tab": {"type": "string", "enum": ["transcript", "changes", "files", "inbox", "todo"]}
"tabs": {"type": "array", "items": {"type": "string", "enum": ["transcript", "changes", "files", "inbox", "project"]}},
"tab": {"type": "string", "enum": ["transcript", "changes", "files", "inbox", "project"]}
}, "required": ["tabs", "tab"]}`,
func(ctx context.Context, user api.User, raw json.RawMessage) (string, error) {
f := api.Focus{}
+1 -1
View File
@@ -941,7 +941,7 @@ func TestStartTodo(t *testing.T) {
e := newEnv(t)
m := e.manager()
writeTestFile(t, filepath.Join(e.repo, "TODO.md"), "# Todo\n\n- Create hello.txt\n It holds the single line `hi`.\n- Leave this one alone\n")
writeTestFile(t, filepath.Join(e.repo, "TODO.md"), "# TODO\n\n- Create hello.txt\n It holds the single line `hi`.\n- Leave this one alone\n")
gitOut(t, e.repo, "add", "TODO.md")
gitOut(t, e.repo, "commit", "--quiet", "--message", "add todo")
+68 -68
View File
@@ -323,7 +323,7 @@ const (
TabChanges TaskTab = "changes"
TabFiles TaskTab = "files"
TabInbox TaskTab = "inbox"
TabTodo TaskTab = "todo"
TabProject TaskTab = "project"
TabTranscript TaskTab = "transcript"
)
@@ -336,7 +336,7 @@ func (e TaskTab) Valid() bool {
return true
case TabInbox:
return true
case TabTodo:
case TabProject:
return true
case TabTranscript:
return true
@@ -2620,72 +2620,72 @@ var swaggerSpec = []string{
"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",
}
// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+4
View File
@@ -253,6 +253,10 @@ ALTER TABLE tasks ADD COLUMN merging_by TEXT NOT NULL DEFAULT '';
`}, {"flag-handoff-prompts", `
UPDATE events SET payload = json_set(payload, '$.handoff', json('true'))
WHERE kind = 'user.message' AND actor = 'byre' AND json_extract(payload, '$.text') LIKE 'Write a handoff for a fresh %';
`}, {"rename-todo-tab-to-project", `
UPDATE users SET focus = json_set(focus,
'$.tab', CASE json_extract(focus, '$.tab') WHEN 'todo' THEN 'project' ELSE json_extract(focus, '$.tab') END,
'$.tabs', json((SELECT json_group_array(CASE value WHEN 'todo' THEN 'project' ELSE value END) FROM json_each(users.focus, '$.tabs'))));
`}}
type Store struct {