Add cloud workflow schedule CLI#831
Conversation
📝 WalkthroughWalkthroughThis PR adds cloud workflow scheduling functionality to the Agent Relay CLI. It introduces two new subcommands ( ChangesCloud Workflow Schedule CLI
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
| "status": "completed", | ||
| "startedAt": "2026-05-09T19:26:42.106Z", | ||
| "completedAt": "2026-05-09T19:29:18.024Z", | ||
| "path": "/Users/khaliqgant/Projects/AgentWorkforce/relay/.trajectories/completed/2026-05/traj_u4ixmbqqm2y1.json" |
There was a problem hiding this comment.
🔴 Trajectory index entry uses absolute local-machine path instead of relative path
The new trajectory entry for traj_u4ixmbqqm2y1 uses an absolute path (/Users/khaliqgant/Projects/AgentWorkforce/relay/.trajectories/completed/2026-05/traj_u4ixmbqqm2y1.json) while every other entry in the file uses a relative path (e.g., .trajectories/completed/2026-05/traj_lieyyspidhfj.json). This breaks portability — any tooling that resolves trajectory paths will fail on other developer machines or in CI, since the path references a specific user's macOS home directory.
| "path": "/Users/khaliqgant/Projects/AgentWorkforce/relay/.trajectories/completed/2026-05/traj_u4ixmbqqm2y1.json" | |
| "path": ".trajectories/completed/2026-05/traj_u4ixmbqqm2y1.json" |
Was this helpful? React with 👍 or 👎 to provide feedback.
| if (hasCron) { | ||
| requestBody.cron_expression = options.cron?.trim(); | ||
| } else { | ||
| requestBody.scheduled_at = new Date(String(options.at)).toISOString(); |
There was a problem hiding this comment.
🟡 Invalid --at date string throws unhelpful RangeError instead of user-facing message
When options.at contains an unparseable date string (e.g., "next tuesday"), new Date(String(options.at)) creates an Invalid Date object, and calling .toISOString() on it throws RangeError: Invalid time value. The user gets a cryptic runtime error instead of a helpful message like "Invalid date format for --at". The hasAt guard on line 664 only checks that the string is non-empty, not that it's a valid date.
| requestBody.scheduled_at = new Date(String(options.at)).toISOString(); | |
| const parsedDate = new Date(String(options.at)); | |
| if (Number.isNaN(parsedDate.getTime())) { | |
| throw new Error(`Invalid date for --at: ${options.at}`); | |
| } | |
| requestBody.scheduled_at = parsedDate.toISOString(); |
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
packages/cloud/src/workflows.test.ts (1)
430-528: ⚡ Quick winAdd tests for the one-time schedule path and invalid option combinations.
Current coverage is good for cron/list, but adding
atsuccess andcron+at/ neither assertions would lock in the core scheduling contract.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cloud/src/workflows.test.ts` around lines 430 - 528, Add tests covering the one-time schedule path and invalid option combinations for scheduleWorkflow/listWorkflowSchedules: create a new spec that mirrors the existing "creates a cron schedule..." test but calls scheduleWorkflow with the at option (e.g., at: '2026-01-01T00:00:00Z') and assert the authorizedApiFetchMock request body indicates a one-time schedule_type (or equivalent) and that workflowRequest includes/omits runId/s3CodeKey as appropriate; then add two negative tests that call scheduleWorkflow with both cron and at and with neither cron nor at and assert they throw or reject (use the same test harness and authorizedApiFetchMock patterns used in the file). Reference scheduleWorkflow and listWorkflowSchedules and reuse authorizedApiFetchMock/scheduleBodies setup and assertions style from the existing cron test.src/cli/commands/cloud.test.ts (1)
118-171: ⚡ Quick winAdd coverage for one-time scheduling (
--at) to match PR scope.Current tests validate cron schedules and listing, but PR usage/docs also include one-time scheduling. Adding a focused
--attest will close that gap and prevent regressions on the second scheduling mode.Proposed test addition
+ it('schedule creates one-time workflow schedules', async () => { + const { program, deps } = createHarness(); + cloudMocks.scheduleWorkflow.mockResolvedValueOnce({ + id: 'sched-2', + name: 'One-off eval', + scheduleType: 'at', + status: 'active', + lastTriggeredRunId: null, + }); + + await program.parseAsync([ + 'node', + 'agent-relay', + 'cloud', + 'schedule', + 'workflow.yaml', + '--at', + '2026-05-10T09:00:00Z', + '--name', + 'One-off eval', + ]); + + expect(cloudMocks.scheduleWorkflow).toHaveBeenCalledWith( + 'workflow.yaml', + expect.objectContaining({ + at: '2026-05-10T09:00:00Z', + name: 'One-off eval', + }) + ); + expect(deps.log).toHaveBeenCalledWith('Schedule created: sched-2'); + });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli/commands/cloud.test.ts` around lines 118 - 171, Add a new test case alongside the existing schedule test to cover one-time scheduling via the --at flag: mock cloudMocks.scheduleWorkflow.mockResolvedValueOnce to return a one-time schedule (e.g., id 'sched-at-1', scheduleType 'at' or 'one-time', atTimestamp set, lastTriggeredRunId null), call program.parseAsync with the same args but replace '--cron' and cron expression with '--at' and an ISO timestamp, then assert cloudMocks.scheduleWorkflow was called with 'workflow.yaml' and an object containing the at/timestamp field (and no cron), and assert deps.log was called with the created schedule id string (e.g., 'sched-at-1') to verify the output.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.trajectories/completed/2026-05/traj_u4ixmbqqm2y1.json:
- Line 19: The JSON key "projectId" contains an absolute local path that leaks a
user-specific filesystem location; replace the value of "projectId" (the entry
named projectId) with a stable, non-sensitive identifier such as the repository
name, a relative path, or a UUID (e.g., "relay" or "repo:relay") instead of
"/Users/khaliqgant/Projects/AgentWorkforce/relay" to avoid embedding local
environment details.
In @.trajectories/index.json:
- Line 333: The index entry currently contains a machine-specific absolute path
string
"/Users/khaliqgant/Projects/AgentWorkforce/relay/.trajectories/completed/2026-05/traj_u4ixmbqqm2y1.json";
update that JSON value to the repo-relative path
".trajectories/completed/2026-05/traj_u4ixmbqqm2y1.json" so the "path" field
matches the rest of the index and is not machine-specific.
In `@packages/cloud/src/workflows.ts`:
- Around line 927-937: The type guard isWorkflowSchedule currently permits
schedules that lack fields callers expect (e.g., timezone and cadence
timestamps); update it to validate those fields: keep the existing
id/name/status/scheduleType checks, and additionally require record.timezone to
be a string when record.scheduleType === 'cron', and require cadence timestamp
fields (e.g., record.startTime and record.endTime) to be numbers (or valid
timestamp types used elsewhere) when those fields are present or required by
your callers; update the predicate inside isWorkflowSchedule (operating on the
record variable) to include these checks so malformed schedule objects are
rejected.
---
Nitpick comments:
In `@packages/cloud/src/workflows.test.ts`:
- Around line 430-528: Add tests covering the one-time schedule path and invalid
option combinations for scheduleWorkflow/listWorkflowSchedules: create a new
spec that mirrors the existing "creates a cron schedule..." test but calls
scheduleWorkflow with the at option (e.g., at: '2026-01-01T00:00:00Z') and
assert the authorizedApiFetchMock request body indicates a one-time
schedule_type (or equivalent) and that workflowRequest includes/omits
runId/s3CodeKey as appropriate; then add two negative tests that call
scheduleWorkflow with both cron and at and with neither cron nor at and assert
they throw or reject (use the same test harness and authorizedApiFetchMock
patterns used in the file). Reference scheduleWorkflow and listWorkflowSchedules
and reuse authorizedApiFetchMock/scheduleBodies setup and assertions style from
the existing cron test.
In `@src/cli/commands/cloud.test.ts`:
- Around line 118-171: Add a new test case alongside the existing schedule test
to cover one-time scheduling via the --at flag: mock
cloudMocks.scheduleWorkflow.mockResolvedValueOnce to return a one-time schedule
(e.g., id 'sched-at-1', scheduleType 'at' or 'one-time', atTimestamp set,
lastTriggeredRunId null), call program.parseAsync with the same args but replace
'--cron' and cron expression with '--at' and an ISO timestamp, then assert
cloudMocks.scheduleWorkflow was called with 'workflow.yaml' and an object
containing the at/timestamp field (and no cron), and assert deps.log was called
with the created schedule id string (e.g., 'sched-at-1') to verify the output.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: b5f1ba72-501f-443e-a6f8-d3bb314c67b2
📒 Files selected for processing (9)
.trajectories/completed/2026-05/traj_u4ixmbqqm2y1.json.trajectories/completed/2026-05/traj_u4ixmbqqm2y1.md.trajectories/index.jsonpackages/cloud/src/index.tspackages/cloud/src/types.tspackages/cloud/src/workflows.test.tspackages/cloud/src/workflows.tssrc/cli/commands/cloud.test.tssrc/cli/commands/cloud.ts
8431571 to
64c4a24
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/cloud/src/workflows.test.ts (1)
501-516: ⚡ Quick winAdd a cron-mode assertion that
scheduled_atis omitted.The one-time test already asserts
cron_expressionis absent; adding the mirror check in cron mode will better lock the request contract.🔍 Suggested test addition
expect(scheduleBodies[0]).toMatchObject({ name: 'Hourly eval', schedule_type: 'cron', cron_expression: '0 * * * *', timezone: 'UTC', workflowRequest: { fileType: 'yaml', }, }); + expect((scheduleBodies[0] as { scheduled_at?: unknown }).scheduled_at).toBeUndefined(); expect( (scheduleBodies[0] as { workflowRequest: Record<string, unknown> }).workflowRequest.runId ).toBeUndefined();🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cloud/src/workflows.test.ts` around lines 501 - 516, The cron-mode test is missing an assertion that scheduled_at is omitted from the request; update the existing cron assertions for scheduleBodies[0] to also assert that (scheduleBodies[0] as { workflowRequest: Record<string, unknown> }).workflowRequest.scheduled_at is undefined so the cron request mirrors the one-time contract (you already check cron_expression presence — add scheduled_at absence). Use the existing scheduleBodies and workflowRequest references to locate where to add this expect.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/cloud/src/workflows.test.ts`:
- Around line 501-516: The cron-mode test is missing an assertion that
scheduled_at is omitted from the request; update the existing cron assertions
for scheduleBodies[0] to also assert that (scheduleBodies[0] as {
workflowRequest: Record<string, unknown> }).workflowRequest.scheduled_at is
undefined so the cron request mirrors the one-time contract (you already check
cron_expression presence — add scheduled_at absence). Use the existing
scheduleBodies and workflowRequest references to locate where to add this
expect.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 1654110b-9339-4858-a19c-c64e663b2661
📒 Files selected for processing (12)
.trajectories/completed/2026-05/traj_oyc528j7suvo.json.trajectories/completed/2026-05/traj_oyc528j7suvo.md.trajectories/completed/2026-05/traj_u4ixmbqqm2y1.json.trajectories/completed/2026-05/traj_uf8y40ewrfh0.json.trajectories/completed/2026-05/traj_uf8y40ewrfh0.md.trajectories/index.jsonpackages/cloud/src/workflows.test.tspackages/cloud/src/workflows.tspackages/sdk/package.jsonpackages/sdk/src/workflows/cloud-schedules.tspackages/sdk/src/workflows/index.tssrc/cli/commands/cloud.test.ts
✅ Files skipped from review due to trivial changes (9)
- packages/sdk/src/workflows/index.ts
- .trajectories/completed/2026-05/traj_uf8y40ewrfh0.md
- packages/sdk/src/workflows/cloud-schedules.ts
- packages/sdk/package.json
- .trajectories/completed/2026-05/traj_uf8y40ewrfh0.json
- .trajectories/completed/2026-05/traj_u4ixmbqqm2y1.json
- .trajectories/completed/2026-05/traj_oyc528j7suvo.md
- .trajectories/completed/2026-05/traj_oyc528j7suvo.json
- .trajectories/index.json
🚧 Files skipped from review as they are similar to previous changes (2)
- src/cli/commands/cloud.test.ts
- packages/cloud/src/workflows.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CHANGELOG.md`:
- Line 47: The changelog entry contains a duplicated PR reference: the line
"Reclaim agent on 409 instead of crashing the broker (`#797`) (`#830`) (`#797`)"
should list each PR only once; edit CHANGELOG.md to remove the duplicate
"(`#797`)" so the line becomes "Reclaim agent on 409 instead of crashing the
broker (`#797`) (`#830`)" (or reorder if you prefer a different ordering), ensuring
no duplicate PR IDs remain.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: d8337581-0844-420c-b300-023df2ed78be
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (10)
.trajectories/completed/2026-05/traj_iole5zdt9orr.json.trajectories/completed/2026-05/traj_iole5zdt9orr.md.trajectories/index.jsonCHANGELOG.mdpackages/sdk/package.jsonpackages/sdk/tsconfig.build.jsonpackages/sdk/tsconfig.jsonpackages/telemetry/src/events.tsscripts/build-cjs.mjssrc/cli/bootstrap.test.ts
✅ Files skipped from review due to trivial changes (4)
- packages/sdk/tsconfig.build.json
- .trajectories/completed/2026-05/traj_iole5zdt9orr.json
- src/cli/bootstrap.test.ts
- .trajectories/index.json
|
|
||
| #### User-Impacting Fixes | ||
|
|
||
| - Reclaim agent on 409 instead of crashing the broker (#797) (#830) (#797) |
There was a problem hiding this comment.
Remove duplicated PR reference in changelog entry.
Line 47 repeats (#797) twice, which creates noisy release traceability. Keep each reference once.
Proposed fix
-- Reclaim agent on 409 instead of crashing the broker (`#797`) (`#830`) (`#797`)
+- Reclaim agent on 409 instead of crashing the broker (`#797`) (`#830`)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - Reclaim agent on 409 instead of crashing the broker (#797) (#830) (#797) | |
| - Reclaim agent on 409 instead of crashing the broker (`#797`) (`#830`) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CHANGELOG.md` at line 47, The changelog entry contains a duplicated PR
reference: the line "Reclaim agent on 409 instead of crashing the broker (`#797`)
(`#830`) (`#797`)" should list each PR only once; edit CHANGELOG.md to remove the
duplicate "(`#797`)" so the line becomes "Reclaim agent on 409 instead of crashing
the broker (`#797`) (`#830`)" (or reorder if you prefer a different ordering),
ensuring no duplicate PR IDs remain.
Summary
scheduleWorkflow,listWorkflowSchedules, and schedule types from@agent-relay/sdk/workflowsso products like Ricky can reuse the Relay SDK surfaceagent-relay cloud schedulefor cron or one-time scheduled workflow launchesagent-relay cloud schedulesto list schedules that also appear in the Cloud dashboardUsage
SDK:
Companion Cloud PR: https://github.com/AgentWorkforce/cloud/pull/511
Companion Ricky CLI PR: AgentWorkforce/ricky#85
Verification