cli: make bundled help self-describing

This commit is contained in:
2026-03-22 23:37:38 +08:00
parent 5859ff219e
commit 4d8c90eb26
49 changed files with 792 additions and 29 deletions
@@ -23,6 +23,13 @@ func newAnswerCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "answer",
Short: "Answer the active blocked question for a task",
Long: helpLong(
"Use answer to write one response back into the active blocked attempt thread for a task.",
"Use body for human-readable guidance, payload-json for structured decisions, or both when workers need a stable machine-readable contract.",
"answer targets the current active blocked attempt for the task; it is not a generic freeform message append.",
),
Example: ` orch --db .agents/coord.db answer --run blog_mvp_001 --task T2 --body "Use stdout for MVP."
orch --db .agents/coord.db answer --run blog_mvp_001 --task T2 --payload-json '{"decision":"stdout","source":"leader"}'`,
RunE: func(cmd *cobra.Command, args []string) error {
body, err := resolveBodyValue(opts.body, opts.bodyFile)
if err != nil {
@@ -19,6 +19,12 @@ func newBlockedCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "blocked",
Short: "List blocked tasks and their latest question",
Long: helpLong(
"Use blocked to list tasks whose active attempt is blocked together with the latest question the leader needs to answer.",
"Use blocked before answer when you want a compact queue of unresolved worker questions instead of the full run view from status.",
),
Example: ` orch --db .agents/coord.db blocked --run blog_mvp_001
orch --db .agents/coord.db --json blocked --run blog_mvp_001`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -21,6 +21,13 @@ func newCancelCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "cancel",
Short: "Cancel a task or an entire run",
Long: helpLong(
"Use cancel to stop one task or an entire run.",
"Pass --task when you want to cancel one task inside the run; omit it when you want to cancel the whole run.",
"Use a reason when later readers need to understand why the work was stopped.",
),
Example: ` orch --db .agents/coord.db cancel --run blog_mvp_001 --task T3 --reason "Superseded by a new plan."
orch --db .agents/coord.db cancel --run blog_mvp_001 --reason "User cancelled the entire request."`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -23,6 +23,16 @@ func newCleanupCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "cleanup",
Short: "Remove completed or abandoned attempt worktrees",
Long: helpLong(
"Use cleanup to remove worktrees that belong to completed, abandoned, or explicitly forced attempt cleanup.",
"cleanup only affects attempts that actually have worktree-backed execution state; analysis-mode attempts have no worktree to remove.",
"Pass --task when you want to clean one task's latest cleanup candidate.",
"Pass --task plus --attempt when you want one exact attempt.",
"Pass --all-completed when you want a run-wide cleanup sweep.",
),
Example: ` orch --db .agents/coord.db cleanup --run blog_mvp_001 --task T1
orch --db .agents/coord.db cleanup --run blog_mvp_001 --task T1 --attempt 2
orch --db .agents/coord.db cleanup --run blog_mvp_001 --all-completed`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -74,9 +84,9 @@ func newCleanupCmd(root *rootOptions) *cobra.Command {
}
cmd.Flags().StringVar(&opts.runID, "run", "", "Run ID")
cmd.Flags().StringVar(&opts.taskID, "task", "", "Optional task ID")
cmd.Flags().IntVar(&opts.attemptNo, "attempt", 0, "Specific attempt number")
cmd.Flags().BoolVar(&opts.allCompleted, "all-completed", false, "Clean all completed or abandoned worktrees in the run")
cmd.Flags().StringVar(&opts.taskID, "task", "", "Limit cleanup candidates to one task")
cmd.Flags().IntVar(&opts.attemptNo, "attempt", 0, "Limit cleanup to one specific attempt number")
cmd.Flags().BoolVar(&opts.allCompleted, "all-completed", false, "Clean every completed or abandoned worktree in the run")
cmd.Flags().BoolVar(&opts.force, "force", false, "Force cleanup even for non-terminal worktrees")
_ = cmd.MarkFlagRequired("run")
@@ -6,6 +6,14 @@ func newCouncilCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "council",
Short: "Council review workflow commands",
Long: helpLong(
"Use council commands for the three-reviewer analysis workflow built on top of orch runs, tasks, and inbox threads.",
"council is analysis-oriented and is meant for grouped review output rather than direct code-writing execution.",
),
Example: ` orch --db .agents/coord.db council start --run council_blog_001 --target "Review the current architecture."
orch --db .agents/coord.db council wait --run council_blog_001 --timeout-seconds 600
orch --db .agents/coord.db council tally --run council_blog_001
orch --db .agents/coord.db council report --run council_blog_001`,
}
cmd.AddCommand(newCouncilStartCmd(root))
@@ -23,6 +23,12 @@ func newCouncilReportCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "report",
Short: "Render the final grouped council output",
Long: helpLong(
"Use council report to render the final council output from previously tallied grouped recommendations and persist the markdown artifact on disk.",
"Run report after tally so the grouped recommendations and vote buckets are already available.",
),
Example: ` orch --db .agents/coord.db council report --run council_blog_001
orch --db .agents/coord.db council report --run council_blog_001 --show consensus,majority`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -27,6 +27,12 @@ func newCouncilStartCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "start",
Short: "Create and dispatch a three-reviewer council run",
Long: helpLong(
"Use council start to create one three-reviewer council run and immediately dispatch the fixed reviewer tasks.",
"This is analysis-oriented workflow setup on top of orch.",
"The result is a normal run with reviewer tasks that later feed council wait, tally, and report.",
),
Example: ` orch --db .agents/coord.db council start --run council_blog_001 --target "Review the current blog architecture." --target-type mixed --output both`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -20,6 +20,11 @@ func newCouncilTallyCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "tally",
Short: "Group reviewer findings and compute council support counts",
Long: helpLong(
"Use council tally to read reviewer outputs, group similar proposals, and compute support counts such as consensus, majority, and minority.",
"Run tally after reviewer completion and before rendering the final report.",
),
Example: ` orch --db .agents/coord.db council tally --run council_blog_001 --similarity normal`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -21,6 +21,11 @@ func newCouncilWaitCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "wait",
Short: "Block until all council reviewers complete or timeout is reached",
Long: helpLong(
"Use council wait to block until all reviewer tasks in one council run have completed or the timeout is reached.",
"Use this after council start instead of polling reviewer task state manually.",
),
Example: ` orch --db .agents/coord.db council wait --run council_blog_001 --timeout-seconds 900`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
+13 -3
View File
@@ -10,15 +10,20 @@ import (
)
type depAddOptions struct {
runID string
taskID string
dependsOn string
runID string
taskID string
dependsOn string
}
func newDepCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "dep",
Short: "Task dependency commands",
Long: helpLong(
"Use dep commands to gate one task on another task's completion.",
"Dependencies affect the ready queue; they do not themselves launch or cancel work.",
),
Example: ` orch --db .agents/coord.db dep add --run blog_mvp_001 --task T2 --depends-on T1`,
}
cmd.AddCommand(newDepAddCmd(root))
@@ -31,6 +36,11 @@ func newDepAddCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "add",
Short: "Add a dependency edge to a task",
Long: helpLong(
"Use dep add to make one task wait for another task to finish before it becomes ready.",
"The dependency target and dependent task must already exist in the same run.",
),
Example: ` orch --db .agents/coord.db dep add --run blog_mvp_001 --task frontend --depends-on backend`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -27,6 +27,16 @@ func newDispatchCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "dispatch",
Short: "Dispatch a ready task to a worker through inbox",
Long: helpLong(
"Use dispatch to turn one ready task into a concrete attempt and inbox thread.",
"You must choose exactly one execution mode.",
"analysis: create the attempt and thread only; do not allocate a worktree.",
"code: allocate a Git worktree for the attempt and record workspace metadata.",
"repo-path, workspace-root, and base-ref only apply to execution-mode code.",
"dispatch creates handoff state only; a separate worker runtime or worker agent must still claim the assigned inbox thread.",
),
Example: ` orch --db .agents/coord.db dispatch --run blog_mvp_001 --task T1 --execution-mode analysis --to qa-worker --body "Summarize the latest failures."
orch --db .agents/coord.db dispatch --run blog_mvp_001 --task T2 --execution-mode code --to backend-worker --repo-path /path/to/repo --workspace-root .orch/worktrees --base-ref main --body-file ./tasks/t2.md`,
RunE: func(cmd *cobra.Command, args []string) error {
normalizedOpts, err := normalizeDispatchOptions(*opts)
if err != nil {
@@ -0,0 +1,24 @@
package orch
import "strings"
func helpLong(purpose string, constraints ...string) string {
var builder strings.Builder
builder.WriteString(strings.TrimSpace(purpose))
if len(constraints) == 0 {
return builder.String()
}
builder.WriteString("\n\nConstraints:\n")
for _, constraint := range constraints {
constraint = strings.TrimSpace(constraint)
if constraint == "" {
continue
}
builder.WriteString("- ")
builder.WriteString(constraint)
builder.WriteByte('\n')
}
return strings.TrimRight(builder.String(), "\n")
}
@@ -0,0 +1,100 @@
package orch
import (
"strings"
"testing"
)
func TestOrchRootHelpExplainsLeaderWorkflow(t *testing.T) {
t.Parallel()
stdout, stderr, exitCode := executeOrchCommand("--help")
if exitCode != 0 {
t.Fatalf("expected help exit 0, got %d\nstderr:\n%s\nstdout:\n%s", exitCode, stderr, stdout)
}
combined := stdout + stderr
if !strings.Contains(combined, "orch is the control plane") {
t.Fatalf("expected root help to explain control-plane role, got:\n%s", combined)
}
if !strings.Contains(combined, "Constraints:") {
t.Fatalf("expected root help to include constraints section, got:\n%s", combined)
}
if !strings.Contains(combined, "dispatch --run blog_mvp_001 --task T1 --execution-mode analysis") {
t.Fatalf("expected root help to include execution-mode example, got:\n%s", combined)
}
}
func TestOrchDispatchHelpExplainsExecutionModes(t *testing.T) {
t.Parallel()
stdout, stderr, exitCode := executeOrchCommand("dispatch", "--help")
if exitCode != 0 {
t.Fatalf("expected help exit 0, got %d\nstderr:\n%s\nstdout:\n%s", exitCode, stderr, stdout)
}
combined := stdout + stderr
if !strings.Contains(combined, "analysis: create the attempt and thread only") {
t.Fatalf("expected dispatch help to explain analysis mode, got:\n%s", combined)
}
if !strings.Contains(combined, "Constraints:") {
t.Fatalf("expected dispatch help to include constraints section, got:\n%s", combined)
}
if !strings.Contains(combined, "repo-path, workspace-root, and base-ref only apply to execution-mode code") {
t.Fatalf("expected dispatch help to explain code-only flags, got:\n%s", combined)
}
}
func TestOrchCouncilStartHelpExplainsWorkflow(t *testing.T) {
t.Parallel()
stdout, stderr, exitCode := executeOrchCommand("council", "start", "--help")
if exitCode != 0 {
t.Fatalf("expected help exit 0, got %d\nstderr:\n%s\nstdout:\n%s", exitCode, stderr, stdout)
}
combined := stdout + stderr
if !strings.Contains(combined, "three-reviewer council run") {
t.Fatalf("expected council start help to explain purpose, got:\n%s", combined)
}
if !strings.Contains(combined, `--target "Review the current blog architecture."`) {
t.Fatalf("expected council start help to include an example, got:\n%s", combined)
}
}
func TestOrchStatusHelpExplainsDashboardRole(t *testing.T) {
t.Parallel()
stdout, stderr, exitCode := executeOrchCommand("status", "--help")
if exitCode != 0 {
t.Fatalf("expected help exit 0, got %d\nstderr:\n%s\nstdout:\n%s", exitCode, stderr, stdout)
}
combined := stdout + stderr
if !strings.Contains(combined, "main leader dashboard command") {
t.Fatalf("expected status help to explain dashboard role, got:\n%s", combined)
}
if !strings.Contains(combined, "Constraints:") {
t.Fatalf("expected status help to include constraints section, got:\n%s", combined)
}
}
func TestOrchCleanupHelpExplainsScopeFlags(t *testing.T) {
t.Parallel()
stdout, stderr, exitCode := executeOrchCommand("cleanup", "--help")
if exitCode != 0 {
t.Fatalf("expected help exit 0, got %d\nstderr:\n%s\nstdout:\n%s", exitCode, stderr, stdout)
}
combined := stdout + stderr
if !strings.Contains(strings.ToLower(combined), "pass --task plus --attempt when you want one exact attempt") {
t.Fatalf("expected cleanup help to explain scope flags, got:\n%s", combined)
}
if !strings.Contains(combined, "Constraints:") {
t.Fatalf("expected cleanup help to include constraints section, got:\n%s", combined)
}
if !strings.Contains(combined, "--task T1 --attempt 2") {
t.Fatalf("expected cleanup help to include exact-attempt example, got:\n%s", combined)
}
}
@@ -20,6 +20,12 @@ func newReadyCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "ready",
Short: "List tasks that are ready for dispatch",
Long: helpLong(
"Use ready to list tasks whose dependencies are already satisfied and can be dispatched now.",
"ready is a queue-inspection command only; it does not create attempts or threads.",
),
Example: ` orch --db .agents/coord.db ready --run blog_mvp_001
orch --db .agents/coord.db ready --run blog_mvp_001 --limit 5`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -22,6 +22,12 @@ func newReassignCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "reassign",
Short: "Reassign a blocked or failed task to another worker",
Long: helpLong(
"Use reassign to cancel the current active attempt and create a new attempt for another worker.",
"Like retry, reassign preserves the prior execution contract: analysis attempts stay analysis-only, and code attempts receive a fresh worktree.",
"Use reassign when the worker target should change, not just when the same worker should try again.",
),
Example: ` orch --db .agents/coord.db reassign --run blog_mvp_001 --task T3 --to worker-b --reason "Worker-a is blocked on a missing dependency."`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -19,6 +19,12 @@ func newReconcileCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "reconcile",
Short: "Reconcile inbox thread state back into orch task state",
Long: helpLong(
"Use reconcile to fold inbox thread state back into orch task and run state.",
"reconcile is the bridge from worker-side inbox activity to leader-side scheduler state.",
"Call reconcile before making new dispatch, retry, or status decisions when you need fresh state.",
),
Example: ` orch --db .agents/coord.db reconcile --run blog_mvp_001`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -23,6 +23,12 @@ func newRetryCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "retry",
Short: "Retry a failed task by creating a new attempt",
Long: helpLong(
"Use retry to create a fresh attempt and inbox thread for one failed task.",
"If the previous attempt used a worktree, retry provisions a new worktree from the recorded workspace contract.",
"If the previous attempt was analysis-only, retry stays analysis-only.",
),
Example: ` orch --db .agents/coord.db retry --run blog_mvp_001 --task T7 --to backend-worker --body "Retry after fixing the contract mismatch."`,
RunE: func(cmd *cobra.Command, args []string) error {
body, err := resolveBodyValue(opts.body, opts.bodyFile)
if err != nil {
@@ -13,8 +13,19 @@ func NewRootCmd() *cobra.Command {
opts := &rootOptions{}
cmd := &cobra.Command{
Use: "orch",
Short: "Leader-facing scheduler and control plane",
Use: "orch",
Short: "Leader-facing scheduler and control plane",
Long: helpLong(
"Use orch to manage leader-side scheduling for runs, tasks, dependencies, dispatch, retries, reassignment, blocked-task answers, and worktree-backed code attempts.",
"orch is the control plane; it creates durable handoff state in inbox but does not launch workers by itself.",
"After dispatch, a separate worker runtime or worker agent should claim the assigned inbox thread.",
"Use execution-mode analysis for thread-only work and execution-mode code for worktree-backed repository changes.",
),
Example: ` orch --db .agents/coord.db run init --run blog_mvp_001 --goal "Build blog MVP"
orch --db .agents/coord.db task add --run blog_mvp_001 --task T1 --title "Summarize flaky tests" --default-to qa-worker
orch --db .agents/coord.db ready --run blog_mvp_001
orch --db .agents/coord.db dispatch --run blog_mvp_001 --task T1 --execution-mode analysis --to qa-worker --body "Read the latest failures."
orch --db .agents/coord.db status --run blog_mvp_001`,
SilenceErrors: true,
SilenceUsage: true,
}
@@ -23,6 +23,12 @@ func newRunCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "run",
Short: "Run management commands",
Long: helpLong(
"Use run commands to create or inspect one orchestration run.",
"A run is the durable container for tasks, dependencies, attempts, and events for one user request or project slice.",
),
Example: ` orch --db .agents/coord.db run init --run blog_mvp_001 --goal "Build blog MVP"
orch --db .agents/coord.db run show --run blog_mvp_001`,
}
cmd.AddCommand(newRunInitCmd(root))
@@ -37,6 +43,12 @@ func newRunInitCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "init",
Short: "Create a new orchestration run",
Long: helpLong(
"Use run init to create one durable run that will own tasks, dependencies, attempts, and events for a single user request or project slice.",
"run IDs should be stable within the database path and are later reused by every other orch command.",
"Create the run before adding tasks, dependencies, or dispatching work.",
),
Example: ` orch --db .agents/coord.db run init --run blog_mvp_001 --goal "Build blog MVP" --summary "Public blog plus admin CRUD"`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -86,6 +98,11 @@ func newRunShowCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "show",
Short: "Show run metadata and aggregate state",
Long: helpLong(
"Use run show to inspect the lightweight run view with run metadata and aggregate task counts.",
"Prefer status when you need the full task list and latest attempt/message context.",
),
Example: ` orch --db .agents/coord.db run show --run blog_mvp_001`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -19,6 +19,13 @@ func newStatusCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "status",
Short: "Show task state summary for the run",
Long: helpLong(
"Use status to show the full operational view for one run.",
"status reconciles inbox state first, then returns the run summary, aggregate task counts, the task list, and latest attempt/message context.",
"Use status as the main leader dashboard command. Prefer it over run show when you need the latest task-level execution picture before making the next dispatch, answer, retry, or cleanup decision.",
),
Example: ` orch --db .agents/coord.db status --run blog_mvp_001
orch --db .agents/coord.db --json status --run blog_mvp_001`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -23,6 +23,11 @@ func newTaskCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "task",
Short: "Task management commands",
Long: helpLong(
"Use task commands to define schedulable work inside one run.",
"Tasks should be small enough to inspect, dispatch, retry, and reconcile independently.",
),
Example: ` orch --db .agents/coord.db task add --run blog_mvp_001 --task T1 --title "Implement backend" --default-to backend-worker`,
}
cmd.AddCommand(newTaskAddCmd(root))
@@ -35,6 +40,12 @@ func newTaskAddCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "add",
Short: "Add a task to a run",
Long: helpLong(
"Use task add to register one schedulable task inside a run.",
"Tasks may include a default worker target, priority, and optional acceptance JSON that downstream tooling can inspect.",
"A task must belong to an existing run before it can become ready or be dispatched.",
),
Example: ` orch --db .agents/coord.db task add --run blog_mvp_001 --task T1 --title "Implement backend" --summary "Ship the first API slice" --default-to backend-worker --priority high`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -24,6 +24,12 @@ func newWaitCmd(root *rootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "wait",
Short: "Block until matching run-scoped task events become available",
Long: helpLong(
"Use wait as the leader-side blocking primitive.",
"Instead of polling with manual sleep loops, wait blocks until later matching task events exist for the run, such as ready, blocked, done, or failed.",
"Use --after-event when resuming from a known cursor so you do not reprocess earlier events.",
),
Example: ` orch --db .agents/coord.db wait --run blog_mvp_001 --for task_blocked,task_done --after-event 0 --timeout-seconds 900`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()