From ad8ba4aac6e091bf2b7ce8dcb4716e46ba2b7f27 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Tue, 25 Nov 2025 15:50:22 +0200 Subject: [PATCH] feat(cli): promote tasks commands from experimental to GA (#20916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Overview This change promotes the tasks CLI commands from `coder exp task` to `coder task`, marking them as generally available (GA). ## Migration Users will need to update their scripts from: ```shell coder exp task create "my task" ``` To: ```shell coder task create "my task" ``` --- 🤖 This change was written by Claude Sonnet 4.5 Thinking using [mux](https://github.com/coder/mux) and reviewed by a human 🏄🏻‍♂️ --- cli/root.go | 2 +- cli/{exp_task.go => task.go} | 2 +- cli/{exp_task_create.go => task_create.go} | 12 +- ...ask_create_test.go => task_create_test.go} | 2 +- cli/{exp_task_delete.go => task_delete.go} | 8 +- ...ask_delete_test.go => task_delete_test.go} | 2 +- cli/{exp_task_list.go => task_list.go} | 12 +- ...xp_task_list_test.go => task_list_test.go} | 14 +- cli/{exp_task_logs.go => task_logs.go} | 2 +- ...xp_task_logs_test.go => task_logs_test.go} | 12 +- cli/{exp_task_send.go => task_send.go} | 4 +- ...xp_task_send_test.go => task_send_test.go} | 12 +- cli/{exp_task_status.go => task_status.go} | 4 +- ...ask_status_test.go => task_status_test.go} | 2 +- cli/{exp_task_test.go => task_test.go} | 12 +- cli/testdata/coder_--help.golden | 1 + cli/testdata/coder_task_--help.golden | 19 ++ cli/testdata/coder_task_create_--help.golden | 51 ++++ cli/testdata/coder_task_delete_--help.golden | 27 ++ cli/testdata/coder_task_list_--help.golden | 50 ++++ cli/testdata/coder_task_logs_--help.golden | 20 ++ cli/testdata/coder_task_send_--help.golden | 21 ++ cli/testdata/coder_task_status_--help.golden | 30 +++ docs/ai-coder/cli.md | 235 +----------------- docs/manifest.json | 35 +++ docs/reference/cli/index.md | 1 + docs/reference/cli/task.md | 25 ++ docs/reference/cli/task_create.md | 100 ++++++++ docs/reference/cli/task_delete.md | 40 +++ docs/reference/cli/task_list.md | 92 +++++++ docs/reference/cli/task_logs.md | 38 +++ docs/reference/cli/task_send.md | 32 +++ docs/reference/cli/task_status.md | 55 ++++ 33 files changed, 697 insertions(+), 277 deletions(-) rename cli/{exp_task.go => task.go} (91%) rename cli/{exp_task_create.go => task_create.go} (92%) rename cli/{exp_task_create_test.go => task_create_test.go} (99%) rename cli/{exp_task_delete.go => task_delete.go} (90%) rename cli/{exp_task_delete_test.go => task_delete_test.go} (99%) rename cli/{exp_task_list.go => task_list.go} (92%) rename cli/{exp_task_list_test.go => task_list_test.go} (94%) rename cli/{exp_task_logs.go => task_logs.go} (96%) rename cli/{exp_task_logs_test.go => task_logs_test.go} (92%) rename cli/{exp_task_send.go => task_send.go} (90%) rename cli/{exp_task_send_test.go => task_send_test.go} (90%) rename cli/{exp_task_status.go => task_status.go} (97%) rename cli/{exp_task_status_test.go => task_status_test.go} (99%) rename cli/{exp_task_test.go => task_test.go} (96%) create mode 100644 cli/testdata/coder_task_--help.golden create mode 100644 cli/testdata/coder_task_create_--help.golden create mode 100644 cli/testdata/coder_task_delete_--help.golden create mode 100644 cli/testdata/coder_task_list_--help.golden create mode 100644 cli/testdata/coder_task_logs_--help.golden create mode 100644 cli/testdata/coder_task_send_--help.golden create mode 100644 cli/testdata/coder_task_status_--help.golden create mode 100644 docs/reference/cli/task.md create mode 100644 docs/reference/cli/task_create.md create mode 100644 docs/reference/cli/task_delete.md create mode 100644 docs/reference/cli/task_list.md create mode 100644 docs/reference/cli/task_logs.md create mode 100644 docs/reference/cli/task_send.md create mode 100644 docs/reference/cli/task_status.md diff --git a/cli/root.go b/cli/root.go index fe6d5c4ccd..b04570956c 100644 --- a/cli/root.go +++ b/cli/root.go @@ -104,6 +104,7 @@ func (r *RootCmd) CoreSubcommands() []*serpent.Command { r.resetPassword(), r.sharing(), r.state(), + r.tasksCommand(), r.templates(), r.tokens(), r.users(), @@ -149,7 +150,6 @@ func (r *RootCmd) AGPLExperimental() []*serpent.Command { r.mcpCommand(), r.promptExample(), r.rptyCommand(), - r.tasksCommand(), r.boundary(), } } diff --git a/cli/exp_task.go b/cli/task.go similarity index 91% rename from cli/exp_task.go rename to cli/task.go index b7a0ada15b..865d1869bf 100644 --- a/cli/exp_task.go +++ b/cli/task.go @@ -8,7 +8,7 @@ func (r *RootCmd) tasksCommand() *serpent.Command { cmd := &serpent.Command{ Use: "task", Aliases: []string{"tasks"}, - Short: "Experimental task commands.", + Short: "Manage tasks", Handler: func(i *serpent.Invocation) error { return i.Command.HelpHandler(i) }, diff --git a/cli/exp_task_create.go b/cli/task_create.go similarity index 92% rename from cli/exp_task_create.go rename to cli/task_create.go index b506d679eb..a0677d5ef0 100644 --- a/cli/exp_task_create.go +++ b/cli/task_create.go @@ -28,27 +28,27 @@ func (r *RootCmd) taskCreate() *serpent.Command { cmd := &serpent.Command{ Use: "create [input]", - Short: "Create an experimental task", + Short: "Create a task", Long: FormatExamples( Example{ Description: "Create a task with direct input", - Command: "coder exp task create \"Add authentication to the user service\"", + Command: "coder task create \"Add authentication to the user service\"", }, Example{ Description: "Create a task with stdin input", - Command: "echo \"Add authentication to the user service\" | coder exp task create", + Command: "echo \"Add authentication to the user service\" | coder task create", }, Example{ Description: "Create a task with a specific name", - Command: "coder exp task create --name task1 \"Add authentication to the user service\"", + Command: "coder task create --name task1 \"Add authentication to the user service\"", }, Example{ Description: "Create a task from a specific template / preset", - Command: "coder exp task create --template backend-dev --preset \"My Preset\" \"Add authentication to the user service\"", + Command: "coder task create --template backend-dev --preset \"My Preset\" \"Add authentication to the user service\"", }, Example{ Description: "Create a task for another user (requires appropriate permissions)", - Command: "coder exp task create --owner user@example.com \"Add authentication to the user service\"", + Command: "coder task create --owner user@example.com \"Add authentication to the user service\"", }, ), Middleware: serpent.Chain( diff --git a/cli/exp_task_create_test.go b/cli/task_create_test.go similarity index 99% rename from cli/exp_task_create_test.go rename to cli/task_create_test.go index aea11e4378..81e05936d1 100644 --- a/cli/exp_task_create_test.go +++ b/cli/task_create_test.go @@ -329,7 +329,7 @@ func TestTaskCreate(t *testing.T) { ctx = testutil.Context(t, testutil.WaitShort) srv = httptest.NewServer(tt.handler(t, ctx)) client = codersdk.New(testutil.MustURL(t, srv.URL)) - args = []string{"exp", "task", "create"} + args = []string{"task", "create"} sb strings.Builder err error ) diff --git a/cli/exp_task_delete.go b/cli/task_delete.go similarity index 90% rename from cli/exp_task_delete.go rename to cli/task_delete.go index 1611e4196e..20a7c127b7 100644 --- a/cli/exp_task_delete.go +++ b/cli/task_delete.go @@ -17,19 +17,19 @@ import ( func (r *RootCmd) taskDelete() *serpent.Command { cmd := &serpent.Command{ Use: "delete [ ...]", - Short: "Delete experimental tasks", + Short: "Delete tasks", Long: FormatExamples( Example{ Description: "Delete a single task.", - Command: "$ coder exp task delete task1", + Command: "$ coder task delete task1", }, Example{ Description: "Delete multiple tasks.", - Command: "$ coder exp task delete task1 task2 task3", + Command: "$ coder task delete task1 task2 task3", }, Example{ Description: "Delete a task without confirmation.", - Command: "$ coder exp task delete task4 --yes", + Command: "$ coder task delete task4 --yes", }, ), Middleware: serpent.Chain( diff --git a/cli/exp_task_delete_test.go b/cli/task_delete_test.go similarity index 99% rename from cli/exp_task_delete_test.go rename to cli/task_delete_test.go index 04bad3ea5f..fc686dc9e8 100644 --- a/cli/exp_task_delete_test.go +++ b/cli/task_delete_test.go @@ -193,7 +193,7 @@ func TestExpTaskDelete(t *testing.T) { client := codersdk.New(testutil.MustURL(t, srv.URL)) - args := append([]string{"exp", "task", "delete"}, tc.args...) + args := append([]string{"task", "delete"}, tc.args...) inv, root := clitest.New(t, args...) inv = inv.WithContext(ctx) clitest.SetupConfig(t, client, root) diff --git a/cli/exp_task_list.go b/cli/task_list.go similarity index 92% rename from cli/exp_task_list.go rename to cli/task_list.go index 89b313a1f4..8458e66252 100644 --- a/cli/exp_task_list.go +++ b/cli/task_list.go @@ -69,27 +69,27 @@ func (r *RootCmd) taskList() *serpent.Command { cmd := &serpent.Command{ Use: "list", - Short: "List experimental tasks", + Short: "List tasks", Long: FormatExamples( Example{ Description: "List tasks for the current user.", - Command: "coder exp task list", + Command: "coder task list", }, Example{ Description: "List tasks for a specific user.", - Command: "coder exp task list --user someone-else", + Command: "coder task list --user someone-else", }, Example{ Description: "List all tasks you can view.", - Command: "coder exp task list --all", + Command: "coder task list --all", }, Example{ Description: "List all your running tasks.", - Command: "coder exp task list --status running", + Command: "coder task list --status running", }, Example{ Description: "As above, but only show IDs.", - Command: "coder exp task list --status running --quiet", + Command: "coder task list --status running --quiet", }, ), Aliases: []string{"ls"}, diff --git a/cli/exp_task_list_test.go b/cli/task_list_test.go similarity index 94% rename from cli/exp_task_list_test.go rename to cli/task_list_test.go index f9255da9b3..c9b91486bb 100644 --- a/cli/exp_task_list_test.go +++ b/cli/task_list_test.go @@ -69,7 +69,7 @@ func TestExpTaskList(t *testing.T) { owner := coderdtest.CreateFirstUser(t, client) memberClient, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - inv, root := clitest.New(t, "exp", "task", "list") + inv, root := clitest.New(t, "task", "list") clitest.SetupConfig(t, memberClient, root) pty := ptytest.New(t).Attach(inv) @@ -93,7 +93,7 @@ func TestExpTaskList(t *testing.T) { wantPrompt := "build me a web app" task := makeAITask(t, db, owner.OrganizationID, owner.UserID, memberUser.ID, database.WorkspaceTransitionStart, wantPrompt) - inv, root := clitest.New(t, "exp", "task", "list", "--column", "id,name,status,initial prompt") + inv, root := clitest.New(t, "task", "list", "--column", "id,name,status,initial prompt") clitest.SetupConfig(t, memberClient, root) pty := ptytest.New(t).Attach(inv) @@ -122,7 +122,7 @@ func TestExpTaskList(t *testing.T) { pausedTask := makeAITask(t, db, owner.OrganizationID, owner.UserID, memberUser.ID, database.WorkspaceTransitionStop, "stop me please") // Use JSON output to reliably validate filtering. - inv, root := clitest.New(t, "exp", "task", "list", "--status=paused", "--output=json") + inv, root := clitest.New(t, "task", "list", "--status=paused", "--output=json") clitest.SetupConfig(t, memberClient, root) ctx := testutil.Context(t, testutil.WaitShort) @@ -153,7 +153,7 @@ func TestExpTaskList(t *testing.T) { _ = makeAITask(t, db, owner.OrganizationID, owner.UserID, memberUser.ID, database.WorkspaceTransitionStart, "other-task") task := makeAITask(t, db, owner.OrganizationID, owner.UserID, owner.UserID, database.WorkspaceTransitionStart, "me-task") - inv, root := clitest.New(t, "exp", "task", "list", "--user", "me") + inv, root := clitest.New(t, "task", "list", "--user", "me") //nolint:gocritic // Owner client is intended here smoke test the member task not showing up. clitest.SetupConfig(t, client, root) @@ -180,7 +180,7 @@ func TestExpTaskList(t *testing.T) { task2 := makeAITask(t, db, owner.OrganizationID, owner.UserID, memberUser.ID, database.WorkspaceTransitionStop, "stop me please") // Given: We add the `--quiet` flag - inv, root := clitest.New(t, "exp", "task", "list", "--quiet") + inv, root := clitest.New(t, "task", "list", "--quiet") clitest.SetupConfig(t, memberClient, root) ctx := testutil.Context(t, testutil.WaitShort) @@ -224,7 +224,7 @@ func TestExpTaskList_OwnerCanListOthers(t *testing.T) { t.Parallel() // As the owner, list only member A tasks. - inv, root := clitest.New(t, "exp", "task", "list", "--user", memberAUser.Username, "--output=json") + inv, root := clitest.New(t, "task", "list", "--user", memberAUser.Username, "--output=json") //nolint:gocritic // Owner client is intended here to allow member tasks to be listed. clitest.SetupConfig(t, ownerClient, root) @@ -252,7 +252,7 @@ func TestExpTaskList_OwnerCanListOthers(t *testing.T) { // As the owner, list all tasks to verify both member tasks are present. // Use JSON output to reliably validate filtering. - inv, root := clitest.New(t, "exp", "task", "list", "--all", "--output=json") + inv, root := clitest.New(t, "task", "list", "--all", "--output=json") //nolint:gocritic // Owner client is intended here to allow all tasks to be listed. clitest.SetupConfig(t, ownerClient, root) diff --git a/cli/exp_task_logs.go b/cli/task_logs.go similarity index 96% rename from cli/exp_task_logs.go rename to cli/task_logs.go index d1d4a826cd..0b2fd520af 100644 --- a/cli/exp_task_logs.go +++ b/cli/task_logs.go @@ -28,7 +28,7 @@ func (r *RootCmd) taskLogs() *serpent.Command { Long: FormatExamples( Example{ Description: "Show logs for a given task.", - Command: "coder exp task logs task1", + Command: "coder task logs task1", }), Middleware: serpent.Chain( serpent.RequireNArgs(1), diff --git a/cli/exp_task_logs_test.go b/cli/task_logs_test.go similarity index 92% rename from cli/exp_task_logs_test.go rename to cli/task_logs_test.go index 859ff135d0..bad8811c10 100644 --- a/cli/exp_task_logs_test.go +++ b/cli/task_logs_test.go @@ -46,7 +46,7 @@ func Test_TaskLogs(t *testing.T) { userClient := client // user already has access to their own workspace var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "logs", task.Name, "--output", "json") + inv, root := clitest.New(t, "task", "logs", task.Name, "--output", "json") inv.Stdout = &stdout clitest.SetupConfig(t, userClient, root) @@ -72,7 +72,7 @@ func Test_TaskLogs(t *testing.T) { userClient := client var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "logs", task.ID.String(), "--output", "json") + inv, root := clitest.New(t, "task", "logs", task.ID.String(), "--output", "json") inv.Stdout = &stdout clitest.SetupConfig(t, userClient, root) @@ -98,7 +98,7 @@ func Test_TaskLogs(t *testing.T) { userClient := client var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "logs", task.ID.String()) + inv, root := clitest.New(t, "task", "logs", task.ID.String()) inv.Stdout = &stdout clitest.SetupConfig(t, userClient, root) @@ -121,7 +121,7 @@ func Test_TaskLogs(t *testing.T) { userClient, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "logs", "doesnotexist") + inv, root := clitest.New(t, "task", "logs", "doesnotexist") inv.Stdout = &stdout clitest.SetupConfig(t, userClient, root) @@ -139,7 +139,7 @@ func Test_TaskLogs(t *testing.T) { userClient, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "logs", uuid.Nil.String()) + inv, root := clitest.New(t, "task", "logs", uuid.Nil.String()) inv.Stdout = &stdout clitest.SetupConfig(t, userClient, root) @@ -155,7 +155,7 @@ func Test_TaskLogs(t *testing.T) { client, task := setupCLITaskTest(ctx, t, fakeAgentAPITaskLogsErr(assert.AnError)) userClient := client - inv, root := clitest.New(t, "exp", "task", "logs", task.ID.String()) + inv, root := clitest.New(t, "task", "logs", task.ID.String()) clitest.SetupConfig(t, userClient, root) err := inv.WithContext(ctx).Run() diff --git a/cli/exp_task_send.go b/cli/task_send.go similarity index 90% rename from cli/exp_task_send.go rename to cli/task_send.go index e8985d55d9..7859fa1ddc 100644 --- a/cli/exp_task_send.go +++ b/cli/task_send.go @@ -17,10 +17,10 @@ func (r *RootCmd) taskSend() *serpent.Command { Short: "Send input to a task", Long: FormatExamples(Example{ Description: "Send direct input to a task.", - Command: "coder exp task send task1 \"Please also add unit tests\"", + Command: "coder task send task1 \"Please also add unit tests\"", }, Example{ Description: "Send input from stdin to a task.", - Command: "echo \"Please also add unit tests\" | coder exp task send task1 --stdin", + Command: "echo \"Please also add unit tests\" | coder task send task1 --stdin", }), Middleware: serpent.RequireRangeArgs(1, 2), Options: serpent.OptionSet{ diff --git a/cli/exp_task_send_test.go b/cli/task_send_test.go similarity index 90% rename from cli/exp_task_send_test.go rename to cli/task_send_test.go index 3529cf2e0b..e36fce443f 100644 --- a/cli/exp_task_send_test.go +++ b/cli/task_send_test.go @@ -30,7 +30,7 @@ func Test_TaskSend(t *testing.T) { userClient := client var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "send", task.Name, "carry on with the task") + inv, root := clitest.New(t, "task", "send", task.Name, "carry on with the task") inv.Stdout = &stdout clitest.SetupConfig(t, userClient, root) @@ -46,7 +46,7 @@ func Test_TaskSend(t *testing.T) { userClient := client var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "send", task.ID.String(), "carry on with the task") + inv, root := clitest.New(t, "task", "send", task.ID.String(), "carry on with the task") inv.Stdout = &stdout clitest.SetupConfig(t, userClient, root) @@ -62,7 +62,7 @@ func Test_TaskSend(t *testing.T) { userClient := client var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "send", task.Name, "--stdin") + inv, root := clitest.New(t, "task", "send", task.Name, "--stdin") inv.Stdout = &stdout inv.Stdin = strings.NewReader("carry on with the task") clitest.SetupConfig(t, userClient, root) @@ -80,7 +80,7 @@ func Test_TaskSend(t *testing.T) { userClient, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "send", "doesnotexist", "some task input") + inv, root := clitest.New(t, "task", "send", "doesnotexist", "some task input") inv.Stdout = &stdout clitest.SetupConfig(t, userClient, root) @@ -98,7 +98,7 @@ func Test_TaskSend(t *testing.T) { userClient, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "send", uuid.Nil.String(), "some task input") + inv, root := clitest.New(t, "task", "send", uuid.Nil.String(), "some task input") inv.Stdout = &stdout clitest.SetupConfig(t, userClient, root) @@ -114,7 +114,7 @@ func Test_TaskSend(t *testing.T) { userClient, task := setupCLITaskTest(ctx, t, fakeAgentAPITaskSendErr(t, assert.AnError)) var stdout strings.Builder - inv, root := clitest.New(t, "exp", "task", "send", task.Name, "some task input") + inv, root := clitest.New(t, "task", "send", task.Name, "some task input") inv.Stdout = &stdout clitest.SetupConfig(t, userClient, root) diff --git a/cli/exp_task_status.go b/cli/task_status.go similarity index 97% rename from cli/exp_task_status.go rename to cli/task_status.go index 1bd77f5f7f..9d97485c51 100644 --- a/cli/exp_task_status.go +++ b/cli/task_status.go @@ -47,11 +47,11 @@ func (r *RootCmd) taskStatus() *serpent.Command { Long: FormatExamples( Example{ Description: "Show the status of a given task.", - Command: "coder exp task status task1", + Command: "coder task status task1", }, Example{ Description: "Watch the status of a given task until it completes (idle or stopped).", - Command: "coder exp task status task1 --watch", + Command: "coder task status task1 --watch", }, ), Use: "status", diff --git a/cli/exp_task_status_test.go b/cli/task_status_test.go similarity index 99% rename from cli/exp_task_status_test.go rename to cli/task_status_test.go index 41102c8710..b19045fa2d 100644 --- a/cli/exp_task_status_test.go +++ b/cli/task_status_test.go @@ -256,7 +256,7 @@ func Test_TaskStatus(t *testing.T) { srv = httptest.NewServer(http.HandlerFunc(tc.hf(ctx, now))) client = codersdk.New(testutil.MustURL(t, srv.URL)) sb = strings.Builder{} - args = []string{"exp", "task", "status", "--watch-interval", testutil.IntervalFast.String()} + args = []string{"task", "status", "--watch-interval", testutil.IntervalFast.String()} ) t.Cleanup(srv.Close) diff --git a/cli/exp_task_test.go b/cli/task_test.go similarity index 96% rename from cli/exp_task_test.go rename to cli/task_test.go index f794e3a077..84097f01e7 100644 --- a/cli/exp_task_test.go +++ b/cli/task_test.go @@ -60,14 +60,14 @@ func Test_Tasks(t *testing.T) { }{ { name: "create task", - cmdArgs: []string{"exp", "task", "create", "test task input for " + t.Name(), "--name", taskName, "--template", taskTpl.Name}, + cmdArgs: []string{"task", "create", "test task input for " + t.Name(), "--name", taskName, "--template", taskTpl.Name}, assertFn: func(stdout string, userClient *codersdk.Client) { require.Contains(t, stdout, taskName, "task name should be in output") }, }, { name: "list tasks after create", - cmdArgs: []string{"exp", "task", "list", "--output", "json"}, + cmdArgs: []string{"task", "list", "--output", "json"}, assertFn: func(stdout string, userClient *codersdk.Client) { var tasks []codersdk.Task err := json.NewDecoder(strings.NewReader(stdout)).Decode(&tasks) @@ -88,7 +88,7 @@ func Test_Tasks(t *testing.T) { }, { name: "get task status after create", - cmdArgs: []string{"exp", "task", "status", taskName, "--output", "json"}, + cmdArgs: []string{"task", "status", taskName, "--output", "json"}, assertFn: func(stdout string, userClient *codersdk.Client) { var task codersdk.Task require.NoError(t, json.NewDecoder(strings.NewReader(stdout)).Decode(&task), "should unmarshal task status") @@ -98,12 +98,12 @@ func Test_Tasks(t *testing.T) { }, { name: "send task message", - cmdArgs: []string{"exp", "task", "send", taskName, "hello"}, + cmdArgs: []string{"task", "send", taskName, "hello"}, // Assertions for this happen in the fake agent API handler. }, { name: "read task logs", - cmdArgs: []string{"exp", "task", "logs", taskName, "--output", "json"}, + cmdArgs: []string{"task", "logs", taskName, "--output", "json"}, assertFn: func(stdout string, userClient *codersdk.Client) { var logs []codersdk.TaskLogEntry require.NoError(t, json.NewDecoder(strings.NewReader(stdout)).Decode(&logs), "should unmarshal task logs") @@ -118,7 +118,7 @@ func Test_Tasks(t *testing.T) { }, { name: "delete task", - cmdArgs: []string{"exp", "task", "delete", taskName, "--yes"}, + cmdArgs: []string{"task", "delete", taskName, "--yes"}, assertFn: func(stdout string, userClient *codersdk.Client) { // The task should eventually no longer show up in the list of tasks testutil.Eventually(ctx, t, func(ctx context.Context) bool { diff --git a/cli/testdata/coder_--help.golden b/cli/testdata/coder_--help.golden index e457aca857..1d6aa621fe 100644 --- a/cli/testdata/coder_--help.golden +++ b/cli/testdata/coder_--help.golden @@ -53,6 +53,7 @@ SUBCOMMANDS: stop Stop a workspace support Commands for troubleshooting issues with a Coder deployment. + task Manage tasks templates Manage templates tokens Manage personal access tokens unfavorite Remove a workspace from your favorites diff --git a/cli/testdata/coder_task_--help.golden b/cli/testdata/coder_task_--help.golden new file mode 100644 index 0000000000..c6fa004de0 --- /dev/null +++ b/cli/testdata/coder_task_--help.golden @@ -0,0 +1,19 @@ +coder v0.0.0-devel + +USAGE: + coder task + + Manage tasks + + Aliases: tasks + +SUBCOMMANDS: + create Create a task + delete Delete tasks + list List tasks + logs Show a task's logs + send Send input to a task + status Show the status of a task. + +——— +Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_task_create_--help.golden b/cli/testdata/coder_task_create_--help.golden new file mode 100644 index 0000000000..4bded64e67 --- /dev/null +++ b/cli/testdata/coder_task_create_--help.golden @@ -0,0 +1,51 @@ +coder v0.0.0-devel + +USAGE: + coder task create [flags] [input] + + Create a task + + - Create a task with direct input: + + $ coder task create "Add authentication to the user service" + + - Create a task with stdin input: + + $ echo "Add authentication to the user service" | coder task create + + - Create a task with a specific name: + + $ coder task create --name task1 "Add authentication to the user service" + + - Create a task from a specific template / preset: + + $ coder task create --template backend-dev --preset "My Preset" "Add + authentication to the user service" + + - Create a task for another user (requires appropriate permissions): + + $ coder task create --owner user@example.com "Add authentication to the + user service" + +OPTIONS: + -O, --org string, $CODER_ORGANIZATION + Select which organization (uuid or name) to use. + + --name string + Specify the name of the task. If you do not specify one, a name will + be generated for you. + + --owner string (default: me) + Specify the owner of the task. Defaults to the current user. + + --preset string, $CODER_TASK_PRESET_NAME (default: none) + -q, --quiet bool + Only display the created task's ID. + + --stdin bool + Reads from stdin for the task input. + + --template string, $CODER_TASK_TEMPLATE_NAME + --template-version string, $CODER_TASK_TEMPLATE_VERSION +——— +Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_task_delete_--help.golden b/cli/testdata/coder_task_delete_--help.golden new file mode 100644 index 0000000000..b0169410a9 --- /dev/null +++ b/cli/testdata/coder_task_delete_--help.golden @@ -0,0 +1,27 @@ +coder v0.0.0-devel + +USAGE: + coder task delete [flags] [ ...] + + Delete tasks + + Aliases: rm + + - Delete a single task.: + + $ $ coder task delete task1 + + - Delete multiple tasks.: + + $ $ coder task delete task1 task2 task3 + + - Delete a task without confirmation.: + + $ $ coder task delete task4 --yes + +OPTIONS: + -y, --yes bool + Bypass prompts. + +——— +Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_task_list_--help.golden b/cli/testdata/coder_task_list_--help.golden new file mode 100644 index 0000000000..8836e06544 --- /dev/null +++ b/cli/testdata/coder_task_list_--help.golden @@ -0,0 +1,50 @@ +coder v0.0.0-devel + +USAGE: + coder task list [flags] + + List tasks + + Aliases: ls + + - List tasks for the current user.: + + $ coder task list + + - List tasks for a specific user.: + + $ coder task list --user someone-else + + - List all tasks you can view.: + + $ coder task list --all + + - List all your running tasks.: + + $ coder task list --status running + + - As above, but only show IDs.: + + $ coder task list --status running --quiet + +OPTIONS: + -a, --all bool (default: false) + List tasks for all users you can view. + + -c, --column [id|organization id|owner id|owner name|owner avatar url|name|display name|template id|template version id|template name|template display name|template icon|workspace id|workspace name|workspace status|workspace build number|workspace agent id|workspace agent lifecycle|workspace agent health|workspace app id|initial prompt|status|state|message|created at|updated at|state changed] (default: name,status,state,state changed,message) + Columns to display in table output. + + -o, --output table|json (default: table) + Output format. + + -q, --quiet bool (default: false) + Only display task IDs. + + --status pending|initializing|active|paused|error|unknown + Filter by task status. + + --user string + List tasks for the specified user (username, "me"). + +——— +Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_task_logs_--help.golden b/cli/testdata/coder_task_logs_--help.golden new file mode 100644 index 0000000000..5175249b6d --- /dev/null +++ b/cli/testdata/coder_task_logs_--help.golden @@ -0,0 +1,20 @@ +coder v0.0.0-devel + +USAGE: + coder task logs [flags] + + Show a task's logs + + - Show logs for a given task.: + + $ coder task logs task1 + +OPTIONS: + -c, --column [id|content|type|time] (default: type,content) + Columns to display in table output. + + -o, --output table|json (default: table) + Output format. + +——— +Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_task_send_--help.golden b/cli/testdata/coder_task_send_--help.golden new file mode 100644 index 0000000000..d0966008b4 --- /dev/null +++ b/cli/testdata/coder_task_send_--help.golden @@ -0,0 +1,21 @@ +coder v0.0.0-devel + +USAGE: + coder task send [flags] [ | --stdin] + + Send input to a task + + - Send direct input to a task.: + + $ coder task send task1 "Please also add unit tests" + + - Send input from stdin to a task.: + + $ echo "Please also add unit tests" | coder task send task1 --stdin + +OPTIONS: + --stdin bool + Reads the input from stdin. + +——— +Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_task_status_--help.golden b/cli/testdata/coder_task_status_--help.golden new file mode 100644 index 0000000000..f1a1ed6238 --- /dev/null +++ b/cli/testdata/coder_task_status_--help.golden @@ -0,0 +1,30 @@ +coder v0.0.0-devel + +USAGE: + coder task status [flags] + + Show the status of a task. + + Aliases: stat + + - Show the status of a given task.: + + $ coder task status task1 + + - Watch the status of a given task until it completes (idle or stopped).: + + $ coder task status task1 --watch + +OPTIONS: + -c, --column [id|organization id|owner id|owner name|owner avatar url|name|display name|template id|template version id|template name|template display name|template icon|workspace id|workspace name|workspace status|workspace build number|workspace agent id|workspace agent lifecycle|workspace agent health|workspace app id|initial prompt|status|state|message|created at|updated at|state changed|healthy] (default: state changed,status,healthy,state,message) + Columns to display in table output. + + -o, --output table|json (default: table) + Output format. + + --watch bool (default: false) + Watch the task status output. This will stream updates to the terminal + until the underlying workspace is stopped. + +——— +Run `coder --help` for a list of global options. diff --git a/docs/ai-coder/cli.md b/docs/ai-coder/cli.md index 6d337b458d..2e56a76cf4 100644 --- a/docs/ai-coder/cli.md +++ b/docs/ai-coder/cli.md @@ -1,230 +1,13 @@ # Tasks CLI -The Coder CLI provides experimental commands for managing tasks programmatically. These are available under `coder exp task`: +The Tasks CLI documentation has moved to the auto-generated CLI reference pages: -```console -USAGE: - coder exp task +- [task](../reference/cli/task.md) - Main tasks command +- [task create](../reference/cli/task_create.md) - Create a task +- [task delete](../reference/cli/task_delete.md) - Delete tasks +- [task list](../reference/cli/task_list.md) - List tasks +- [task logs](../reference/cli/task_logs.md) - Show task logs +- [task send](../reference/cli/task_send.md) - Send input to a task +- [task status](../reference/cli/task_status.md) - Show task status - Experimental task commands. - - Aliases: tasks - -SUBCOMMANDS: - create Create an experimental task - delete Delete experimental tasks - list List experimental tasks - logs Show a task's logs - send Send input to a task - status Show the status of a task. -``` - -## Creating tasks - -```console -USAGE: - coder exp task create [flags] [input] - - Create an experimental task - - - Create a task with direct input: - - $ coder exp task create "Add authentication to the user service" - - - Create a task with stdin input: - - $ echo "Add authentication to the user service" | coder exp task create - - - Create a task with a specific name: - - $ coder exp task create --name task1 "Add authentication to the user service" - - - Create a task from a specific template / preset: - - $ coder exp task create --template backend-dev --preset "My Preset" "Add authentication to the user service" - - - Create a task for another user (requires appropriate permissions): - - $ coder exp task create --owner user@example.com "Add authentication to the user service" - -OPTIONS: - -O, --org string, $CODER_ORGANIZATION - Select which organization (uuid or name) to use. - - --name string - Specify the name of the task. If you do not specify one, a name will be generated for you. - - --owner string (default: me) - Specify the owner of the task. Defaults to the current user. - - --preset string, $CODER_TASK_PRESET_NAME (default: none) - -q, --quiet bool - Only display the created task's ID. - - --stdin bool - Reads from stdin for the task input. - - --template string, $CODER_TASK_TEMPLATE_NAME - --template-version string, $CODER_TASK_TEMPLATE_VERSION -``` - -## Deleting Tasks - -```console -USAGE: - coder exp task delete [flags] [ ...] - - Delete experimental tasks - - Aliases: rm - - - Delete a single task.: - - $ $ coder exp task delete task1 - - - Delete multiple tasks.: - - $ $ coder exp task delete task1 task2 task3 - - - Delete a task without confirmation.: - - $ $ coder exp task delete task4 --yes - -OPTIONS: - -y, --yes bool - Bypass prompts. -``` - -## Listing tasks - -```console -USAGE: - coder exp task list [flags] - - List experimental tasks - - Aliases: ls - - - List tasks for the current user.: - - $ coder exp task list - - - List tasks for a specific user.: - - $ coder exp task list --user someone-else - - - List all tasks you can view.: - - $ coder exp task list --all - - - List all your running tasks.: - - $ coder exp task list --status running - - - As above, but only show IDs.: - - $ coder exp task list --status running --quiet - -OPTIONS: - -a, --all bool (default: false) - List tasks for all users you can view. - - -c, --column [id|organization id|owner id|owner name|name|template id|template name|template display name|template icon|workspace id|workspace agent id|workspace agent lifecycle|workspace agent health|initial prompt|status|state|message|created at|updated at|state changed] (default: name,status,state,state changed,message) - Columns to display in table output. - - -o, --output table|json (default: table) - Output format. - - -q, --quiet bool (default: false) - Only display task IDs. - - --status string - Filter by task status (e.g. running, failed, etc). - - --user string - List tasks for the specified user (username, "me"). -``` - -## Viewing Task Logs - -```console -USAGE: - coder exp task logs [flags] - - Show a task's logs - - - Show logs for a given task.: - - $ coder exp task logs task1 - -OPTIONS: - -c, --column [id|content|type|time] (default: type,content) - Columns to display in table output. - - -o, --output table|json (default: table) - Output format. -``` - -## Sending input to a task - -```console -USAGE: - coder exp task send [flags] [ | --stdin] - - Send input to a task - - - Send direct input to a task.: - - $ coder exp task send task1 "Please also add unit tests" - - - Send input from stdin to a task.: - - $ echo "Please also add unit tests" | coder exp task send task1 --stdin - -OPTIONS: - --stdin bool - Reads the input from stdin. -``` - -## Viewing Task Status - -```console -USAGE: - coder exp task status [flags] - - Show the status of a task. - - Aliases: stat - - - Show the status of a given task.: - - $ coder exp task status task1 - - - Watch the status of a given task until it completes (idle or stopped).: - - $ coder exp task status task1 --watch - -OPTIONS: - -c, --column [state changed|status|healthy|state|message] (default: state changed,status,healthy,state,message) - Columns to display in table output. - - -o, --output table|json (default: table) - Output format. - - --watch bool (default: false) - Watch the task status output. This will stream updates to the terminal until the underlying workspace is stopped. -``` - -> **Note**: The `--watch` flag will automatically exit when the task reaches a terminal state. Watch mode ends when: -> -> - The workspace is stopped -> - The workspace agent becomes unhealthy or is shutting down -> - The task completes (reaches a non-working state like completed, failed, or canceled) - -## Identifying Tasks - -Tasks can be identified in CLI commands using either: - -- **Task Name**: The human-readable name (e.g., `my-task-name`) - > Note: Tasks owned by other users can be identified by their owner and name (e.g., `alice/her-task`). -- **Task ID**: The UUID identifier (e.g., `550e8400-e29b-41d4-a716-446655440000`) +For the complete CLI reference, see the [CLI documentation](../reference/cli/index.md). diff --git a/docs/manifest.json b/docs/manifest.json index eb44a17b84..d4fda8da60 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1771,6 +1771,41 @@ "description": "Generate a support bundle to troubleshoot issues connecting to a workspace.", "path": "reference/cli/support_bundle.md" }, + { + "title": "task", + "description": "Manage tasks", + "path": "reference/cli/task.md" + }, + { + "title": "task create", + "description": "Create a task", + "path": "reference/cli/task_create.md" + }, + { + "title": "task delete", + "description": "Delete tasks", + "path": "reference/cli/task_delete.md" + }, + { + "title": "task list", + "description": "List tasks", + "path": "reference/cli/task_list.md" + }, + { + "title": "task logs", + "description": "Show a task's logs", + "path": "reference/cli/task_logs.md" + }, + { + "title": "task send", + "description": "Send input to a task", + "path": "reference/cli/task_send.md" + }, + { + "title": "task status", + "description": "Show the status of a task.", + "path": "reference/cli/task_status.md" + }, { "title": "templates", "description": "Manage templates", diff --git a/docs/reference/cli/index.md b/docs/reference/cli/index.md index 958e475fea..6a3ec16c9c 100644 --- a/docs/reference/cli/index.md +++ b/docs/reference/cli/index.md @@ -36,6 +36,7 @@ Coder — A tool for provisioning self-hosted development environments with Terr | [publickey](./publickey.md) | Output your Coder public key used for Git operations | | [reset-password](./reset-password.md) | Directly connect to the database to reset a user's password | | [state](./state.md) | Manually manage Terraform state to fix broken workspaces | +| [task](./task.md) | Manage tasks | | [templates](./templates.md) | Manage templates | | [tokens](./tokens.md) | Manage personal access tokens | | [users](./users.md) | Manage users | diff --git a/docs/reference/cli/task.md b/docs/reference/cli/task.md new file mode 100644 index 0000000000..9f70c9c4d5 --- /dev/null +++ b/docs/reference/cli/task.md @@ -0,0 +1,25 @@ + +# task + +Manage tasks + +Aliases: + +* tasks + +## Usage + +```console +coder task +``` + +## Subcommands + +| Name | Purpose | +|-----------------------------------------|----------------------------| +| [create](./task_create.md) | Create a task | +| [delete](./task_delete.md) | Delete tasks | +| [list](./task_list.md) | List tasks | +| [logs](./task_logs.md) | Show a task's logs | +| [send](./task_send.md) | Send input to a task | +| [status](./task_status.md) | Show the status of a task. | diff --git a/docs/reference/cli/task_create.md b/docs/reference/cli/task_create.md new file mode 100644 index 0000000000..726c805469 --- /dev/null +++ b/docs/reference/cli/task_create.md @@ -0,0 +1,100 @@ + +# task create + +Create a task + +## Usage + +```console +coder task create [flags] [input] +``` + +## Description + +```console + - Create a task with direct input: + + $ coder task create "Add authentication to the user service" + + - Create a task with stdin input: + + $ echo "Add authentication to the user service" | coder task create + + - Create a task with a specific name: + + $ coder task create --name task1 "Add authentication to the user service" + + - Create a task from a specific template / preset: + + $ coder task create --template backend-dev --preset "My Preset" "Add authentication to the user service" + + - Create a task for another user (requires appropriate permissions): + + $ coder task create --owner user@example.com "Add authentication to the user service" +``` + +## Options + +### --name + +| | | +|------|---------------------| +| Type | string | + +Specify the name of the task. If you do not specify one, a name will be generated for you. + +### --owner + +| | | +|---------|---------------------| +| Type | string | +| Default | me | + +Specify the owner of the task. Defaults to the current user. + +### --template + +| | | +|-------------|----------------------------------------| +| Type | string | +| Environment | $CODER_TASK_TEMPLATE_NAME | + +### --template-version + +| | | +|-------------|-------------------------------------------| +| Type | string | +| Environment | $CODER_TASK_TEMPLATE_VERSION | + +### --preset + +| | | +|-------------|--------------------------------------| +| Type | string | +| Environment | $CODER_TASK_PRESET_NAME | +| Default | none | + +### --stdin + +| | | +|------|-------------------| +| Type | bool | + +Reads from stdin for the task input. + +### -q, --quiet + +| | | +|------|-------------------| +| Type | bool | + +Only display the created task's ID. + +### -O, --org + +| | | +|-------------|----------------------------------| +| Type | string | +| Environment | $CODER_ORGANIZATION | + +Select which organization (uuid or name) to use. diff --git a/docs/reference/cli/task_delete.md b/docs/reference/cli/task_delete.md new file mode 100644 index 0000000000..0181ee0cea --- /dev/null +++ b/docs/reference/cli/task_delete.md @@ -0,0 +1,40 @@ + +# task delete + +Delete tasks + +Aliases: + +* rm + +## Usage + +```console +coder task delete [flags] [ ...] +``` + +## Description + +```console + - Delete a single task.: + + $ $ coder task delete task1 + + - Delete multiple tasks.: + + $ $ coder task delete task1 task2 task3 + + - Delete a task without confirmation.: + + $ $ coder task delete task4 --yes +``` + +## Options + +### -y, --yes + +| | | +|------|-------------------| +| Type | bool | + +Bypass prompts. diff --git a/docs/reference/cli/task_list.md b/docs/reference/cli/task_list.md new file mode 100644 index 0000000000..1a9335f65f --- /dev/null +++ b/docs/reference/cli/task_list.md @@ -0,0 +1,92 @@ + +# task list + +List tasks + +Aliases: + +* ls + +## Usage + +```console +coder task list [flags] +``` + +## Description + +```console + - List tasks for the current user.: + + $ coder task list + + - List tasks for a specific user.: + + $ coder task list --user someone-else + + - List all tasks you can view.: + + $ coder task list --all + + - List all your running tasks.: + + $ coder task list --status running + + - As above, but only show IDs.: + + $ coder task list --status running --quiet +``` + +## Options + +### --status + +| | | +|------|--------------------------------------------------------------------| +| Type | pending\|initializing\|active\|paused\|error\|unknown | + +Filter by task status. + +### -a, --all + +| | | +|---------|--------------------| +| Type | bool | +| Default | false | + +List tasks for all users you can view. + +### --user + +| | | +|------|---------------------| +| Type | string | + +List tasks for the specified user (username, "me"). + +### -q, --quiet + +| | | +|---------|--------------------| +| Type | bool | +| Default | false | + +Only display task IDs. + +### -c, --column + +| | | +|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Type | [id\|organization id\|owner id\|owner name\|owner avatar url\|name\|display name\|template id\|template version id\|template name\|template display name\|template icon\|workspace id\|workspace name\|workspace status\|workspace build number\|workspace agent id\|workspace agent lifecycle\|workspace agent health\|workspace app id\|initial prompt\|status\|state\|message\|created at\|updated at\|state changed] | +| Default | name,status,state,state changed,message | + +Columns to display in table output. + +### -o, --output + +| | | +|---------|--------------------------| +| Type | table\|json | +| Default | table | + +Output format. diff --git a/docs/reference/cli/task_logs.md b/docs/reference/cli/task_logs.md new file mode 100644 index 0000000000..d7e4b0eda6 --- /dev/null +++ b/docs/reference/cli/task_logs.md @@ -0,0 +1,38 @@ + +# task logs + +Show a task's logs + +## Usage + +```console +coder task logs [flags] +``` + +## Description + +```console + - Show logs for a given task.: + + $ coder task logs task1 +``` + +## Options + +### -c, --column + +| | | +|---------|----------------------------------------| +| Type | [id\|content\|type\|time] | +| Default | type,content | + +Columns to display in table output. + +### -o, --output + +| | | +|---------|--------------------------| +| Type | table\|json | +| Default | table | + +Output format. diff --git a/docs/reference/cli/task_send.md b/docs/reference/cli/task_send.md new file mode 100644 index 0000000000..0ad847a441 --- /dev/null +++ b/docs/reference/cli/task_send.md @@ -0,0 +1,32 @@ + +# task send + +Send input to a task + +## Usage + +```console +coder task send [flags] [ | --stdin] +``` + +## Description + +```console + - Send direct input to a task.: + + $ coder task send task1 "Please also add unit tests" + + - Send input from stdin to a task.: + + $ echo "Please also add unit tests" | coder task send task1 --stdin +``` + +## Options + +### --stdin + +| | | +|------|-------------------| +| Type | bool | + +Reads the input from stdin. diff --git a/docs/reference/cli/task_status.md b/docs/reference/cli/task_status.md new file mode 100644 index 0000000000..4a167a249f --- /dev/null +++ b/docs/reference/cli/task_status.md @@ -0,0 +1,55 @@ + +# task status + +Show the status of a task. + +Aliases: + +* stat + +## Usage + +```console +coder task status [flags] +``` + +## Description + +```console + - Show the status of a given task.: + + $ coder task status task1 + + - Watch the status of a given task until it completes (idle or stopped).: + + $ coder task status task1 --watch +``` + +## Options + +### --watch + +| | | +|---------|--------------------| +| Type | bool | +| Default | false | + +Watch the task status output. This will stream updates to the terminal until the underlying workspace is stopped. + +### -c, --column + +| | | +|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Type | [id\|organization id\|owner id\|owner name\|owner avatar url\|name\|display name\|template id\|template version id\|template name\|template display name\|template icon\|workspace id\|workspace name\|workspace status\|workspace build number\|workspace agent id\|workspace agent lifecycle\|workspace agent health\|workspace app id\|initial prompt\|status\|state\|message\|created at\|updated at\|state changed\|healthy] | +| Default | state changed,status,healthy,state,message | + +Columns to display in table output. + +### -o, --output + +| | | +|---------|--------------------------| +| Type | table\|json | +| Default | table | + +Output format.