From 7c8fcbc6df1a3c1e49a2dc93e6a38784e87d79ce Mon Sep 17 00:00:00 2001 From: "Scion Agent (agent-scheduler-dev)" Date: Tue, 9 Jun 2026 17:47:07 +0000 Subject: [PATCH 1/2] feat: enable scheduler write commands in agent mode, remove dispatch_agent from CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add schedule.create, schedule.create-recurring, schedule.pause, schedule.resume, and schedule.delete to the agent-mode allowlist. Update tests to expect these commands as allowed. Remove dispatch_agent event type from the CLI create and create-recurring commands — the message-to-orchestrator pattern is the recommended approach for scheduled task dispatch. --- cmd/cli_mode.go | 5 +++++ cmd/cli_mode_test.go | 17 +++++++-------- cmd/schedule.go | 49 ++++++++++++-------------------------------- 3 files changed, 27 insertions(+), 44 deletions(-) diff --git a/cmd/cli_mode.go b/cmd/cli_mode.go index 901cc4974..c5ad0c4ff 100644 --- a/cmd/cli_mode.go +++ b/cmd/cli_mode.go @@ -55,6 +55,11 @@ var agentAllowed = map[string]bool{ "schedule.list": true, "schedule.get": true, "schedule.cancel": true, + "schedule.create": true, + "schedule.create-recurring": true, + "schedule.pause": true, + "schedule.resume": true, + "schedule.delete": true, "schedule.history": true, "shared-dir": true, "shared-dir.list": true, diff --git a/cmd/cli_mode_test.go b/cmd/cli_mode_test.go index 888a719ad..fe3234d17 100644 --- a/cmd/cli_mode_test.go +++ b/cmd/cli_mode_test.go @@ -283,7 +283,9 @@ func TestApplyModeRestrictions_Agent(t *testing.T) { "notifications.ack", "notifications.subscribe", "notifications.subscriptions", "notifications.unsubscribe", "notifications.update", "resume", - "schedule", "schedule.cancel", "schedule.get", "schedule.history", "schedule.list", + "schedule", "schedule.cancel", "schedule.create", "schedule.create-recurring", + "schedule.delete", "schedule.get", "schedule.history", "schedule.list", + "schedule.pause", "schedule.resume", "shared-dir", "shared-dir.info", "shared-dir.list", "start", "stop", "template", @@ -334,11 +336,11 @@ func TestApplyModeRestrictions_AgentScheduleSubcommands(t *testing.T) { assert.Contains(t, remaining, "schedule.cancel") assert.Contains(t, remaining, "schedule.history") - assert.NotContains(t, remaining, "schedule.create") - assert.NotContains(t, remaining, "schedule.create-recurring") - assert.NotContains(t, remaining, "schedule.pause") - assert.NotContains(t, remaining, "schedule.resume") - assert.NotContains(t, remaining, "schedule.delete") + assert.Contains(t, remaining, "schedule.create") + assert.Contains(t, remaining, "schedule.create-recurring") + assert.Contains(t, remaining, "schedule.pause") + assert.Contains(t, remaining, "schedule.resume") + assert.Contains(t, remaining, "schedule.delete") } func TestApplyModeRestrictions_HelpAlwaysKept(t *testing.T) { @@ -413,6 +415,7 @@ func TestAgentAllowedList(t *testing.T) { "resume", "version", "notifications", "schedule", "schedule.list", "schedule.get", "schedule.cancel", "schedule.history", + "schedule.create", "schedule.create-recurring", "schedule.pause", "schedule.resume", "schedule.delete", "shared-dir", "shared-dir.list", "shared-dir.info", "templates", "templates.list", "templates.show", "templates.create", "templates.clone", "templates.delete", "templates.update-default", @@ -436,8 +439,6 @@ func TestAgentAllowedList(t *testing.T) { "hub.auth", "hub.token", "hub.groves", "hub.brokers", "hub.env", "hub.secret", "hub.status", "hub.notifications", "messages.read", - "schedule.create", "schedule.create-recurring", "schedule.delete", - "schedule.pause", "schedule.resume", "shared-dir.create", "shared-dir.remove", } for _, path := range notAllowed { diff --git a/cmd/schedule.go b/cmd/schedule.go index 97783e7a2..9b5da96e3 100644 --- a/cmd/schedule.go +++ b/cmd/schedule.go @@ -38,9 +38,6 @@ var ( scheduleName string scheduleCron string scheduleListType string // "events", "recurring", "all" - scheduleTemplate string - scheduleTask string - scheduleBranch string ) // scheduleCmd is the top-level command group for schedule management. @@ -77,8 +74,8 @@ var scheduleCancelCmd = &cobra.Command{ var scheduleCreateCmd = &cobra.Command{ Use: "create", Short: "Create a one-shot scheduled event", - Long: `Create a one-shot scheduled event. Requires --type, timing (--in or --at), -and type-specific flags (e.g. --agent and --message for message events).`, + Long: `Create a one-shot scheduled event. Requires --type message, timing (--in or --at), +--agent, and --message.`, RunE: runScheduleCreate, } @@ -87,7 +84,7 @@ var scheduleCreateRecurringCmd = &cobra.Command{ Use: "create-recurring", Short: "Create a recurring schedule", Long: `Create a recurring schedule with a cron expression. Requires --name, --cron, ---type, and type-specific flags (e.g. --agent and --message for message events).`, +--type message, --agent, and --message.`, RunE: runScheduleCreateRecurring, } @@ -427,12 +424,8 @@ func runScheduleCreate(cmd *cobra.Command, args []string) error { if scheduleMessage == "" { return fmt.Errorf("--message is required for message events") } - case "dispatch_agent": - if scheduleAgent == "" { - return fmt.Errorf("--agent is required for dispatch_agent events (the name of the agent to create)") - } default: - return fmt.Errorf("unsupported event type: %q (supported: message, dispatch_agent)", scheduleType) + return fmt.Errorf("unsupported event type: %q (supported: message)", scheduleType) } hubCtx, err := CheckHubAvailabilityWithOptions(projectPath, true) @@ -457,9 +450,6 @@ func runScheduleCreate(cmd *cobra.Command, args []string) error { AgentName: scheduleAgent, Message: scheduleMessage, Interrupt: scheduleInterrupt, - Template: scheduleTemplate, - Task: scheduleTask, - Branch: scheduleBranch, } if scheduleIn != "" { @@ -507,12 +497,8 @@ func runScheduleCreateRecurring(cmd *cobra.Command, args []string) error { if scheduleMessage == "" { return fmt.Errorf("--message is required for message schedules") } - case "dispatch_agent": - if scheduleAgent == "" { - return fmt.Errorf("--agent is required for dispatch_agent schedules (the name of the agent to create)") - } default: - return fmt.Errorf("unsupported event type: %q (supported: message, dispatch_agent)", scheduleType) + return fmt.Errorf("unsupported event type: %q (supported: message)", scheduleType) } hubCtx, err := CheckHubAvailabilityWithOptions(projectPath, true) @@ -539,9 +525,6 @@ func runScheduleCreateRecurring(cmd *cobra.Command, args []string) error { AgentName: scheduleAgent, Message: scheduleMessage, Interrupt: scheduleInterrupt, - Template: scheduleTemplate, - Task: scheduleTask, - Branch: scheduleBranch, } ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) @@ -805,24 +788,18 @@ func init() { scheduleListCmd.Flags().StringVar(&scheduleListType, "show", "", "Filter by resource type: events, recurring, or all (default: all)") // Create one-shot flags - scheduleCreateCmd.Flags().StringVar(&scheduleType, "type", "", "Event type (required: message, dispatch_agent)") + scheduleCreateCmd.Flags().StringVar(&scheduleType, "type", "", "Event type (required: message)") scheduleCreateCmd.Flags().StringVar(&scheduleIn, "in", "", "Schedule after a duration (e.g. 30m, 1h)") scheduleCreateCmd.Flags().StringVar(&scheduleAt, "at", "", "Schedule at an absolute time (ISO 8601)") scheduleCreateCmd.Flags().StringVar(&scheduleAgent, "agent", "", "Target agent name") - scheduleCreateCmd.Flags().StringVar(&scheduleMessage, "message", "", "Message body (for message events)") - scheduleCreateCmd.Flags().BoolVar(&scheduleInterrupt, "interrupt", false, "Interrupt the agent (for message events)") - scheduleCreateCmd.Flags().StringVar(&scheduleTemplate, "template", "", "Agent template (for dispatch_agent events)") - scheduleCreateCmd.Flags().StringVar(&scheduleTask, "task", "", "Task/prompt for the agent (for dispatch_agent events)") - scheduleCreateCmd.Flags().StringVar(&scheduleBranch, "branch", "", "Git branch name (for dispatch_agent events)") + scheduleCreateCmd.Flags().StringVar(&scheduleMessage, "message", "", "Message body") + scheduleCreateCmd.Flags().BoolVar(&scheduleInterrupt, "interrupt", false, "Interrupt the agent") // Create recurring flags scheduleCreateRecurringCmd.Flags().StringVar(&scheduleName, "name", "", "Schedule name (required)") - scheduleCreateRecurringCmd.Flags().StringVar(&scheduleCron, "cron", "", "Cron expression (required, 5-field: minute hour day month weekday)") - scheduleCreateRecurringCmd.Flags().StringVar(&scheduleType, "type", "", "Event type (required: message, dispatch_agent)") - scheduleCreateRecurringCmd.Flags().StringVar(&scheduleAgent, "agent", "", "Target agent name (for message: name or 'all'; for dispatch_agent: name to create)") - scheduleCreateRecurringCmd.Flags().StringVar(&scheduleMessage, "message", "", "Message body (for message events)") - scheduleCreateRecurringCmd.Flags().BoolVar(&scheduleInterrupt, "interrupt", false, "Interrupt the agent (for message events)") - scheduleCreateRecurringCmd.Flags().StringVar(&scheduleTemplate, "template", "", "Agent template (for dispatch_agent events)") - scheduleCreateRecurringCmd.Flags().StringVar(&scheduleTask, "task", "", "Task/prompt for the agent (for dispatch_agent events)") - scheduleCreateRecurringCmd.Flags().StringVar(&scheduleBranch, "branch", "", "Git branch name (for dispatch_agent events)") + scheduleCreateRecurringCmd.Flags().StringVar(&scheduleCron, "cron", "", "Cron expression (required, 5-field: minute hour day month weekday, UTC)") + scheduleCreateRecurringCmd.Flags().StringVar(&scheduleType, "type", "", "Event type (required: message)") + scheduleCreateRecurringCmd.Flags().StringVar(&scheduleAgent, "agent", "", "Target agent name") + scheduleCreateRecurringCmd.Flags().StringVar(&scheduleMessage, "message", "", "Message body") + scheduleCreateRecurringCmd.Flags().BoolVar(&scheduleInterrupt, "interrupt", false, "Interrupt the agent") } From 35e1485aa597b377b47cf266172864fc7e809178 Mon Sep 17 00:00:00 2001 From: "Scion Agent (agent-scheduler-dev)" Date: Wed, 10 Jun 2026 01:15:27 +0000 Subject: [PATCH 2/2] fix: default --type flag to "message" since it's the only supported type Review feedback: with dispatch_agent removed, --type always has to be "message", so default it instead of requiring it. Remove the dead "--type is required" validation and update help text accordingly. --- cmd/schedule.go | 17 ++++------------- cmd/schedule_test.go | 4 ++-- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/cmd/schedule.go b/cmd/schedule.go index 9b5da96e3..1a0abca01 100644 --- a/cmd/schedule.go +++ b/cmd/schedule.go @@ -74,8 +74,7 @@ var scheduleCancelCmd = &cobra.Command{ var scheduleCreateCmd = &cobra.Command{ Use: "create", Short: "Create a one-shot scheduled event", - Long: `Create a one-shot scheduled event. Requires --type message, timing (--in or --at), ---agent, and --message.`, + Long: `Create a one-shot scheduled event. Requires timing (--in or --at), --agent, and --message.`, RunE: runScheduleCreate, } @@ -83,8 +82,7 @@ var scheduleCreateCmd = &cobra.Command{ var scheduleCreateRecurringCmd = &cobra.Command{ Use: "create-recurring", Short: "Create a recurring schedule", - Long: `Create a recurring schedule with a cron expression. Requires --name, --cron, ---type message, --agent, and --message.`, + Long: `Create a recurring schedule with a cron expression. Requires --name, --cron, --agent, and --message.`, RunE: runScheduleCreateRecurring, } @@ -405,9 +403,6 @@ func runScheduleCancel(cmd *cobra.Command, args []string) error { } func runScheduleCreate(cmd *cobra.Command, args []string) error { - if scheduleType == "" { - return fmt.Errorf("--type is required") - } if scheduleIn == "" && scheduleAt == "" { return fmt.Errorf("either --in or --at is required") } @@ -484,10 +479,6 @@ func runScheduleCreateRecurring(cmd *cobra.Command, args []string) error { if scheduleCron == "" { return fmt.Errorf("--cron is required") } - if scheduleType == "" { - return fmt.Errorf("--type is required") - } - // Validate type-specific flags switch scheduleType { case "message": @@ -788,7 +779,7 @@ func init() { scheduleListCmd.Flags().StringVar(&scheduleListType, "show", "", "Filter by resource type: events, recurring, or all (default: all)") // Create one-shot flags - scheduleCreateCmd.Flags().StringVar(&scheduleType, "type", "", "Event type (required: message)") + scheduleCreateCmd.Flags().StringVar(&scheduleType, "type", "message", "Event type") scheduleCreateCmd.Flags().StringVar(&scheduleIn, "in", "", "Schedule after a duration (e.g. 30m, 1h)") scheduleCreateCmd.Flags().StringVar(&scheduleAt, "at", "", "Schedule at an absolute time (ISO 8601)") scheduleCreateCmd.Flags().StringVar(&scheduleAgent, "agent", "", "Target agent name") @@ -798,7 +789,7 @@ func init() { // Create recurring flags scheduleCreateRecurringCmd.Flags().StringVar(&scheduleName, "name", "", "Schedule name (required)") scheduleCreateRecurringCmd.Flags().StringVar(&scheduleCron, "cron", "", "Cron expression (required, 5-field: minute hour day month weekday, UTC)") - scheduleCreateRecurringCmd.Flags().StringVar(&scheduleType, "type", "", "Event type (required: message)") + scheduleCreateRecurringCmd.Flags().StringVar(&scheduleType, "type", "message", "Event type") scheduleCreateRecurringCmd.Flags().StringVar(&scheduleAgent, "agent", "", "Target agent name") scheduleCreateRecurringCmd.Flags().StringVar(&scheduleMessage, "message", "", "Message body") scheduleCreateRecurringCmd.Flags().BoolVar(&scheduleInterrupt, "interrupt", false, "Interrupt the agent") diff --git a/cmd/schedule_test.go b/cmd/schedule_test.go index 573e346d2..5a3b247ca 100644 --- a/cmd/schedule_test.go +++ b/cmd/schedule_test.go @@ -81,12 +81,12 @@ func TestScheduleCreateValidation(t *testing.T) { scheduleMessage = origMessage }() - t.Run("missing type", func(t *testing.T) { + t.Run("empty type rejected", func(t *testing.T) { scheduleType = "" scheduleIn = "30m" err := runScheduleCreate(nil, nil) assert.Error(t, err) - assert.Contains(t, err.Error(), "--type is required") + assert.Contains(t, err.Error(), "unsupported event type") }) t.Run("missing timing", func(t *testing.T) {