feat(deploy): support deploy input overrides - #101

Merged
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags
May 13, 2026
Merged

feat(deploy): support deploy input overrides#101
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

  • Track I: Track I — Deploy CLI flags
  • Final signoff: COMPLETE.
  • Eligible for auto-merge when CI green and upstream deps merged.

Spec reference

Source spec: workforce/docs/plans/deploy-v1-schema-cascade-spec.md

Track section: Track I — Deploy CLI flags

Final signoff

Verifying acceptance bullets against actual files:
**Spec (deploy-v1.md §3.8, §5 flag list):**
- Repeatable `--input KEY=value` flags ✅
- CLI rejects undeclared keys ✅
- Requires string values ✅
- dev + sandbox: inject `WORKFORCE_INPUT_<KEY>` env ✅
- cloud: send as `inputs` in POST body ✅
**Verified files:**
1. **CLI parser** (`packages/cli/src/deploy-command.ts:86, 109, 136-181`)
- `--input` documented in DEPLOY_USAGE
- Accepts both `--input KEY=val` (sep arg) and `--input=KEY=val` (joined) — repeatable via accumulator
- Malformed input dies with clean error (`expected <key>=<value>`)
2. **Validation** (`packages/deploy/src/index.ts:61-75`)
- `validateDeployInputs` checks string type → `Input '${key}' must be a string`
- Rejects undeclared keys → `Unknown input '${key}'; persona declares: ${list}`
- Runs against parsed persona's `inputs` declaration via `preflightPersona`
3. **Env injection — dev & sandbox** (`packages/deploy/src/index.ts:96-120`)
- `wrapLauncher` wraps `dev`, `sandbox`, AND `cloud` launchers
- `toInputEnv` prefixes every key with `WORKFORCE_INPUT_` and merges into `env`
- `inputs` also forwarded to launcher input
4. **Cloud POST body** (`packages/deploy/src/modes/cloud.ts:49-57`)
- `body: JSON.stringify({ persona, bundle, ...(inputs && Object.keys.length > 0 ? { inputs } : {}) })`
5. **Tests** (`packages/deploy/src/modes/input-values.test.ts`, `packages/cli/src/deploy-command.test.ts`)
- Parser: single, multiple, malformed → all covered
- Validation: env propagation, undeclared rejection, non-string rejection
- Cloud: live `fetch` capture asserts POST body contains `inputs: { TOPIC: 'Deploy v1' }`
- Dev launcher: end-to-end child process observes `WORKFORCE_INPUT_TOPIC`/`WORKFORCE_INPUT_REGION` in env
6. **Spec doc** (`docs/plans/deploy-v1.md:188-190, 289, 295`) — `--input` flag listed in CLI surface and §3.8 normative paragraph.
All five acceptance bullets are satisfied with both implementation and test coverage. The undeclared-key error message format matches the test regex (`Unknown input 'UNKNOWN'; persona declares: TOPIC, REGION`).
SIGNOFF_FINAL: COMPLETE Track-I

Final gate (typecheck + tests)

FINAL_I_TSC=0
FINAL_I_TESTS=0
> workforce@0.1.0 typecheck /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> corepack pnpm -r typecheck && corepack pnpm run typecheck:examples
Scope: 8 of 9 workspace projects
packages/daytona-runner typecheck$ tsc -p tsconfig.json --noEmit
packages/persona-kit typecheck$ tsc -p tsconfig.json --noEmit
packages/daytona-runner typecheck: Done
packages/persona-kit typecheck: Done
packages/runtime typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck: Done
packages/runtime typecheck: Done
packages/deploy typecheck$ tsc -p tsconfig.json --noEmit
packages/deploy typecheck: Done
packages/cli typecheck$ tsc -p tsconfig.json --noEmit
packages/cli typecheck: Done
packages/agentworkforce typecheck$ node --check bin/agentworkforce.js
packages/agentworkforce typecheck: Done
> workforce@0.1.0 typecheck:examples /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> tsc -p examples/tsconfig.json --noEmit
packages/cli test: # Subtest: computeTuiView: matches mode honors visibleCap
packages/cli test: ok 166 - computeTuiView: matches mode honors visibleCap
packages/cli test: ---
packages/cli test: duration_ms: 0.033
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: # Subtest: loadRecents returns [] when the file is absent or corrupt
packages/cli test: ok 167 - loadRecents returns [] when the file is absent or corrupt
packages/cli test: ---
packages/cli test: duration_ms: 0.35175
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: 1..167
packages/cli test: # tests 167
packages/cli test: # suites 0
packages/cli test: # pass 167
packages/cli test: # fail 0
packages/cli test: # cancelled 0
packages/cli test: # skipped 0
packages/cli test: # todo 0
packages/cli test: # duration_ms 39466.787541
packages/cli test: Done
packages/agentworkforce test$ node --check bin/agentworkforce.js && node --test test/*.test.js
packages/agentworkforce test: TAP version 13
packages/agentworkforce test: # Subtest: agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ok 1 - agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ---
packages/agentworkforce test: duration_ms: 87.809666
packages/agentworkforce test: type: 'test'
packages/agentworkforce test: ...
packages/agentworkforce test: 1..1
packages/agentworkforce test: # tests 1
packages/agentworkforce test: # suites 0
packages/agentworkforce test: # pass 1
packages/agentworkforce test: # fail 0
packages/agentworkforce test: # cancelled 0
packages/agentworkforce test: # skipped 0
packages/agentworkforce test: # todo 0
packages/agentworkforce test: # duration_ms 193.364041
packages/agentworkforce test: Done

Self-reflection report

REFLECT_GAPS:
- "Update persona spec docs in `docs/plans/deploy-v1.md` §3 to mention `--input` as the deploy-time override mechanism." — MISSING. `docs/plans/deploy-v1.md` has zero matches for `--input` / `input` / `override`; the file is unchanged in this diff.
- Test bullet "Single `--input` parses and forwards." — MISSING. No test files added/modified in the diff (only `cli.ts`, `deploy/src/index.ts`, `modes/cloud.ts`, `types.ts`); no new vitest cases under `packages/cli` or `packages/deploy`.
- Test bullet "Multiple `--input` flags accumulate." — MISSING. No tests added covering `parseDeployInputFlags` in `packages/cli/src/cli.ts:3771`.
- Test bullet "Malformed flag (`--input foo`) → clean error." — MISSING. `expectDeployInputValue` / `parseDeployInputValue` (cli.ts:3795/3803) untested.
- Test bullet "Undeclared input key → clean error citing persona's declared inputs." — MISSING. `validateDeployInputs` in `packages/deploy/src/index.ts:96` has no test asserting the `Unknown input '<key>'; persona declares: …` message.
- Test bullet "`--mode dev` env vars actually reach the child process." — MISSING. No test asserts `WORKFORCE_INPUT_<KEY>` makes it into the dev launcher's child process env via `wrapLauncher` (`packages/deploy/src/index.ts:124`).
- Test bullet "`--mode cloud` POST body includes the `inputs` field." — MISSING. `postCloudDeployment` (`packages/deploy/src/modes/cloud.ts:36`) has no test verifying the body contains `inputs`.
- Implementation bullet "Plumb through `packages/deploy/src/index.ts`'s `deploy()` function as `DeployOptions.inputs?: Record<string, string>`." — PARTIAL. The type is added (`types.ts:24`) and `deploy()` reads `opts.inputs`, but the CLI does NOT pass `opts.inputs` through `runDeploy` — it sets `process.env.WORKFORCE_DEPLOY_INPUTS_JSON` in `cli.ts:3745` and the new `deploy()` wrapper reads it back from env (`index.ts:67`). Programmatic SDK callers using `DeployOptions.inputs` are covered; CLI flow is a roundabout env-var handoff rather than direct plumbing.
- Validation strength: spec says "Value must be a string (basic type check; persona-kit may add more later)." — PARTIAL/redundant. `validateDeployInputs` checks `typeof value !== 'string'` but `inputs` is already typed `Record<string,string>` and the CLI always assigns strings (cli.ts:3808), so the check is unreachable in practice. No declared-but-required-missing handling here (that's Track F's runtime job, so acceptable).
Summary: implementation core is in place across CLI parsing, `DeployOptions.inputs`, validation, and forwarding to all three modes (dev/sandbox env, cloud POST body). The notable gaps are: zero tests added (six explicit test bullets unmet), `docs/plans/deploy-v1.md §3` not updated, and the CLI→`deploy()` plumbing routes through an env-var shim instead of a direct `opts.inputs` pass.

Known gaps after this PR

⚠️Memory is not wired. is a stub in v1; see § Loud hole. Memory wiring lands in a follow-up workflow (not yet specced).

⚠️M3 destroy/list CLI commands not implemented. Separate workflow.

⚠️ ** not on npm** under scope. Handled by a separate agent per platform-team OIDC setup; not blocking morning state because cloud consumes via workspace ref.

Co-Authored-By: Ricky deploy-v1 schema cascade noreply@agentworkforce.com

@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 162e8328-e312-4761-8d57-8ee946ca7be2

📥 Commits

Reviewing files that changed from the base of the PR and between 77660a0 and 8fb4518.

📒 Files selected for processing (2)
  • packages/deploy/src/deploy.ts
  • packages/deploy/src/modes/cloud.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/deploy/src/modes/cloud.ts

📝 Walkthrough

Walkthrough

This PR implements deploy-time persona input overrides via repeatable --input KEY=value CLI flags. Inputs are validated against persona schemas, injected into runners as WORKFORCE_INPUT_<KEY> environment variables, and included in cloud deployment API requests.

Changes

Deploy Input Overrides Feature

Layer / File(s)Summary
Input type contracts
packages/deploy/src/types.ts
DeployOptions adds optional inputs: Record<string,string>; ModeLaunchInput adds inputs and cloudUrl for mode launchers.
CLI input flag parsing
packages/cli/src/deploy-command.ts, packages/cli/src/deploy-command.test.ts
parseDeployArgs recognizes repeatable --input KEY=value / --input=<key>=<value>, validates format, accumulates into inputs, and returns in DeployOptions. Tests cover single/multiple flags and malformed input exit behavior.
Feature specification and design
docs/plans/deploy-v1.md
Docs add "Deploy-time persona inputs" and update CLI usage and deploy flow to describe validation, env var naming, and cloud payload behavior.
Deploy orchestration and input validation
packages/deploy/src/index.ts
New exported deploy wrapper performs preflightPersona, validates opts.inputs against persona-declared keys, rejects unknown/non-string values, and wraps mode launchers to inject WORKFORCE_INPUT_<KEY> env vars and inputs payloads.
Cloud deployment with input support
packages/deploy/src/modes/cloud.ts
Cloud launcher now POSTs deployments to ${cloudUrl}/api/v1/workspaces/:id/deployments with persona, bundle, parsed package.json, and optional inputs; enforces 30s timeout, parses response, logs status, and maps status to exit code.
Deploy callsite forwarding
packages/deploy/src/deploy.ts
deploy forwards cloudUrl into launcher.launch when opts.cloudUrl is set.
End-to-end input integration tests
packages/deploy/src/modes/input-values.test.ts
Tests cover forwarding of validated inputs into dev launcher env and payloads, child-runner env observation, unknown-key and non-string rejections, and that cloud POST includes inputs.

Sequence Diagram

sequenceDiagram
participant CLI as parseDeployArgs
participant Deploy as deploy
participant Persona as preflightPersona
participant Validator as validateDeployInputs
participant Wrapper as wrapInputResolvers
participant Launcher as dev/sandbox/cloudLauncher
participant Cloud as Cloud API
CLI->>Deploy: deploy(opts with inputs)
Deploy->>Persona: preflightPersona(personaPath)
Deploy->>Validator: validateDeployInputs(inputs, persona)
Validator-->>Deploy: validated inputs
Deploy->>Wrapper: wrapInputResolvers(validated inputs, cloudUrl)
Wrapper->>Launcher: launch(input {inputs, env, cloudUrl})
Launcher->>Cloud: POST /deployments { persona, bundle, packageJson, inputs? }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hopping flags into a neat little row,
--input whispers where the overrides go,
Validated keys, strings held tight,
Runners wake with envs alight,
Cloud POST sings the persona's glow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 5.56% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title 'feat(deploy): support deploy input overrides' clearly and concisely summarizes the main change—adding support for deploy-time input overrides via CLI flags.
Description check✅ PassedThe description is detailed and directly related to the changeset, covering spec references, implementation verification, test coverage, and known gaps.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/deploy-input-flags

Comment @coderabbitai help to get the list of available commands and usage tips.

@khaliqgant
khaliqgant marked this pull request as ready for review May 13, 2026 04:49

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/deploy/src/modes/cloud.ts (1)

9-22: ⚡ Quick win

Update the launcher docblock to match current behavior.

The header comment still says cloud mode is unavailable and describes multipart + polling, but the implementation now does a JSON POST and returns immediately.

🤖 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/deploy/src/modes/cloud.ts` around lines 9 - 22, The top docblock in
packages/deploy/src/modes/cloud.ts is outdated: update the comment for `--mode
cloud` to remove the multipart/polling description (steps 1–4) and explicitly
describe the current behavior: the CLI performs a single JSON POST to `POST
/api/v1/workspaces/:id/deployments` with the persona and bundle, the server
returns immediately, and the function returns a deployment handle without
polling; adjust wording to reflect that cloud deploys return immediately and
mention how stop() on the returned handle behaves (e.g., issues a DELETE) so the
docblock matches the implementation.
🤖 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 `@packages/deploy/src/modes/cloud.ts`:
- Around line 41-59: The fetch POST to
`${cloudUrl}/api/v1/workspaces/.../deployments` has no timeout; wrap the request
with an AbortController: create an AbortController before calling fetch, set a
timer (e.g. with setTimeout) that calls controller.abort() after a chosen
timeout, pass controller.signal in the fetch options, and clear the timer once
fetch resolves or throws; update the block that builds the request body
(references: cloudUrl, input, workspaceToken, readFile) to include the signal
and ensure any AbortError is handled/propagated appropriately so `workforce
deploy` cannot hang indefinitely.
---
Nitpick comments:
In `@packages/deploy/src/modes/cloud.ts`:
- Around line 9-22: The top docblock in packages/deploy/src/modes/cloud.ts is
outdated: update the comment for `--mode cloud` to remove the multipart/polling
description (steps 1–4) and explicitly describe the current behavior: the CLI
performs a single JSON POST to `POST /api/v1/workspaces/:id/deployments` with
the persona and bundle, the server returns immediately, and the function returns
a deployment handle without polling; adjust wording to reflect that cloud
deploys return immediately and mention how stop() on the returned handle behaves
(e.g., issues a DELETE) so the docblock matches the implementation.
🪄 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: 4b91f72e-dccb-4cd2-9744-1695b6274f0a

📥 Commits

Reviewing files that changed from the base of the PR and between 19ebbee and 77660a0.

📒 Files selected for processing (7)
  • docs/plans/deploy-v1.md
  • packages/cli/src/deploy-command.test.ts
  • packages/cli/src/deploy-command.ts
  • packages/deploy/src/index.ts
  • packages/deploy/src/modes/cloud.ts
  • packages/deploy/src/modes/input-values.test.ts
  • packages/deploy/src/types.ts

Comment threadpackages/deploy/src/modes/cloud.ts Outdated

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +53 to +54
const inputs = opts.inputs && Object.keys(opts.inputs).length > 0 ? opts.inputs : undefined;
if (!inputs) return deployInternal(opts, resolvers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 --cloud-url CLI flag silently ignored when no --input flags are provided

The new deploy() wrapper in index.ts only forwards opts.cloudUrl to the cloud launcher through wrapLauncher (line 110), which is only invoked when inputs are present (line 58). When there are no inputs, the wrapper calls deployInternal(opts, resolvers) directly, and deployInternal at packages/deploy/src/deploy.ts:177-183 never passes cloudUrl in the launcher.launch(...) call. As a result, the cloud launcher at packages/deploy/src/modes/cloud.ts:25 sees input.cloudUrl as undefined and falls back to process.env.WORKFORCE_CLOUD_URL. This means workforce deploy persona.json --mode cloud --cloud-url https://custom.example.com (without --input) silently ignores --cloud-url, and if WORKFORCE_CLOUD_URL env var is not set, the deployment fails with the "not yet available" error despite a valid cloud URL being specified.

Prompt for agents
The deploy() wrapper in packages/deploy/src/index.ts only wraps launchers (to inject cloudUrl into ModeLaunchInput) when inputs are present. When no inputs are provided, it calls deployInternal directly, and deployInternal in packages/deploy/src/deploy.ts:177-183 does not pass opts.cloudUrl to the launcher.
The cloud launcher (packages/deploy/src/modes/cloud.ts:25) reads input.cloudUrl as its primary source, falling back to env var. So --cloud-url is silently lost in the no-inputs path.
Two possible approaches:
1. Have deployInternal (deploy.ts) pass cloudUrl to launcher.launch() from opts.cloudUrl, so it always reaches launchers regardless of the wrapper.
2. Ensure the deploy() wrapper in index.ts also wraps launchers for cloudUrl when opts.cloudUrl is set, not just when inputs are present. This would mean the wrapper calls wrapInputResolvers even when inputs are empty but cloudUrl is present.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Pass opts.cloudUrl through launcher.launch in deployInternal so
--cloud-url reaches the cloud launcher even when --input is not used.
- Wrap the cloud deploy fetch in an AbortController with a 30s timeout
so a stalled network request can no longer hang `workforce deploy`
indefinitely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit 47dd049 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the feat/deploy-input-flags branch May 13, 2026 08:17
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(deploy): support deploy input overrides - #101

Merged
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags
May 13, 2026
Merged

feat(deploy): support deploy input overrides#101
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

  • Track I: Track I — Deploy CLI flags
  • Final signoff: COMPLETE.
  • Eligible for auto-merge when CI green and upstream deps merged.

Spec reference

Source spec: workforce/docs/plans/deploy-v1-schema-cascade-spec.md

Track section: Track I — Deploy CLI flags

Final signoff

Verifying acceptance bullets against actual files:
**Spec (deploy-v1.md §3.8, §5 flag list):**
- Repeatable `--input KEY=value` flags ✅
- CLI rejects undeclared keys ✅
- Requires string values ✅
- dev + sandbox: inject `WORKFORCE_INPUT_<KEY>` env ✅
- cloud: send as `inputs` in POST body ✅
**Verified files:**
1. **CLI parser** (`packages/cli/src/deploy-command.ts:86, 109, 136-181`)
- `--input` documented in DEPLOY_USAGE
- Accepts both `--input KEY=val` (sep arg) and `--input=KEY=val` (joined) — repeatable via accumulator
- Malformed input dies with clean error (`expected <key>=<value>`)
2. **Validation** (`packages/deploy/src/index.ts:61-75`)
- `validateDeployInputs` checks string type → `Input '${key}' must be a string`
- Rejects undeclared keys → `Unknown input '${key}'; persona declares: ${list}`
- Runs against parsed persona's `inputs` declaration via `preflightPersona`
3. **Env injection — dev & sandbox** (`packages/deploy/src/index.ts:96-120`)
- `wrapLauncher` wraps `dev`, `sandbox`, AND `cloud` launchers
- `toInputEnv` prefixes every key with `WORKFORCE_INPUT_` and merges into `env`
- `inputs` also forwarded to launcher input
4. **Cloud POST body** (`packages/deploy/src/modes/cloud.ts:49-57`)
- `body: JSON.stringify({ persona, bundle, ...(inputs && Object.keys.length > 0 ? { inputs } : {}) })`
5. **Tests** (`packages/deploy/src/modes/input-values.test.ts`, `packages/cli/src/deploy-command.test.ts`)
- Parser: single, multiple, malformed → all covered
- Validation: env propagation, undeclared rejection, non-string rejection
- Cloud: live `fetch` capture asserts POST body contains `inputs: { TOPIC: 'Deploy v1' }`
- Dev launcher: end-to-end child process observes `WORKFORCE_INPUT_TOPIC`/`WORKFORCE_INPUT_REGION` in env
6. **Spec doc** (`docs/plans/deploy-v1.md:188-190, 289, 295`) — `--input` flag listed in CLI surface and §3.8 normative paragraph.
All five acceptance bullets are satisfied with both implementation and test coverage. The undeclared-key error message format matches the test regex (`Unknown input 'UNKNOWN'; persona declares: TOPIC, REGION`).
SIGNOFF_FINAL: COMPLETE Track-I

Final gate (typecheck + tests)

FINAL_I_TSC=0
FINAL_I_TESTS=0
> workforce@0.1.0 typecheck /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> corepack pnpm -r typecheck && corepack pnpm run typecheck:examples
Scope: 8 of 9 workspace projects
packages/daytona-runner typecheck$ tsc -p tsconfig.json --noEmit
packages/persona-kit typecheck$ tsc -p tsconfig.json --noEmit
packages/daytona-runner typecheck: Done
packages/persona-kit typecheck: Done
packages/runtime typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck: Done
packages/runtime typecheck: Done
packages/deploy typecheck$ tsc -p tsconfig.json --noEmit
packages/deploy typecheck: Done
packages/cli typecheck$ tsc -p tsconfig.json --noEmit
packages/cli typecheck: Done
packages/agentworkforce typecheck$ node --check bin/agentworkforce.js
packages/agentworkforce typecheck: Done
> workforce@0.1.0 typecheck:examples /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> tsc -p examples/tsconfig.json --noEmit
packages/cli test: # Subtest: computeTuiView: matches mode honors visibleCap
packages/cli test: ok 166 - computeTuiView: matches mode honors visibleCap
packages/cli test: ---
packages/cli test: duration_ms: 0.033
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: # Subtest: loadRecents returns [] when the file is absent or corrupt
packages/cli test: ok 167 - loadRecents returns [] when the file is absent or corrupt
packages/cli test: ---
packages/cli test: duration_ms: 0.35175
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: 1..167
packages/cli test: # tests 167
packages/cli test: # suites 0
packages/cli test: # pass 167
packages/cli test: # fail 0
packages/cli test: # cancelled 0
packages/cli test: # skipped 0
packages/cli test: # todo 0
packages/cli test: # duration_ms 39466.787541
packages/cli test: Done
packages/agentworkforce test$ node --check bin/agentworkforce.js && node --test test/*.test.js
packages/agentworkforce test: TAP version 13
packages/agentworkforce test: # Subtest: agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ok 1 - agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ---
packages/agentworkforce test: duration_ms: 87.809666
packages/agentworkforce test: type: 'test'
packages/agentworkforce test: ...
packages/agentworkforce test: 1..1
packages/agentworkforce test: # tests 1
packages/agentworkforce test: # suites 0
packages/agentworkforce test: # pass 1
packages/agentworkforce test: # fail 0
packages/agentworkforce test: # cancelled 0
packages/agentworkforce test: # skipped 0
packages/agentworkforce test: # todo 0
packages/agentworkforce test: # duration_ms 193.364041
packages/agentworkforce test: Done

Self-reflection report

REFLECT_GAPS:
- "Update persona spec docs in `docs/plans/deploy-v1.md` §3 to mention `--input` as the deploy-time override mechanism." — MISSING. `docs/plans/deploy-v1.md` has zero matches for `--input` / `input` / `override`; the file is unchanged in this diff.
- Test bullet "Single `--input` parses and forwards." — MISSING. No test files added/modified in the diff (only `cli.ts`, `deploy/src/index.ts`, `modes/cloud.ts`, `types.ts`); no new vitest cases under `packages/cli` or `packages/deploy`.
- Test bullet "Multiple `--input` flags accumulate." — MISSING. No tests added covering `parseDeployInputFlags` in `packages/cli/src/cli.ts:3771`.
- Test bullet "Malformed flag (`--input foo`) → clean error." — MISSING. `expectDeployInputValue` / `parseDeployInputValue` (cli.ts:3795/3803) untested.
- Test bullet "Undeclared input key → clean error citing persona's declared inputs." — MISSING. `validateDeployInputs` in `packages/deploy/src/index.ts:96` has no test asserting the `Unknown input '<key>'; persona declares: …` message.
- Test bullet "`--mode dev` env vars actually reach the child process." — MISSING. No test asserts `WORKFORCE_INPUT_<KEY>` makes it into the dev launcher's child process env via `wrapLauncher` (`packages/deploy/src/index.ts:124`).
- Test bullet "`--mode cloud` POST body includes the `inputs` field." — MISSING. `postCloudDeployment` (`packages/deploy/src/modes/cloud.ts:36`) has no test verifying the body contains `inputs`.
- Implementation bullet "Plumb through `packages/deploy/src/index.ts`'s `deploy()` function as `DeployOptions.inputs?: Record<string, string>`." — PARTIAL. The type is added (`types.ts:24`) and `deploy()` reads `opts.inputs`, but the CLI does NOT pass `opts.inputs` through `runDeploy` — it sets `process.env.WORKFORCE_DEPLOY_INPUTS_JSON` in `cli.ts:3745` and the new `deploy()` wrapper reads it back from env (`index.ts:67`). Programmatic SDK callers using `DeployOptions.inputs` are covered; CLI flow is a roundabout env-var handoff rather than direct plumbing.
- Validation strength: spec says "Value must be a string (basic type check; persona-kit may add more later)." — PARTIAL/redundant. `validateDeployInputs` checks `typeof value !== 'string'` but `inputs` is already typed `Record<string,string>` and the CLI always assigns strings (cli.ts:3808), so the check is unreachable in practice. No declared-but-required-missing handling here (that's Track F's runtime job, so acceptable).
Summary: implementation core is in place across CLI parsing, `DeployOptions.inputs`, validation, and forwarding to all three modes (dev/sandbox env, cloud POST body). The notable gaps are: zero tests added (six explicit test bullets unmet), `docs/plans/deploy-v1.md §3` not updated, and the CLI→`deploy()` plumbing routes through an env-var shim instead of a direct `opts.inputs` pass.

Known gaps after this PR

⚠️Memory is not wired. is a stub in v1; see § Loud hole. Memory wiring lands in a follow-up workflow (not yet specced).

⚠️M3 destroy/list CLI commands not implemented. Separate workflow.

⚠️ ** not on npm** under scope. Handled by a separate agent per platform-team OIDC setup; not blocking morning state because cloud consumes via workspace ref.

Co-Authored-By: Ricky deploy-v1 schema cascade noreply@agentworkforce.com

@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 162e8328-e312-4761-8d57-8ee946ca7be2

📥 Commits

Reviewing files that changed from the base of the PR and between 77660a0 and 8fb4518.

📒 Files selected for processing (2)
  • packages/deploy/src/deploy.ts
  • packages/deploy/src/modes/cloud.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/deploy/src/modes/cloud.ts

📝 Walkthrough

Walkthrough

This PR implements deploy-time persona input overrides via repeatable --input KEY=value CLI flags. Inputs are validated against persona schemas, injected into runners as WORKFORCE_INPUT_<KEY> environment variables, and included in cloud deployment API requests.

Changes

Deploy Input Overrides Feature

Layer / File(s)Summary
Input type contracts
packages/deploy/src/types.ts
DeployOptions adds optional inputs: Record<string,string>; ModeLaunchInput adds inputs and cloudUrl for mode launchers.
CLI input flag parsing
packages/cli/src/deploy-command.ts, packages/cli/src/deploy-command.test.ts
parseDeployArgs recognizes repeatable --input KEY=value / --input=<key>=<value>, validates format, accumulates into inputs, and returns in DeployOptions. Tests cover single/multiple flags and malformed input exit behavior.
Feature specification and design
docs/plans/deploy-v1.md
Docs add "Deploy-time persona inputs" and update CLI usage and deploy flow to describe validation, env var naming, and cloud payload behavior.
Deploy orchestration and input validation
packages/deploy/src/index.ts
New exported deploy wrapper performs preflightPersona, validates opts.inputs against persona-declared keys, rejects unknown/non-string values, and wraps mode launchers to inject WORKFORCE_INPUT_<KEY> env vars and inputs payloads.
Cloud deployment with input support
packages/deploy/src/modes/cloud.ts
Cloud launcher now POSTs deployments to ${cloudUrl}/api/v1/workspaces/:id/deployments with persona, bundle, parsed package.json, and optional inputs; enforces 30s timeout, parses response, logs status, and maps status to exit code.
Deploy callsite forwarding
packages/deploy/src/deploy.ts
deploy forwards cloudUrl into launcher.launch when opts.cloudUrl is set.
End-to-end input integration tests
packages/deploy/src/modes/input-values.test.ts
Tests cover forwarding of validated inputs into dev launcher env and payloads, child-runner env observation, unknown-key and non-string rejections, and that cloud POST includes inputs.

Sequence Diagram

sequenceDiagram
participant CLI as parseDeployArgs
participant Deploy as deploy
participant Persona as preflightPersona
participant Validator as validateDeployInputs
participant Wrapper as wrapInputResolvers
participant Launcher as dev/sandbox/cloudLauncher
participant Cloud as Cloud API
CLI->>Deploy: deploy(opts with inputs)
Deploy->>Persona: preflightPersona(personaPath)
Deploy->>Validator: validateDeployInputs(inputs, persona)
Validator-->>Deploy: validated inputs
Deploy->>Wrapper: wrapInputResolvers(validated inputs, cloudUrl)
Wrapper->>Launcher: launch(input {inputs, env, cloudUrl})
Launcher->>Cloud: POST /deployments { persona, bundle, packageJson, inputs? }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hopping flags into a neat little row,
--input whispers where the overrides go,
Validated keys, strings held tight,
Runners wake with envs alight,
Cloud POST sings the persona's glow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 5.56% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title 'feat(deploy): support deploy input overrides' clearly and concisely summarizes the main change—adding support for deploy-time input overrides via CLI flags.
Description check✅ PassedThe description is detailed and directly related to the changeset, covering spec references, implementation verification, test coverage, and known gaps.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/deploy-input-flags

Comment @coderabbitai help to get the list of available commands and usage tips.

@khaliqgant
khaliqgant marked this pull request as ready for review May 13, 2026 04:49

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/deploy/src/modes/cloud.ts (1)

9-22: ⚡ Quick win

Update the launcher docblock to match current behavior.

The header comment still says cloud mode is unavailable and describes multipart + polling, but the implementation now does a JSON POST and returns immediately.

🤖 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/deploy/src/modes/cloud.ts` around lines 9 - 22, The top docblock in
packages/deploy/src/modes/cloud.ts is outdated: update the comment for `--mode
cloud` to remove the multipart/polling description (steps 1–4) and explicitly
describe the current behavior: the CLI performs a single JSON POST to `POST
/api/v1/workspaces/:id/deployments` with the persona and bundle, the server
returns immediately, and the function returns a deployment handle without
polling; adjust wording to reflect that cloud deploys return immediately and
mention how stop() on the returned handle behaves (e.g., issues a DELETE) so the
docblock matches the implementation.
🤖 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 `@packages/deploy/src/modes/cloud.ts`:
- Around line 41-59: The fetch POST to
`${cloudUrl}/api/v1/workspaces/.../deployments` has no timeout; wrap the request
with an AbortController: create an AbortController before calling fetch, set a
timer (e.g. with setTimeout) that calls controller.abort() after a chosen
timeout, pass controller.signal in the fetch options, and clear the timer once
fetch resolves or throws; update the block that builds the request body
(references: cloudUrl, input, workspaceToken, readFile) to include the signal
and ensure any AbortError is handled/propagated appropriately so `workforce
deploy` cannot hang indefinitely.
---
Nitpick comments:
In `@packages/deploy/src/modes/cloud.ts`:
- Around line 9-22: The top docblock in packages/deploy/src/modes/cloud.ts is
outdated: update the comment for `--mode cloud` to remove the multipart/polling
description (steps 1–4) and explicitly describe the current behavior: the CLI
performs a single JSON POST to `POST /api/v1/workspaces/:id/deployments` with
the persona and bundle, the server returns immediately, and the function returns
a deployment handle without polling; adjust wording to reflect that cloud
deploys return immediately and mention how stop() on the returned handle behaves
(e.g., issues a DELETE) so the docblock matches the implementation.
🪄 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: 4b91f72e-dccb-4cd2-9744-1695b6274f0a

📥 Commits

Reviewing files that changed from the base of the PR and between 19ebbee and 77660a0.

📒 Files selected for processing (7)
  • docs/plans/deploy-v1.md
  • packages/cli/src/deploy-command.test.ts
  • packages/cli/src/deploy-command.ts
  • packages/deploy/src/index.ts
  • packages/deploy/src/modes/cloud.ts
  • packages/deploy/src/modes/input-values.test.ts
  • packages/deploy/src/types.ts

Comment threadpackages/deploy/src/modes/cloud.ts Outdated

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +53 to +54
const inputs = opts.inputs && Object.keys(opts.inputs).length > 0 ? opts.inputs : undefined;
if (!inputs) return deployInternal(opts, resolvers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 --cloud-url CLI flag silently ignored when no --input flags are provided

The new deploy() wrapper in index.ts only forwards opts.cloudUrl to the cloud launcher through wrapLauncher (line 110), which is only invoked when inputs are present (line 58). When there are no inputs, the wrapper calls deployInternal(opts, resolvers) directly, and deployInternal at packages/deploy/src/deploy.ts:177-183 never passes cloudUrl in the launcher.launch(...) call. As a result, the cloud launcher at packages/deploy/src/modes/cloud.ts:25 sees input.cloudUrl as undefined and falls back to process.env.WORKFORCE_CLOUD_URL. This means workforce deploy persona.json --mode cloud --cloud-url https://custom.example.com (without --input) silently ignores --cloud-url, and if WORKFORCE_CLOUD_URL env var is not set, the deployment fails with the "not yet available" error despite a valid cloud URL being specified.

Prompt for agents
The deploy() wrapper in packages/deploy/src/index.ts only wraps launchers (to inject cloudUrl into ModeLaunchInput) when inputs are present. When no inputs are provided, it calls deployInternal directly, and deployInternal in packages/deploy/src/deploy.ts:177-183 does not pass opts.cloudUrl to the launcher.
The cloud launcher (packages/deploy/src/modes/cloud.ts:25) reads input.cloudUrl as its primary source, falling back to env var. So --cloud-url is silently lost in the no-inputs path.
Two possible approaches:
1. Have deployInternal (deploy.ts) pass cloudUrl to launcher.launch() from opts.cloudUrl, so it always reaches launchers regardless of the wrapper.
2. Ensure the deploy() wrapper in index.ts also wraps launchers for cloudUrl when opts.cloudUrl is set, not just when inputs are present. This would mean the wrapper calls wrapInputResolvers even when inputs are empty but cloudUrl is present.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Pass opts.cloudUrl through launcher.launch in deployInternal so
--cloud-url reaches the cloud launcher even when --input is not used.
- Wrap the cloud deploy fetch in an AbortController with a 30s timeout
so a stalled network request can no longer hang `workforce deploy`
indefinitely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit 47dd049 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the feat/deploy-input-flags branch May 13, 2026 08:17
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(deploy): support deploy input overrides - #101

Merged
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags
May 13, 2026
Merged

feat(deploy): support deploy input overrides#101
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

  • Track I: Track I — Deploy CLI flags
  • Final signoff: COMPLETE.
  • Eligible for auto-merge when CI green and upstream deps merged.

Spec reference

Source spec: workforce/docs/plans/deploy-v1-schema-cascade-spec.md

Track section: Track I — Deploy CLI flags

Final signoff

Verifying acceptance bullets against actual files:
**Spec (deploy-v1.md §3.8, §5 flag list):**
- Repeatable `--input KEY=value` flags ✅
- CLI rejects undeclared keys ✅
- Requires string values ✅
- dev + sandbox: inject `WORKFORCE_INPUT_<KEY>` env ✅
- cloud: send as `inputs` in POST body ✅
**Verified files:**
1. **CLI parser** (`packages/cli/src/deploy-command.ts:86, 109, 136-181`)
- `--input` documented in DEPLOY_USAGE
- Accepts both `--input KEY=val` (sep arg) and `--input=KEY=val` (joined) — repeatable via accumulator
- Malformed input dies with clean error (`expected <key>=<value>`)
2. **Validation** (`packages/deploy/src/index.ts:61-75`)
- `validateDeployInputs` checks string type → `Input '${key}' must be a string`
- Rejects undeclared keys → `Unknown input '${key}'; persona declares: ${list}`
- Runs against parsed persona's `inputs` declaration via `preflightPersona`
3. **Env injection — dev & sandbox** (`packages/deploy/src/index.ts:96-120`)
- `wrapLauncher` wraps `dev`, `sandbox`, AND `cloud` launchers
- `toInputEnv` prefixes every key with `WORKFORCE_INPUT_` and merges into `env`
- `inputs` also forwarded to launcher input
4. **Cloud POST body** (`packages/deploy/src/modes/cloud.ts:49-57`)
- `body: JSON.stringify({ persona, bundle, ...(inputs && Object.keys.length > 0 ? { inputs } : {}) })`
5. **Tests** (`packages/deploy/src/modes/input-values.test.ts`, `packages/cli/src/deploy-command.test.ts`)
- Parser: single, multiple, malformed → all covered
- Validation: env propagation, undeclared rejection, non-string rejection
- Cloud: live `fetch` capture asserts POST body contains `inputs: { TOPIC: 'Deploy v1' }`
- Dev launcher: end-to-end child process observes `WORKFORCE_INPUT_TOPIC`/`WORKFORCE_INPUT_REGION` in env
6. **Spec doc** (`docs/plans/deploy-v1.md:188-190, 289, 295`) — `--input` flag listed in CLI surface and §3.8 normative paragraph.
All five acceptance bullets are satisfied with both implementation and test coverage. The undeclared-key error message format matches the test regex (`Unknown input 'UNKNOWN'; persona declares: TOPIC, REGION`).
SIGNOFF_FINAL: COMPLETE Track-I

Final gate (typecheck + tests)

FINAL_I_TSC=0
FINAL_I_TESTS=0
> workforce@0.1.0 typecheck /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> corepack pnpm -r typecheck && corepack pnpm run typecheck:examples
Scope: 8 of 9 workspace projects
packages/daytona-runner typecheck$ tsc -p tsconfig.json --noEmit
packages/persona-kit typecheck$ tsc -p tsconfig.json --noEmit
packages/daytona-runner typecheck: Done
packages/persona-kit typecheck: Done
packages/runtime typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck: Done
packages/runtime typecheck: Done
packages/deploy typecheck$ tsc -p tsconfig.json --noEmit
packages/deploy typecheck: Done
packages/cli typecheck$ tsc -p tsconfig.json --noEmit
packages/cli typecheck: Done
packages/agentworkforce typecheck$ node --check bin/agentworkforce.js
packages/agentworkforce typecheck: Done
> workforce@0.1.0 typecheck:examples /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> tsc -p examples/tsconfig.json --noEmit
packages/cli test: # Subtest: computeTuiView: matches mode honors visibleCap
packages/cli test: ok 166 - computeTuiView: matches mode honors visibleCap
packages/cli test: ---
packages/cli test: duration_ms: 0.033
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: # Subtest: loadRecents returns [] when the file is absent or corrupt
packages/cli test: ok 167 - loadRecents returns [] when the file is absent or corrupt
packages/cli test: ---
packages/cli test: duration_ms: 0.35175
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: 1..167
packages/cli test: # tests 167
packages/cli test: # suites 0
packages/cli test: # pass 167
packages/cli test: # fail 0
packages/cli test: # cancelled 0
packages/cli test: # skipped 0
packages/cli test: # todo 0
packages/cli test: # duration_ms 39466.787541
packages/cli test: Done
packages/agentworkforce test$ node --check bin/agentworkforce.js && node --test test/*.test.js
packages/agentworkforce test: TAP version 13
packages/agentworkforce test: # Subtest: agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ok 1 - agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ---
packages/agentworkforce test: duration_ms: 87.809666
packages/agentworkforce test: type: 'test'
packages/agentworkforce test: ...
packages/agentworkforce test: 1..1
packages/agentworkforce test: # tests 1
packages/agentworkforce test: # suites 0
packages/agentworkforce test: # pass 1
packages/agentworkforce test: # fail 0
packages/agentworkforce test: # cancelled 0
packages/agentworkforce test: # skipped 0
packages/agentworkforce test: # todo 0
packages/agentworkforce test: # duration_ms 193.364041
packages/agentworkforce test: Done

Self-reflection report

REFLECT_GAPS:
- "Update persona spec docs in `docs/plans/deploy-v1.md` §3 to mention `--input` as the deploy-time override mechanism." — MISSING. `docs/plans/deploy-v1.md` has zero matches for `--input` / `input` / `override`; the file is unchanged in this diff.
- Test bullet "Single `--input` parses and forwards." — MISSING. No test files added/modified in the diff (only `cli.ts`, `deploy/src/index.ts`, `modes/cloud.ts`, `types.ts`); no new vitest cases under `packages/cli` or `packages/deploy`.
- Test bullet "Multiple `--input` flags accumulate." — MISSING. No tests added covering `parseDeployInputFlags` in `packages/cli/src/cli.ts:3771`.
- Test bullet "Malformed flag (`--input foo`) → clean error." — MISSING. `expectDeployInputValue` / `parseDeployInputValue` (cli.ts:3795/3803) untested.
- Test bullet "Undeclared input key → clean error citing persona's declared inputs." — MISSING. `validateDeployInputs` in `packages/deploy/src/index.ts:96` has no test asserting the `Unknown input '<key>'; persona declares: …` message.
- Test bullet "`--mode dev` env vars actually reach the child process." — MISSING. No test asserts `WORKFORCE_INPUT_<KEY>` makes it into the dev launcher's child process env via `wrapLauncher` (`packages/deploy/src/index.ts:124`).
- Test bullet "`--mode cloud` POST body includes the `inputs` field." — MISSING. `postCloudDeployment` (`packages/deploy/src/modes/cloud.ts:36`) has no test verifying the body contains `inputs`.
- Implementation bullet "Plumb through `packages/deploy/src/index.ts`'s `deploy()` function as `DeployOptions.inputs?: Record<string, string>`." — PARTIAL. The type is added (`types.ts:24`) and `deploy()` reads `opts.inputs`, but the CLI does NOT pass `opts.inputs` through `runDeploy` — it sets `process.env.WORKFORCE_DEPLOY_INPUTS_JSON` in `cli.ts:3745` and the new `deploy()` wrapper reads it back from env (`index.ts:67`). Programmatic SDK callers using `DeployOptions.inputs` are covered; CLI flow is a roundabout env-var handoff rather than direct plumbing.
- Validation strength: spec says "Value must be a string (basic type check; persona-kit may add more later)." — PARTIAL/redundant. `validateDeployInputs` checks `typeof value !== 'string'` but `inputs` is already typed `Record<string,string>` and the CLI always assigns strings (cli.ts:3808), so the check is unreachable in practice. No declared-but-required-missing handling here (that's Track F's runtime job, so acceptable).
Summary: implementation core is in place across CLI parsing, `DeployOptions.inputs`, validation, and forwarding to all three modes (dev/sandbox env, cloud POST body). The notable gaps are: zero tests added (six explicit test bullets unmet), `docs/plans/deploy-v1.md §3` not updated, and the CLI→`deploy()` plumbing routes through an env-var shim instead of a direct `opts.inputs` pass.

Known gaps after this PR

⚠️Memory is not wired. is a stub in v1; see § Loud hole. Memory wiring lands in a follow-up workflow (not yet specced).

⚠️M3 destroy/list CLI commands not implemented. Separate workflow.

⚠️ ** not on npm** under scope. Handled by a separate agent per platform-team OIDC setup; not blocking morning state because cloud consumes via workspace ref.

Co-Authored-By: Ricky deploy-v1 schema cascade noreply@agentworkforce.com

@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 162e8328-e312-4761-8d57-8ee946ca7be2

📥 Commits

Reviewing files that changed from the base of the PR and between 77660a0 and 8fb4518.

📒 Files selected for processing (2)
  • packages/deploy/src/deploy.ts
  • packages/deploy/src/modes/cloud.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/deploy/src/modes/cloud.ts

📝 Walkthrough

Walkthrough

This PR implements deploy-time persona input overrides via repeatable --input KEY=value CLI flags. Inputs are validated against persona schemas, injected into runners as WORKFORCE_INPUT_<KEY> environment variables, and included in cloud deployment API requests.

Changes

Deploy Input Overrides Feature

Layer / File(s)Summary
Input type contracts
packages/deploy/src/types.ts
DeployOptions adds optional inputs: Record<string,string>; ModeLaunchInput adds inputs and cloudUrl for mode launchers.
CLI input flag parsing
packages/cli/src/deploy-command.ts, packages/cli/src/deploy-command.test.ts
parseDeployArgs recognizes repeatable --input KEY=value / --input=<key>=<value>, validates format, accumulates into inputs, and returns in DeployOptions. Tests cover single/multiple flags and malformed input exit behavior.
Feature specification and design
docs/plans/deploy-v1.md
Docs add "Deploy-time persona inputs" and update CLI usage and deploy flow to describe validation, env var naming, and cloud payload behavior.
Deploy orchestration and input validation
packages/deploy/src/index.ts
New exported deploy wrapper performs preflightPersona, validates opts.inputs against persona-declared keys, rejects unknown/non-string values, and wraps mode launchers to inject WORKFORCE_INPUT_<KEY> env vars and inputs payloads.
Cloud deployment with input support
packages/deploy/src/modes/cloud.ts
Cloud launcher now POSTs deployments to ${cloudUrl}/api/v1/workspaces/:id/deployments with persona, bundle, parsed package.json, and optional inputs; enforces 30s timeout, parses response, logs status, and maps status to exit code.
Deploy callsite forwarding
packages/deploy/src/deploy.ts
deploy forwards cloudUrl into launcher.launch when opts.cloudUrl is set.
End-to-end input integration tests
packages/deploy/src/modes/input-values.test.ts
Tests cover forwarding of validated inputs into dev launcher env and payloads, child-runner env observation, unknown-key and non-string rejections, and that cloud POST includes inputs.

Sequence Diagram

sequenceDiagram
participant CLI as parseDeployArgs
participant Deploy as deploy
participant Persona as preflightPersona
participant Validator as validateDeployInputs
participant Wrapper as wrapInputResolvers
participant Launcher as dev/sandbox/cloudLauncher
participant Cloud as Cloud API
CLI->>Deploy: deploy(opts with inputs)
Deploy->>Persona: preflightPersona(personaPath)
Deploy->>Validator: validateDeployInputs(inputs, persona)
Validator-->>Deploy: validated inputs
Deploy->>Wrapper: wrapInputResolvers(validated inputs, cloudUrl)
Wrapper->>Launcher: launch(input {inputs, env, cloudUrl})
Launcher->>Cloud: POST /deployments { persona, bundle, packageJson, inputs? }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hopping flags into a neat little row,
--input whispers where the overrides go,
Validated keys, strings held tight,
Runners wake with envs alight,
Cloud POST sings the persona's glow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 5.56% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title 'feat(deploy): support deploy input overrides' clearly and concisely summarizes the main change—adding support for deploy-time input overrides via CLI flags.
Description check✅ PassedThe description is detailed and directly related to the changeset, covering spec references, implementation verification, test coverage, and known gaps.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/deploy-input-flags

Comment @coderabbitai help to get the list of available commands and usage tips.

@khaliqgant
khaliqgant marked this pull request as ready for review May 13, 2026 04:49

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/deploy/src/modes/cloud.ts (1)

9-22: ⚡ Quick win

Update the launcher docblock to match current behavior.

The header comment still says cloud mode is unavailable and describes multipart + polling, but the implementation now does a JSON POST and returns immediately.

🤖 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/deploy/src/modes/cloud.ts` around lines 9 - 22, The top docblock in
packages/deploy/src/modes/cloud.ts is outdated: update the comment for `--mode
cloud` to remove the multipart/polling description (steps 1–4) and explicitly
describe the current behavior: the CLI performs a single JSON POST to `POST
/api/v1/workspaces/:id/deployments` with the persona and bundle, the server
returns immediately, and the function returns a deployment handle without
polling; adjust wording to reflect that cloud deploys return immediately and
mention how stop() on the returned handle behaves (e.g., issues a DELETE) so the
docblock matches the implementation.
🤖 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 `@packages/deploy/src/modes/cloud.ts`:
- Around line 41-59: The fetch POST to
`${cloudUrl}/api/v1/workspaces/.../deployments` has no timeout; wrap the request
with an AbortController: create an AbortController before calling fetch, set a
timer (e.g. with setTimeout) that calls controller.abort() after a chosen
timeout, pass controller.signal in the fetch options, and clear the timer once
fetch resolves or throws; update the block that builds the request body
(references: cloudUrl, input, workspaceToken, readFile) to include the signal
and ensure any AbortError is handled/propagated appropriately so `workforce
deploy` cannot hang indefinitely.
---
Nitpick comments:
In `@packages/deploy/src/modes/cloud.ts`:
- Around line 9-22: The top docblock in packages/deploy/src/modes/cloud.ts is
outdated: update the comment for `--mode cloud` to remove the multipart/polling
description (steps 1–4) and explicitly describe the current behavior: the CLI
performs a single JSON POST to `POST /api/v1/workspaces/:id/deployments` with
the persona and bundle, the server returns immediately, and the function returns
a deployment handle without polling; adjust wording to reflect that cloud
deploys return immediately and mention how stop() on the returned handle behaves
(e.g., issues a DELETE) so the docblock matches the implementation.
🪄 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: 4b91f72e-dccb-4cd2-9744-1695b6274f0a

📥 Commits

Reviewing files that changed from the base of the PR and between 19ebbee and 77660a0.

📒 Files selected for processing (7)
  • docs/plans/deploy-v1.md
  • packages/cli/src/deploy-command.test.ts
  • packages/cli/src/deploy-command.ts
  • packages/deploy/src/index.ts
  • packages/deploy/src/modes/cloud.ts
  • packages/deploy/src/modes/input-values.test.ts
  • packages/deploy/src/types.ts

Comment threadpackages/deploy/src/modes/cloud.ts Outdated

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +53 to +54
const inputs = opts.inputs && Object.keys(opts.inputs).length > 0 ? opts.inputs : undefined;
if (!inputs) return deployInternal(opts, resolvers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 --cloud-url CLI flag silently ignored when no --input flags are provided

The new deploy() wrapper in index.ts only forwards opts.cloudUrl to the cloud launcher through wrapLauncher (line 110), which is only invoked when inputs are present (line 58). When there are no inputs, the wrapper calls deployInternal(opts, resolvers) directly, and deployInternal at packages/deploy/src/deploy.ts:177-183 never passes cloudUrl in the launcher.launch(...) call. As a result, the cloud launcher at packages/deploy/src/modes/cloud.ts:25 sees input.cloudUrl as undefined and falls back to process.env.WORKFORCE_CLOUD_URL. This means workforce deploy persona.json --mode cloud --cloud-url https://custom.example.com (without --input) silently ignores --cloud-url, and if WORKFORCE_CLOUD_URL env var is not set, the deployment fails with the "not yet available" error despite a valid cloud URL being specified.

Prompt for agents
The deploy() wrapper in packages/deploy/src/index.ts only wraps launchers (to inject cloudUrl into ModeLaunchInput) when inputs are present. When no inputs are provided, it calls deployInternal directly, and deployInternal in packages/deploy/src/deploy.ts:177-183 does not pass opts.cloudUrl to the launcher.
The cloud launcher (packages/deploy/src/modes/cloud.ts:25) reads input.cloudUrl as its primary source, falling back to env var. So --cloud-url is silently lost in the no-inputs path.
Two possible approaches:
1. Have deployInternal (deploy.ts) pass cloudUrl to launcher.launch() from opts.cloudUrl, so it always reaches launchers regardless of the wrapper.
2. Ensure the deploy() wrapper in index.ts also wraps launchers for cloudUrl when opts.cloudUrl is set, not just when inputs are present. This would mean the wrapper calls wrapInputResolvers even when inputs are empty but cloudUrl is present.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Pass opts.cloudUrl through launcher.launch in deployInternal so
--cloud-url reaches the cloud launcher even when --input is not used.
- Wrap the cloud deploy fetch in an AbortController with a 30s timeout
so a stalled network request can no longer hang `workforce deploy`
indefinitely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit 47dd049 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the feat/deploy-input-flags branch May 13, 2026 08:17
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(deploy): support deploy input overrides - #101

Merged
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags
May 13, 2026
Merged

feat(deploy): support deploy input overrides#101
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

  • Track I: Track I — Deploy CLI flags
  • Final signoff: COMPLETE.
  • Eligible for auto-merge when CI green and upstream deps merged.

Spec reference

Source spec: workforce/docs/plans/deploy-v1-schema-cascade-spec.md

Track section: Track I — Deploy CLI flags

Final signoff

Verifying acceptance bullets against actual files:
**Spec (deploy-v1.md §3.8, §5 flag list):**
- Repeatable `--input KEY=value` flags ✅
- CLI rejects undeclared keys ✅
- Requires string values ✅
- dev + sandbox: inject `WORKFORCE_INPUT_<KEY>` env ✅
- cloud: send as `inputs` in POST body ✅
**Verified files:**
1. **CLI parser** (`packages/cli/src/deploy-command.ts:86, 109, 136-181`)
- `--input` documented in DEPLOY_USAGE
- Accepts both `--input KEY=val` (sep arg) and `--input=KEY=val` (joined) — repeatable via accumulator
- Malformed input dies with clean error (`expected <key>=<value>`)
2. **Validation** (`packages/deploy/src/index.ts:61-75`)
- `validateDeployInputs` checks string type → `Input '${key}' must be a string`
- Rejects undeclared keys → `Unknown input '${key}'; persona declares: ${list}`
- Runs against parsed persona's `inputs` declaration via `preflightPersona`
3. **Env injection — dev & sandbox** (`packages/deploy/src/index.ts:96-120`)
- `wrapLauncher` wraps `dev`, `sandbox`, AND `cloud` launchers
- `toInputEnv` prefixes every key with `WORKFORCE_INPUT_` and merges into `env`
- `inputs` also forwarded to launcher input
4. **Cloud POST body** (`packages/deploy/src/modes/cloud.ts:49-57`)
- `body: JSON.stringify({ persona, bundle, ...(inputs && Object.keys.length > 0 ? { inputs } : {}) })`
5. **Tests** (`packages/deploy/src/modes/input-values.test.ts`, `packages/cli/src/deploy-command.test.ts`)
- Parser: single, multiple, malformed → all covered
- Validation: env propagation, undeclared rejection, non-string rejection
- Cloud: live `fetch` capture asserts POST body contains `inputs: { TOPIC: 'Deploy v1' }`
- Dev launcher: end-to-end child process observes `WORKFORCE_INPUT_TOPIC`/`WORKFORCE_INPUT_REGION` in env
6. **Spec doc** (`docs/plans/deploy-v1.md:188-190, 289, 295`) — `--input` flag listed in CLI surface and §3.8 normative paragraph.
All five acceptance bullets are satisfied with both implementation and test coverage. The undeclared-key error message format matches the test regex (`Unknown input 'UNKNOWN'; persona declares: TOPIC, REGION`).
SIGNOFF_FINAL: COMPLETE Track-I

Final gate (typecheck + tests)

FINAL_I_TSC=0
FINAL_I_TESTS=0
> workforce@0.1.0 typecheck /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> corepack pnpm -r typecheck && corepack pnpm run typecheck:examples
Scope: 8 of 9 workspace projects
packages/daytona-runner typecheck$ tsc -p tsconfig.json --noEmit
packages/persona-kit typecheck$ tsc -p tsconfig.json --noEmit
packages/daytona-runner typecheck: Done
packages/persona-kit typecheck: Done
packages/runtime typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck: Done
packages/runtime typecheck: Done
packages/deploy typecheck$ tsc -p tsconfig.json --noEmit
packages/deploy typecheck: Done
packages/cli typecheck$ tsc -p tsconfig.json --noEmit
packages/cli typecheck: Done
packages/agentworkforce typecheck$ node --check bin/agentworkforce.js
packages/agentworkforce typecheck: Done
> workforce@0.1.0 typecheck:examples /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> tsc -p examples/tsconfig.json --noEmit
packages/cli test: # Subtest: computeTuiView: matches mode honors visibleCap
packages/cli test: ok 166 - computeTuiView: matches mode honors visibleCap
packages/cli test: ---
packages/cli test: duration_ms: 0.033
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: # Subtest: loadRecents returns [] when the file is absent or corrupt
packages/cli test: ok 167 - loadRecents returns [] when the file is absent or corrupt
packages/cli test: ---
packages/cli test: duration_ms: 0.35175
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: 1..167
packages/cli test: # tests 167
packages/cli test: # suites 0
packages/cli test: # pass 167
packages/cli test: # fail 0
packages/cli test: # cancelled 0
packages/cli test: # skipped 0
packages/cli test: # todo 0
packages/cli test: # duration_ms 39466.787541
packages/cli test: Done
packages/agentworkforce test$ node --check bin/agentworkforce.js && node --test test/*.test.js
packages/agentworkforce test: TAP version 13
packages/agentworkforce test: # Subtest: agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ok 1 - agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ---
packages/agentworkforce test: duration_ms: 87.809666
packages/agentworkforce test: type: 'test'
packages/agentworkforce test: ...
packages/agentworkforce test: 1..1
packages/agentworkforce test: # tests 1
packages/agentworkforce test: # suites 0
packages/agentworkforce test: # pass 1
packages/agentworkforce test: # fail 0
packages/agentworkforce test: # cancelled 0
packages/agentworkforce test: # skipped 0
packages/agentworkforce test: # todo 0
packages/agentworkforce test: # duration_ms 193.364041
packages/agentworkforce test: Done

Self-reflection report

REFLECT_GAPS:
- "Update persona spec docs in `docs/plans/deploy-v1.md` §3 to mention `--input` as the deploy-time override mechanism." — MISSING. `docs/plans/deploy-v1.md` has zero matches for `--input` / `input` / `override`; the file is unchanged in this diff.
- Test bullet "Single `--input` parses and forwards." — MISSING. No test files added/modified in the diff (only `cli.ts`, `deploy/src/index.ts`, `modes/cloud.ts`, `types.ts`); no new vitest cases under `packages/cli` or `packages/deploy`.
- Test bullet "Multiple `--input` flags accumulate." — MISSING. No tests added covering `parseDeployInputFlags` in `packages/cli/src/cli.ts:3771`.
- Test bullet "Malformed flag (`--input foo`) → clean error." — MISSING. `expectDeployInputValue` / `parseDeployInputValue` (cli.ts:3795/3803) untested.
- Test bullet "Undeclared input key → clean error citing persona's declared inputs." — MISSING. `validateDeployInputs` in `packages/deploy/src/index.ts:96` has no test asserting the `Unknown input '<key>'; persona declares: …` message.
- Test bullet "`--mode dev` env vars actually reach the child process." — MISSING. No test asserts `WORKFORCE_INPUT_<KEY>` makes it into the dev launcher's child process env via `wrapLauncher` (`packages/deploy/src/index.ts:124`).
- Test bullet "`--mode cloud` POST body includes the `inputs` field." — MISSING. `postCloudDeployment` (`packages/deploy/src/modes/cloud.ts:36`) has no test verifying the body contains `inputs`.
- Implementation bullet "Plumb through `packages/deploy/src/index.ts`'s `deploy()` function as `DeployOptions.inputs?: Record<string, string>`." — PARTIAL. The type is added (`types.ts:24`) and `deploy()` reads `opts.inputs`, but the CLI does NOT pass `opts.inputs` through `runDeploy` — it sets `process.env.WORKFORCE_DEPLOY_INPUTS_JSON` in `cli.ts:3745` and the new `deploy()` wrapper reads it back from env (`index.ts:67`). Programmatic SDK callers using `DeployOptions.inputs` are covered; CLI flow is a roundabout env-var handoff rather than direct plumbing.
- Validation strength: spec says "Value must be a string (basic type check; persona-kit may add more later)." — PARTIAL/redundant. `validateDeployInputs` checks `typeof value !== 'string'` but `inputs` is already typed `Record<string,string>` and the CLI always assigns strings (cli.ts:3808), so the check is unreachable in practice. No declared-but-required-missing handling here (that's Track F's runtime job, so acceptable).
Summary: implementation core is in place across CLI parsing, `DeployOptions.inputs`, validation, and forwarding to all three modes (dev/sandbox env, cloud POST body). The notable gaps are: zero tests added (six explicit test bullets unmet), `docs/plans/deploy-v1.md §3` not updated, and the CLI→`deploy()` plumbing routes through an env-var shim instead of a direct `opts.inputs` pass.

Known gaps after this PR

⚠️Memory is not wired. is a stub in v1; see § Loud hole. Memory wiring lands in a follow-up workflow (not yet specced).

⚠️M3 destroy/list CLI commands not implemented. Separate workflow.

⚠️ ** not on npm** under scope. Handled by a separate agent per platform-team OIDC setup; not blocking morning state because cloud consumes via workspace ref.

Co-Authored-By: Ricky deploy-v1 schema cascade noreply@agentworkforce.com

@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 162e8328-e312-4761-8d57-8ee946ca7be2

📥 Commits

Reviewing files that changed from the base of the PR and between 77660a0 and 8fb4518.

📒 Files selected for processing (2)
  • packages/deploy/src/deploy.ts
  • packages/deploy/src/modes/cloud.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/deploy/src/modes/cloud.ts

📝 Walkthrough

Walkthrough

This PR implements deploy-time persona input overrides via repeatable --input KEY=value CLI flags. Inputs are validated against persona schemas, injected into runners as WORKFORCE_INPUT_<KEY> environment variables, and included in cloud deployment API requests.

Changes

Deploy Input Overrides Feature

Layer / File(s)Summary
Input type contracts
packages/deploy/src/types.ts
DeployOptions adds optional inputs: Record<string,string>; ModeLaunchInput adds inputs and cloudUrl for mode launchers.
CLI input flag parsing
packages/cli/src/deploy-command.ts, packages/cli/src/deploy-command.test.ts
parseDeployArgs recognizes repeatable --input KEY=value / --input=<key>=<value>, validates format, accumulates into inputs, and returns in DeployOptions. Tests cover single/multiple flags and malformed input exit behavior.
Feature specification and design
docs/plans/deploy-v1.md
Docs add "Deploy-time persona inputs" and update CLI usage and deploy flow to describe validation, env var naming, and cloud payload behavior.
Deploy orchestration and input validation
packages/deploy/src/index.ts
New exported deploy wrapper performs preflightPersona, validates opts.inputs against persona-declared keys, rejects unknown/non-string values, and wraps mode launchers to inject WORKFORCE_INPUT_<KEY> env vars and inputs payloads.
Cloud deployment with input support
packages/deploy/src/modes/cloud.ts
Cloud launcher now POSTs deployments to ${cloudUrl}/api/v1/workspaces/:id/deployments with persona, bundle, parsed package.json, and optional inputs; enforces 30s timeout, parses response, logs status, and maps status to exit code.
Deploy callsite forwarding
packages/deploy/src/deploy.ts
deploy forwards cloudUrl into launcher.launch when opts.cloudUrl is set.
End-to-end input integration tests
packages/deploy/src/modes/input-values.test.ts
Tests cover forwarding of validated inputs into dev launcher env and payloads, child-runner env observation, unknown-key and non-string rejections, and that cloud POST includes inputs.

Sequence Diagram

sequenceDiagram
participant CLI as parseDeployArgs
participant Deploy as deploy
participant Persona as preflightPersona
participant Validator as validateDeployInputs
participant Wrapper as wrapInputResolvers
participant Launcher as dev/sandbox/cloudLauncher
participant Cloud as Cloud API
CLI->>Deploy: deploy(opts with inputs)
Deploy->>Persona: preflightPersona(personaPath)
Deploy->>Validator: validateDeployInputs(inputs, persona)
Validator-->>Deploy: validated inputs
Deploy->>Wrapper: wrapInputResolvers(validated inputs, cloudUrl)
Wrapper->>Launcher: launch(input {inputs, env, cloudUrl})
Launcher->>Cloud: POST /deployments { persona, bundle, packageJson, inputs? }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hopping flags into a neat little row,
--input whispers where the overrides go,
Validated keys, strings held tight,
Runners wake with envs alight,
Cloud POST sings the persona's glow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 5.56% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title 'feat(deploy): support deploy input overrides' clearly and concisely summarizes the main change—adding support for deploy-time input overrides via CLI flags.
Description check✅ PassedThe description is detailed and directly related to the changeset, covering spec references, implementation verification, test coverage, and known gaps.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/deploy-input-flags

Comment @coderabbitai help to get the list of available commands and usage tips.

@khaliqgant
khaliqgant marked this pull request as ready for review May 13, 2026 04:49

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/deploy/src/modes/cloud.ts (1)

9-22: ⚡ Quick win

Update the launcher docblock to match current behavior.

The header comment still says cloud mode is unavailable and describes multipart + polling, but the implementation now does a JSON POST and returns immediately.

🤖 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/deploy/src/modes/cloud.ts` around lines 9 - 22, The top docblock in
packages/deploy/src/modes/cloud.ts is outdated: update the comment for `--mode
cloud` to remove the multipart/polling description (steps 1–4) and explicitly
describe the current behavior: the CLI performs a single JSON POST to `POST
/api/v1/workspaces/:id/deployments` with the persona and bundle, the server
returns immediately, and the function returns a deployment handle without
polling; adjust wording to reflect that cloud deploys return immediately and
mention how stop() on the returned handle behaves (e.g., issues a DELETE) so the
docblock matches the implementation.
🤖 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 `@packages/deploy/src/modes/cloud.ts`:
- Around line 41-59: The fetch POST to
`${cloudUrl}/api/v1/workspaces/.../deployments` has no timeout; wrap the request
with an AbortController: create an AbortController before calling fetch, set a
timer (e.g. with setTimeout) that calls controller.abort() after a chosen
timeout, pass controller.signal in the fetch options, and clear the timer once
fetch resolves or throws; update the block that builds the request body
(references: cloudUrl, input, workspaceToken, readFile) to include the signal
and ensure any AbortError is handled/propagated appropriately so `workforce
deploy` cannot hang indefinitely.
---
Nitpick comments:
In `@packages/deploy/src/modes/cloud.ts`:
- Around line 9-22: The top docblock in packages/deploy/src/modes/cloud.ts is
outdated: update the comment for `--mode cloud` to remove the multipart/polling
description (steps 1–4) and explicitly describe the current behavior: the CLI
performs a single JSON POST to `POST /api/v1/workspaces/:id/deployments` with
the persona and bundle, the server returns immediately, and the function returns
a deployment handle without polling; adjust wording to reflect that cloud
deploys return immediately and mention how stop() on the returned handle behaves
(e.g., issues a DELETE) so the docblock matches the implementation.
🪄 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: 4b91f72e-dccb-4cd2-9744-1695b6274f0a

📥 Commits

Reviewing files that changed from the base of the PR and between 19ebbee and 77660a0.

📒 Files selected for processing (7)
  • docs/plans/deploy-v1.md
  • packages/cli/src/deploy-command.test.ts
  • packages/cli/src/deploy-command.ts
  • packages/deploy/src/index.ts
  • packages/deploy/src/modes/cloud.ts
  • packages/deploy/src/modes/input-values.test.ts
  • packages/deploy/src/types.ts

Comment threadpackages/deploy/src/modes/cloud.ts Outdated

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +53 to +54
const inputs = opts.inputs && Object.keys(opts.inputs).length > 0 ? opts.inputs : undefined;
if (!inputs) return deployInternal(opts, resolvers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 --cloud-url CLI flag silently ignored when no --input flags are provided

The new deploy() wrapper in index.ts only forwards opts.cloudUrl to the cloud launcher through wrapLauncher (line 110), which is only invoked when inputs are present (line 58). When there are no inputs, the wrapper calls deployInternal(opts, resolvers) directly, and deployInternal at packages/deploy/src/deploy.ts:177-183 never passes cloudUrl in the launcher.launch(...) call. As a result, the cloud launcher at packages/deploy/src/modes/cloud.ts:25 sees input.cloudUrl as undefined and falls back to process.env.WORKFORCE_CLOUD_URL. This means workforce deploy persona.json --mode cloud --cloud-url https://custom.example.com (without --input) silently ignores --cloud-url, and if WORKFORCE_CLOUD_URL env var is not set, the deployment fails with the "not yet available" error despite a valid cloud URL being specified.

Prompt for agents
The deploy() wrapper in packages/deploy/src/index.ts only wraps launchers (to inject cloudUrl into ModeLaunchInput) when inputs are present. When no inputs are provided, it calls deployInternal directly, and deployInternal in packages/deploy/src/deploy.ts:177-183 does not pass opts.cloudUrl to the launcher.
The cloud launcher (packages/deploy/src/modes/cloud.ts:25) reads input.cloudUrl as its primary source, falling back to env var. So --cloud-url is silently lost in the no-inputs path.
Two possible approaches:
1. Have deployInternal (deploy.ts) pass cloudUrl to launcher.launch() from opts.cloudUrl, so it always reaches launchers regardless of the wrapper.
2. Ensure the deploy() wrapper in index.ts also wraps launchers for cloudUrl when opts.cloudUrl is set, not just when inputs are present. This would mean the wrapper calls wrapInputResolvers even when inputs are empty but cloudUrl is present.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Pass opts.cloudUrl through launcher.launch in deployInternal so
--cloud-url reaches the cloud launcher even when --input is not used.
- Wrap the cloud deploy fetch in an AbortController with a 30s timeout
so a stalled network request can no longer hang `workforce deploy`
indefinitely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit 47dd049 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the feat/deploy-input-flags branch May 13, 2026 08:17
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(deploy): support deploy input overrides - #101

Merged
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags
May 13, 2026
Merged

feat(deploy): support deploy input overrides#101
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

  • Track I: Track I — Deploy CLI flags
  • Final signoff: COMPLETE.
  • Eligible for auto-merge when CI green and upstream deps merged.

Spec reference

Source spec: workforce/docs/plans/deploy-v1-schema-cascade-spec.md

Track section: Track I — Deploy CLI flags

Final signoff

Verifying acceptance bullets against actual files:
**Spec (deploy-v1.md §3.8, §5 flag list):**
- Repeatable `--input KEY=value` flags ✅
- CLI rejects undeclared keys ✅
- Requires string values ✅
- dev + sandbox: inject `WORKFORCE_INPUT_<KEY>` env ✅
- cloud: send as `inputs` in POST body ✅
**Verified files:**
1. **CLI parser** (`packages/cli/src/deploy-command.ts:86, 109, 136-181`)
- `--input` documented in DEPLOY_USAGE
- Accepts both `--input KEY=val` (sep arg) and `--input=KEY=val` (joined) — repeatable via accumulator
- Malformed input dies with clean error (`expected <key>=<value>`)
2. **Validation** (`packages/deploy/src/index.ts:61-75`)
- `validateDeployInputs` checks string type → `Input '${key}' must be a string`
- Rejects undeclared keys → `Unknown input '${key}'; persona declares: ${list}`
- Runs against parsed persona's `inputs` declaration via `preflightPersona`
3. **Env injection — dev & sandbox** (`packages/deploy/src/index.ts:96-120`)
- `wrapLauncher` wraps `dev`, `sandbox`, AND `cloud` launchers
- `toInputEnv` prefixes every key with `WORKFORCE_INPUT_` and merges into `env`
- `inputs` also forwarded to launcher input
4. **Cloud POST body** (`packages/deploy/src/modes/cloud.ts:49-57`)
- `body: JSON.stringify({ persona, bundle, ...(inputs && Object.keys.length > 0 ? { inputs } : {}) })`
5. **Tests** (`packages/deploy/src/modes/input-values.test.ts`, `packages/cli/src/deploy-command.test.ts`)
- Parser: single, multiple, malformed → all covered
- Validation: env propagation, undeclared rejection, non-string rejection
- Cloud: live `fetch` capture asserts POST body contains `inputs: { TOPIC: 'Deploy v1' }`
- Dev launcher: end-to-end child process observes `WORKFORCE_INPUT_TOPIC`/`WORKFORCE_INPUT_REGION` in env
6. **Spec doc** (`docs/plans/deploy-v1.md:188-190, 289, 295`) — `--input` flag listed in CLI surface and §3.8 normative paragraph.
All five acceptance bullets are satisfied with both implementation and test coverage. The undeclared-key error message format matches the test regex (`Unknown input 'UNKNOWN'; persona declares: TOPIC, REGION`).
SIGNOFF_FINAL: COMPLETE Track-I

Final gate (typecheck + tests)

FINAL_I_TSC=0
FINAL_I_TESTS=0
> workforce@0.1.0 typecheck /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> corepack pnpm -r typecheck && corepack pnpm run typecheck:examples
Scope: 8 of 9 workspace projects
packages/daytona-runner typecheck$ tsc -p tsconfig.json --noEmit
packages/persona-kit typecheck$ tsc -p tsconfig.json --noEmit
packages/daytona-runner typecheck: Done
packages/persona-kit typecheck: Done
packages/runtime typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck: Done
packages/runtime typecheck: Done
packages/deploy typecheck$ tsc -p tsconfig.json --noEmit
packages/deploy typecheck: Done
packages/cli typecheck$ tsc -p tsconfig.json --noEmit
packages/cli typecheck: Done
packages/agentworkforce typecheck$ node --check bin/agentworkforce.js
packages/agentworkforce typecheck: Done
> workforce@0.1.0 typecheck:examples /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> tsc -p examples/tsconfig.json --noEmit
packages/cli test: # Subtest: computeTuiView: matches mode honors visibleCap
packages/cli test: ok 166 - computeTuiView: matches mode honors visibleCap
packages/cli test: ---
packages/cli test: duration_ms: 0.033
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: # Subtest: loadRecents returns [] when the file is absent or corrupt
packages/cli test: ok 167 - loadRecents returns [] when the file is absent or corrupt
packages/cli test: ---
packages/cli test: duration_ms: 0.35175
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: 1..167
packages/cli test: # tests 167
packages/cli test: # suites 0
packages/cli test: # pass 167
packages/cli test: # fail 0
packages/cli test: # cancelled 0
packages/cli test: # skipped 0
packages/cli test: # todo 0
packages/cli test: # duration_ms 39466.787541
packages/cli test: Done
packages/agentworkforce test$ node --check bin/agentworkforce.js && node --test test/*.test.js
packages/agentworkforce test: TAP version 13
packages/agentworkforce test: # Subtest: agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ok 1 - agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ---
packages/agentworkforce test: duration_ms: 87.809666
packages/agentworkforce test: type: 'test'
packages/agentworkforce test: ...
packages/agentworkforce test: 1..1
packages/agentworkforce test: # tests 1
packages/agentworkforce test: # suites 0
packages/agentworkforce test: # pass 1
packages/agentworkforce test: # fail 0
packages/agentworkforce test: # cancelled 0
packages/agentworkforce test: # skipped 0
packages/agentworkforce test: # todo 0
packages/agentworkforce test: # duration_ms 193.364041
packages/agentworkforce test: Done

Self-reflection report

REFLECT_GAPS:
- "Update persona spec docs in `docs/plans/deploy-v1.md` §3 to mention `--input` as the deploy-time override mechanism." — MISSING. `docs/plans/deploy-v1.md` has zero matches for `--input` / `input` / `override`; the file is unchanged in this diff.
- Test bullet "Single `--input` parses and forwards." — MISSING. No test files added/modified in the diff (only `cli.ts`, `deploy/src/index.ts`, `modes/cloud.ts`, `types.ts`); no new vitest cases under `packages/cli` or `packages/deploy`.
- Test bullet "Multiple `--input` flags accumulate." — MISSING. No tests added covering `parseDeployInputFlags` in `packages/cli/src/cli.ts:3771`.
- Test bullet "Malformed flag (`--input foo`) → clean error." — MISSING. `expectDeployInputValue` / `parseDeployInputValue` (cli.ts:3795/3803) untested.
- Test bullet "Undeclared input key → clean error citing persona's declared inputs." — MISSING. `validateDeployInputs` in `packages/deploy/src/index.ts:96` has no test asserting the `Unknown input '<key>'; persona declares: …` message.
- Test bullet "`--mode dev` env vars actually reach the child process." — MISSING. No test asserts `WORKFORCE_INPUT_<KEY>` makes it into the dev launcher's child process env via `wrapLauncher` (`packages/deploy/src/index.ts:124`).
- Test bullet "`--mode cloud` POST body includes the `inputs` field." — MISSING. `postCloudDeployment` (`packages/deploy/src/modes/cloud.ts:36`) has no test verifying the body contains `inputs`.
- Implementation bullet "Plumb through `packages/deploy/src/index.ts`'s `deploy()` function as `DeployOptions.inputs?: Record<string, string>`." — PARTIAL. The type is added (`types.ts:24`) and `deploy()` reads `opts.inputs`, but the CLI does NOT pass `opts.inputs` through `runDeploy` — it sets `process.env.WORKFORCE_DEPLOY_INPUTS_JSON` in `cli.ts:3745` and the new `deploy()` wrapper reads it back from env (`index.ts:67`). Programmatic SDK callers using `DeployOptions.inputs` are covered; CLI flow is a roundabout env-var handoff rather than direct plumbing.
- Validation strength: spec says "Value must be a string (basic type check; persona-kit may add more later)." — PARTIAL/redundant. `validateDeployInputs` checks `typeof value !== 'string'` but `inputs` is already typed `Record<string,string>` and the CLI always assigns strings (cli.ts:3808), so the check is unreachable in practice. No declared-but-required-missing handling here (that's Track F's runtime job, so acceptable).
Summary: implementation core is in place across CLI parsing, `DeployOptions.inputs`, validation, and forwarding to all three modes (dev/sandbox env, cloud POST body). The notable gaps are: zero tests added (six explicit test bullets unmet), `docs/plans/deploy-v1.md §3` not updated, and the CLI→`deploy()` plumbing routes through an env-var shim instead of a direct `opts.inputs` pass.

Known gaps after this PR

⚠️Memory is not wired. is a stub in v1; see § Loud hole. Memory wiring lands in a follow-up workflow (not yet specced).

⚠️M3 destroy/list CLI commands not implemented. Separate workflow.

⚠️ ** not on npm** under scope. Handled by a separate agent per platform-team OIDC setup; not blocking morning state because cloud consumes via workspace ref.

Co-Authored-By: Ricky deploy-v1 schema cascade noreply@agentworkforce.com

@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 162e8328-e312-4761-8d57-8ee946ca7be2

📥 Commits

Reviewing files that changed from the base of the PR and between 77660a0 and 8fb4518.

📒 Files selected for processing (2)
  • packages/deploy/src/deploy.ts
  • packages/deploy/src/modes/cloud.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/deploy/src/modes/cloud.ts

📝 Walkthrough

Walkthrough

This PR implements deploy-time persona input overrides via repeatable --input KEY=value CLI flags. Inputs are validated against persona schemas, injected into runners as WORKFORCE_INPUT_<KEY> environment variables, and included in cloud deployment API requests.

Changes

Deploy Input Overrides Feature

Layer / File(s)Summary
Input type contracts
packages/deploy/src/types.ts
DeployOptions adds optional inputs: Record<string,string>; ModeLaunchInput adds inputs and cloudUrl for mode launchers.
CLI input flag parsing
packages/cli/src/deploy-command.ts, packages/cli/src/deploy-command.test.ts
parseDeployArgs recognizes repeatable --input KEY=value / --input=<key>=<value>, validates format, accumulates into inputs, and returns in DeployOptions. Tests cover single/multiple flags and malformed input exit behavior.
Feature specification and design
docs/plans/deploy-v1.md
Docs add "Deploy-time persona inputs" and update CLI usage and deploy flow to describe validation, env var naming, and cloud payload behavior.
Deploy orchestration and input validation
packages/deploy/src/index.ts
New exported deploy wrapper performs preflightPersona, validates opts.inputs against persona-declared keys, rejects unknown/non-string values, and wraps mode launchers to inject WORKFORCE_INPUT_<KEY> env vars and inputs payloads.
Cloud deployment with input support
packages/deploy/src/modes/cloud.ts
Cloud launcher now POSTs deployments to ${cloudUrl}/api/v1/workspaces/:id/deployments with persona, bundle, parsed package.json, and optional inputs; enforces 30s timeout, parses response, logs status, and maps status to exit code.
Deploy callsite forwarding
packages/deploy/src/deploy.ts
deploy forwards cloudUrl into launcher.launch when opts.cloudUrl is set.
End-to-end input integration tests
packages/deploy/src/modes/input-values.test.ts
Tests cover forwarding of validated inputs into dev launcher env and payloads, child-runner env observation, unknown-key and non-string rejections, and that cloud POST includes inputs.

Sequence Diagram

sequenceDiagram
participant CLI as parseDeployArgs
participant Deploy as deploy
participant Persona as preflightPersona
participant Validator as validateDeployInputs
participant Wrapper as wrapInputResolvers
participant Launcher as dev/sandbox/cloudLauncher
participant Cloud as Cloud API
CLI->>Deploy: deploy(opts with inputs)
Deploy->>Persona: preflightPersona(personaPath)
Deploy->>Validator: validateDeployInputs(inputs, persona)
Validator-->>Deploy: validated inputs
Deploy->>Wrapper: wrapInputResolvers(validated inputs, cloudUrl)
Wrapper->>Launcher: launch(input {inputs, env, cloudUrl})
Launcher->>Cloud: POST /deployments { persona, bundle, packageJson, inputs? }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hopping flags into a neat little row,
--input whispers where the overrides go,
Validated keys, strings held tight,
Runners wake with envs alight,
Cloud POST sings the persona's glow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 5.56% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title 'feat(deploy): support deploy input overrides' clearly and concisely summarizes the main change—adding support for deploy-time input overrides via CLI flags.
Description check✅ PassedThe description is detailed and directly related to the changeset, covering spec references, implementation verification, test coverage, and known gaps.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/deploy-input-flags

Comment @coderabbitai help to get the list of available commands and usage tips.

@khaliqgant
khaliqgant marked this pull request as ready for review May 13, 2026 04:49

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/deploy/src/modes/cloud.ts (1)

9-22: ⚡ Quick win

Update the launcher docblock to match current behavior.

The header comment still says cloud mode is unavailable and describes multipart + polling, but the implementation now does a JSON POST and returns immediately.

🤖 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/deploy/src/modes/cloud.ts` around lines 9 - 22, The top docblock in
packages/deploy/src/modes/cloud.ts is outdated: update the comment for `--mode
cloud` to remove the multipart/polling description (steps 1–4) and explicitly
describe the current behavior: the CLI performs a single JSON POST to `POST
/api/v1/workspaces/:id/deployments` with the persona and bundle, the server
returns immediately, and the function returns a deployment handle without
polling; adjust wording to reflect that cloud deploys return immediately and
mention how stop() on the returned handle behaves (e.g., issues a DELETE) so the
docblock matches the implementation.
🤖 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 `@packages/deploy/src/modes/cloud.ts`:
- Around line 41-59: The fetch POST to
`${cloudUrl}/api/v1/workspaces/.../deployments` has no timeout; wrap the request
with an AbortController: create an AbortController before calling fetch, set a
timer (e.g. with setTimeout) that calls controller.abort() after a chosen
timeout, pass controller.signal in the fetch options, and clear the timer once
fetch resolves or throws; update the block that builds the request body
(references: cloudUrl, input, workspaceToken, readFile) to include the signal
and ensure any AbortError is handled/propagated appropriately so `workforce
deploy` cannot hang indefinitely.
---
Nitpick comments:
In `@packages/deploy/src/modes/cloud.ts`:
- Around line 9-22: The top docblock in packages/deploy/src/modes/cloud.ts is
outdated: update the comment for `--mode cloud` to remove the multipart/polling
description (steps 1–4) and explicitly describe the current behavior: the CLI
performs a single JSON POST to `POST /api/v1/workspaces/:id/deployments` with
the persona and bundle, the server returns immediately, and the function returns
a deployment handle without polling; adjust wording to reflect that cloud
deploys return immediately and mention how stop() on the returned handle behaves
(e.g., issues a DELETE) so the docblock matches the implementation.
🪄 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: 4b91f72e-dccb-4cd2-9744-1695b6274f0a

📥 Commits

Reviewing files that changed from the base of the PR and between 19ebbee and 77660a0.

📒 Files selected for processing (7)
  • docs/plans/deploy-v1.md
  • packages/cli/src/deploy-command.test.ts
  • packages/cli/src/deploy-command.ts
  • packages/deploy/src/index.ts
  • packages/deploy/src/modes/cloud.ts
  • packages/deploy/src/modes/input-values.test.ts
  • packages/deploy/src/types.ts

Comment threadpackages/deploy/src/modes/cloud.ts Outdated

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +53 to +54
const inputs = opts.inputs && Object.keys(opts.inputs).length > 0 ? opts.inputs : undefined;
if (!inputs) return deployInternal(opts, resolvers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 --cloud-url CLI flag silently ignored when no --input flags are provided

The new deploy() wrapper in index.ts only forwards opts.cloudUrl to the cloud launcher through wrapLauncher (line 110), which is only invoked when inputs are present (line 58). When there are no inputs, the wrapper calls deployInternal(opts, resolvers) directly, and deployInternal at packages/deploy/src/deploy.ts:177-183 never passes cloudUrl in the launcher.launch(...) call. As a result, the cloud launcher at packages/deploy/src/modes/cloud.ts:25 sees input.cloudUrl as undefined and falls back to process.env.WORKFORCE_CLOUD_URL. This means workforce deploy persona.json --mode cloud --cloud-url https://custom.example.com (without --input) silently ignores --cloud-url, and if WORKFORCE_CLOUD_URL env var is not set, the deployment fails with the "not yet available" error despite a valid cloud URL being specified.

Prompt for agents
The deploy() wrapper in packages/deploy/src/index.ts only wraps launchers (to inject cloudUrl into ModeLaunchInput) when inputs are present. When no inputs are provided, it calls deployInternal directly, and deployInternal in packages/deploy/src/deploy.ts:177-183 does not pass opts.cloudUrl to the launcher.
The cloud launcher (packages/deploy/src/modes/cloud.ts:25) reads input.cloudUrl as its primary source, falling back to env var. So --cloud-url is silently lost in the no-inputs path.
Two possible approaches:
1. Have deployInternal (deploy.ts) pass cloudUrl to launcher.launch() from opts.cloudUrl, so it always reaches launchers regardless of the wrapper.
2. Ensure the deploy() wrapper in index.ts also wraps launchers for cloudUrl when opts.cloudUrl is set, not just when inputs are present. This would mean the wrapper calls wrapInputResolvers even when inputs are empty but cloudUrl is present.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Pass opts.cloudUrl through launcher.launch in deployInternal so
--cloud-url reaches the cloud launcher even when --input is not used.
- Wrap the cloud deploy fetch in an AbortController with a 30s timeout
so a stalled network request can no longer hang `workforce deploy`
indefinitely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit 47dd049 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the feat/deploy-input-flags branch May 13, 2026 08:17
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(deploy): support deploy input overrides - #101

Merged
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags
May 13, 2026
Merged

feat(deploy): support deploy input overrides#101
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

  • Track I: Track I — Deploy CLI flags
  • Final signoff: COMPLETE.
  • Eligible for auto-merge when CI green and upstream deps merged.

Spec reference

Source spec: workforce/docs/plans/deploy-v1-schema-cascade-spec.md

Track section: Track I — Deploy CLI flags

Final signoff

Verifying acceptance bullets against actual files:
**Spec (deploy-v1.md §3.8, §5 flag list):**
- Repeatable `--input KEY=value` flags ✅
- CLI rejects undeclared keys ✅
- Requires string values ✅
- dev + sandbox: inject `WORKFORCE_INPUT_<KEY>` env ✅
- cloud: send as `inputs` in POST body ✅
**Verified files:**
1. **CLI parser** (`packages/cli/src/deploy-command.ts:86, 109, 136-181`)
- `--input` documented in DEPLOY_USAGE
- Accepts both `--input KEY=val` (sep arg) and `--input=KEY=val` (joined) — repeatable via accumulator
- Malformed input dies with clean error (`expected <key>=<value>`)
2. **Validation** (`packages/deploy/src/index.ts:61-75`)
- `validateDeployInputs` checks string type → `Input '${key}' must be a string`
- Rejects undeclared keys → `Unknown input '${key}'; persona declares: ${list}`
- Runs against parsed persona's `inputs` declaration via `preflightPersona`
3. **Env injection — dev & sandbox** (`packages/deploy/src/index.ts:96-120`)
- `wrapLauncher` wraps `dev`, `sandbox`, AND `cloud` launchers
- `toInputEnv` prefixes every key with `WORKFORCE_INPUT_` and merges into `env`
- `inputs` also forwarded to launcher input
4. **Cloud POST body** (`packages/deploy/src/modes/cloud.ts:49-57`)
- `body: JSON.stringify({ persona, bundle, ...(inputs && Object.keys.length > 0 ? { inputs } : {}) })`
5. **Tests** (`packages/deploy/src/modes/input-values.test.ts`, `packages/cli/src/deploy-command.test.ts`)
- Parser: single, multiple, malformed → all covered
- Validation: env propagation, undeclared rejection, non-string rejection
- Cloud: live `fetch` capture asserts POST body contains `inputs: { TOPIC: 'Deploy v1' }`
- Dev launcher: end-to-end child process observes `WORKFORCE_INPUT_TOPIC`/`WORKFORCE_INPUT_REGION` in env
6. **Spec doc** (`docs/plans/deploy-v1.md:188-190, 289, 295`) — `--input` flag listed in CLI surface and §3.8 normative paragraph.
All five acceptance bullets are satisfied with both implementation and test coverage. The undeclared-key error message format matches the test regex (`Unknown input 'UNKNOWN'; persona declares: TOPIC, REGION`).
SIGNOFF_FINAL: COMPLETE Track-I

Final gate (typecheck + tests)

FINAL_I_TSC=0
FINAL_I_TESTS=0
> workforce@0.1.0 typecheck /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> corepack pnpm -r typecheck && corepack pnpm run typecheck:examples
Scope: 8 of 9 workspace projects
packages/daytona-runner typecheck$ tsc -p tsconfig.json --noEmit
packages/persona-kit typecheck$ tsc -p tsconfig.json --noEmit
packages/daytona-runner typecheck: Done
packages/persona-kit typecheck: Done
packages/runtime typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck: Done
packages/runtime typecheck: Done
packages/deploy typecheck$ tsc -p tsconfig.json --noEmit
packages/deploy typecheck: Done
packages/cli typecheck$ tsc -p tsconfig.json --noEmit
packages/cli typecheck: Done
packages/agentworkforce typecheck$ node --check bin/agentworkforce.js
packages/agentworkforce typecheck: Done
> workforce@0.1.0 typecheck:examples /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> tsc -p examples/tsconfig.json --noEmit
packages/cli test: # Subtest: computeTuiView: matches mode honors visibleCap
packages/cli test: ok 166 - computeTuiView: matches mode honors visibleCap
packages/cli test: ---
packages/cli test: duration_ms: 0.033
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: # Subtest: loadRecents returns [] when the file is absent or corrupt
packages/cli test: ok 167 - loadRecents returns [] when the file is absent or corrupt
packages/cli test: ---
packages/cli test: duration_ms: 0.35175
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: 1..167
packages/cli test: # tests 167
packages/cli test: # suites 0
packages/cli test: # pass 167
packages/cli test: # fail 0
packages/cli test: # cancelled 0
packages/cli test: # skipped 0
packages/cli test: # todo 0
packages/cli test: # duration_ms 39466.787541
packages/cli test: Done
packages/agentworkforce test$ node --check bin/agentworkforce.js && node --test test/*.test.js
packages/agentworkforce test: TAP version 13
packages/agentworkforce test: # Subtest: agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ok 1 - agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ---
packages/agentworkforce test: duration_ms: 87.809666
packages/agentworkforce test: type: 'test'
packages/agentworkforce test: ...
packages/agentworkforce test: 1..1
packages/agentworkforce test: # tests 1
packages/agentworkforce test: # suites 0
packages/agentworkforce test: # pass 1
packages/agentworkforce test: # fail 0
packages/agentworkforce test: # cancelled 0
packages/agentworkforce test: # skipped 0
packages/agentworkforce test: # todo 0
packages/agentworkforce test: # duration_ms 193.364041
packages/agentworkforce test: Done

Self-reflection report

REFLECT_GAPS:
- "Update persona spec docs in `docs/plans/deploy-v1.md` §3 to mention `--input` as the deploy-time override mechanism." — MISSING. `docs/plans/deploy-v1.md` has zero matches for `--input` / `input` / `override`; the file is unchanged in this diff.
- Test bullet "Single `--input` parses and forwards." — MISSING. No test files added/modified in the diff (only `cli.ts`, `deploy/src/index.ts`, `modes/cloud.ts`, `types.ts`); no new vitest cases under `packages/cli` or `packages/deploy`.
- Test bullet "Multiple `--input` flags accumulate." — MISSING. No tests added covering `parseDeployInputFlags` in `packages/cli/src/cli.ts:3771`.
- Test bullet "Malformed flag (`--input foo`) → clean error." — MISSING. `expectDeployInputValue` / `parseDeployInputValue` (cli.ts:3795/3803) untested.
- Test bullet "Undeclared input key → clean error citing persona's declared inputs." — MISSING. `validateDeployInputs` in `packages/deploy/src/index.ts:96` has no test asserting the `Unknown input '<key>'; persona declares: …` message.
- Test bullet "`--mode dev` env vars actually reach the child process." — MISSING. No test asserts `WORKFORCE_INPUT_<KEY>` makes it into the dev launcher's child process env via `wrapLauncher` (`packages/deploy/src/index.ts:124`).
- Test bullet "`--mode cloud` POST body includes the `inputs` field." — MISSING. `postCloudDeployment` (`packages/deploy/src/modes/cloud.ts:36`) has no test verifying the body contains `inputs`.
- Implementation bullet "Plumb through `packages/deploy/src/index.ts`'s `deploy()` function as `DeployOptions.inputs?: Record<string, string>`." — PARTIAL. The type is added (`types.ts:24`) and `deploy()` reads `opts.inputs`, but the CLI does NOT pass `opts.inputs` through `runDeploy` — it sets `process.env.WORKFORCE_DEPLOY_INPUTS_JSON` in `cli.ts:3745` and the new `deploy()` wrapper reads it back from env (`index.ts:67`). Programmatic SDK callers using `DeployOptions.inputs` are covered; CLI flow is a roundabout env-var handoff rather than direct plumbing.
- Validation strength: spec says "Value must be a string (basic type check; persona-kit may add more later)." — PARTIAL/redundant. `validateDeployInputs` checks `typeof value !== 'string'` but `inputs` is already typed `Record<string,string>` and the CLI always assigns strings (cli.ts:3808), so the check is unreachable in practice. No declared-but-required-missing handling here (that's Track F's runtime job, so acceptable).
Summary: implementation core is in place across CLI parsing, `DeployOptions.inputs`, validation, and forwarding to all three modes (dev/sandbox env, cloud POST body). The notable gaps are: zero tests added (six explicit test bullets unmet), `docs/plans/deploy-v1.md §3` not updated, and the CLI→`deploy()` plumbing routes through an env-var shim instead of a direct `opts.inputs` pass.

Known gaps after this PR

⚠️Memory is not wired. is a stub in v1; see § Loud hole. Memory wiring lands in a follow-up workflow (not yet specced).

⚠️M3 destroy/list CLI commands not implemented. Separate workflow.

⚠️ ** not on npm** under scope. Handled by a separate agent per platform-team OIDC setup; not blocking morning state because cloud consumes via workspace ref.

Co-Authored-By: Ricky deploy-v1 schema cascade noreply@agentworkforce.com

@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 162e8328-e312-4761-8d57-8ee946ca7be2

📥 Commits

Reviewing files that changed from the base of the PR and between 77660a0 and 8fb4518.

📒 Files selected for processing (2)
  • packages/deploy/src/deploy.ts
  • packages/deploy/src/modes/cloud.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/deploy/src/modes/cloud.ts

📝 Walkthrough

Walkthrough

This PR implements deploy-time persona input overrides via repeatable --input KEY=value CLI flags. Inputs are validated against persona schemas, injected into runners as WORKFORCE_INPUT_<KEY> environment variables, and included in cloud deployment API requests.

Changes

Deploy Input Overrides Feature

Layer / File(s)Summary
Input type contracts
packages/deploy/src/types.ts
DeployOptions adds optional inputs: Record<string,string>; ModeLaunchInput adds inputs and cloudUrl for mode launchers.
CLI input flag parsing
packages/cli/src/deploy-command.ts, packages/cli/src/deploy-command.test.ts
parseDeployArgs recognizes repeatable --input KEY=value / --input=<key>=<value>, validates format, accumulates into inputs, and returns in DeployOptions. Tests cover single/multiple flags and malformed input exit behavior.
Feature specification and design
docs/plans/deploy-v1.md
Docs add "Deploy-time persona inputs" and update CLI usage and deploy flow to describe validation, env var naming, and cloud payload behavior.
Deploy orchestration and input validation
packages/deploy/src/index.ts
New exported deploy wrapper performs preflightPersona, validates opts.inputs against persona-declared keys, rejects unknown/non-string values, and wraps mode launchers to inject WORKFORCE_INPUT_<KEY> env vars and inputs payloads.
Cloud deployment with input support
packages/deploy/src/modes/cloud.ts
Cloud launcher now POSTs deployments to ${cloudUrl}/api/v1/workspaces/:id/deployments with persona, bundle, parsed package.json, and optional inputs; enforces 30s timeout, parses response, logs status, and maps status to exit code.
Deploy callsite forwarding
packages/deploy/src/deploy.ts
deploy forwards cloudUrl into launcher.launch when opts.cloudUrl is set.
End-to-end input integration tests
packages/deploy/src/modes/input-values.test.ts
Tests cover forwarding of validated inputs into dev launcher env and payloads, child-runner env observation, unknown-key and non-string rejections, and that cloud POST includes inputs.

Sequence Diagram

sequenceDiagram
participant CLI as parseDeployArgs
participant Deploy as deploy
participant Persona as preflightPersona
participant Validator as validateDeployInputs
participant Wrapper as wrapInputResolvers
participant Launcher as dev/sandbox/cloudLauncher
participant Cloud as Cloud API
CLI->>Deploy: deploy(opts with inputs)
Deploy->>Persona: preflightPersona(personaPath)
Deploy->>Validator: validateDeployInputs(inputs, persona)
Validator-->>Deploy: validated inputs
Deploy->>Wrapper: wrapInputResolvers(validated inputs, cloudUrl)
Wrapper->>Launcher: launch(input {inputs, env, cloudUrl})
Launcher->>Cloud: POST /deployments { persona, bundle, packageJson, inputs? }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hopping flags into a neat little row,
--input whispers where the overrides go,
Validated keys, strings held tight,
Runners wake with envs alight,
Cloud POST sings the persona's glow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 5.56% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title 'feat(deploy): support deploy input overrides' clearly and concisely summarizes the main change—adding support for deploy-time input overrides via CLI flags.
Description check✅ PassedThe description is detailed and directly related to the changeset, covering spec references, implementation verification, test coverage, and known gaps.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/deploy-input-flags

Comment @coderabbitai help to get the list of available commands and usage tips.

@khaliqgant
khaliqgant marked this pull request as ready for review May 13, 2026 04:49

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/deploy/src/modes/cloud.ts (1)

9-22: ⚡ Quick win

Update the launcher docblock to match current behavior.

The header comment still says cloud mode is unavailable and describes multipart + polling, but the implementation now does a JSON POST and returns immediately.

🤖 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/deploy/src/modes/cloud.ts` around lines 9 - 22, The top docblock in
packages/deploy/src/modes/cloud.ts is outdated: update the comment for `--mode
cloud` to remove the multipart/polling description (steps 1–4) and explicitly
describe the current behavior: the CLI performs a single JSON POST to `POST
/api/v1/workspaces/:id/deployments` with the persona and bundle, the server
returns immediately, and the function returns a deployment handle without
polling; adjust wording to reflect that cloud deploys return immediately and
mention how stop() on the returned handle behaves (e.g., issues a DELETE) so the
docblock matches the implementation.
🤖 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 `@packages/deploy/src/modes/cloud.ts`:
- Around line 41-59: The fetch POST to
`${cloudUrl}/api/v1/workspaces/.../deployments` has no timeout; wrap the request
with an AbortController: create an AbortController before calling fetch, set a
timer (e.g. with setTimeout) that calls controller.abort() after a chosen
timeout, pass controller.signal in the fetch options, and clear the timer once
fetch resolves or throws; update the block that builds the request body
(references: cloudUrl, input, workspaceToken, readFile) to include the signal
and ensure any AbortError is handled/propagated appropriately so `workforce
deploy` cannot hang indefinitely.
---
Nitpick comments:
In `@packages/deploy/src/modes/cloud.ts`:
- Around line 9-22: The top docblock in packages/deploy/src/modes/cloud.ts is
outdated: update the comment for `--mode cloud` to remove the multipart/polling
description (steps 1–4) and explicitly describe the current behavior: the CLI
performs a single JSON POST to `POST /api/v1/workspaces/:id/deployments` with
the persona and bundle, the server returns immediately, and the function returns
a deployment handle without polling; adjust wording to reflect that cloud
deploys return immediately and mention how stop() on the returned handle behaves
(e.g., issues a DELETE) so the docblock matches the implementation.
🪄 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: 4b91f72e-dccb-4cd2-9744-1695b6274f0a

📥 Commits

Reviewing files that changed from the base of the PR and between 19ebbee and 77660a0.

📒 Files selected for processing (7)
  • docs/plans/deploy-v1.md
  • packages/cli/src/deploy-command.test.ts
  • packages/cli/src/deploy-command.ts
  • packages/deploy/src/index.ts
  • packages/deploy/src/modes/cloud.ts
  • packages/deploy/src/modes/input-values.test.ts
  • packages/deploy/src/types.ts

Comment threadpackages/deploy/src/modes/cloud.ts Outdated

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +53 to +54
const inputs = opts.inputs && Object.keys(opts.inputs).length > 0 ? opts.inputs : undefined;
if (!inputs) return deployInternal(opts, resolvers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 --cloud-url CLI flag silently ignored when no --input flags are provided

The new deploy() wrapper in index.ts only forwards opts.cloudUrl to the cloud launcher through wrapLauncher (line 110), which is only invoked when inputs are present (line 58). When there are no inputs, the wrapper calls deployInternal(opts, resolvers) directly, and deployInternal at packages/deploy/src/deploy.ts:177-183 never passes cloudUrl in the launcher.launch(...) call. As a result, the cloud launcher at packages/deploy/src/modes/cloud.ts:25 sees input.cloudUrl as undefined and falls back to process.env.WORKFORCE_CLOUD_URL. This means workforce deploy persona.json --mode cloud --cloud-url https://custom.example.com (without --input) silently ignores --cloud-url, and if WORKFORCE_CLOUD_URL env var is not set, the deployment fails with the "not yet available" error despite a valid cloud URL being specified.

Prompt for agents
The deploy() wrapper in packages/deploy/src/index.ts only wraps launchers (to inject cloudUrl into ModeLaunchInput) when inputs are present. When no inputs are provided, it calls deployInternal directly, and deployInternal in packages/deploy/src/deploy.ts:177-183 does not pass opts.cloudUrl to the launcher.
The cloud launcher (packages/deploy/src/modes/cloud.ts:25) reads input.cloudUrl as its primary source, falling back to env var. So --cloud-url is silently lost in the no-inputs path.
Two possible approaches:
1. Have deployInternal (deploy.ts) pass cloudUrl to launcher.launch() from opts.cloudUrl, so it always reaches launchers regardless of the wrapper.
2. Ensure the deploy() wrapper in index.ts also wraps launchers for cloudUrl when opts.cloudUrl is set, not just when inputs are present. This would mean the wrapper calls wrapInputResolvers even when inputs are empty but cloudUrl is present.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Pass opts.cloudUrl through launcher.launch in deployInternal so
--cloud-url reaches the cloud launcher even when --input is not used.
- Wrap the cloud deploy fetch in an AbortController with a 30s timeout
so a stalled network request can no longer hang `workforce deploy`
indefinitely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit 47dd049 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the feat/deploy-input-flags branch May 13, 2026 08:17
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(deploy): support deploy input overrides - #101

Merged
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags
May 13, 2026
Merged

feat(deploy): support deploy input overrides#101
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

  • Track I: Track I — Deploy CLI flags
  • Final signoff: COMPLETE.
  • Eligible for auto-merge when CI green and upstream deps merged.

Spec reference

Source spec: workforce/docs/plans/deploy-v1-schema-cascade-spec.md

Track section: Track I — Deploy CLI flags

Final signoff

Verifying acceptance bullets against actual files:
**Spec (deploy-v1.md §3.8, §5 flag list):**
- Repeatable `--input KEY=value` flags ✅
- CLI rejects undeclared keys ✅
- Requires string values ✅
- dev + sandbox: inject `WORKFORCE_INPUT_<KEY>` env ✅
- cloud: send as `inputs` in POST body ✅
**Verified files:**
1. **CLI parser** (`packages/cli/src/deploy-command.ts:86, 109, 136-181`)
- `--input` documented in DEPLOY_USAGE
- Accepts both `--input KEY=val` (sep arg) and `--input=KEY=val` (joined) — repeatable via accumulator
- Malformed input dies with clean error (`expected <key>=<value>`)
2. **Validation** (`packages/deploy/src/index.ts:61-75`)
- `validateDeployInputs` checks string type → `Input '${key}' must be a string`
- Rejects undeclared keys → `Unknown input '${key}'; persona declares: ${list}`
- Runs against parsed persona's `inputs` declaration via `preflightPersona`
3. **Env injection — dev & sandbox** (`packages/deploy/src/index.ts:96-120`)
- `wrapLauncher` wraps `dev`, `sandbox`, AND `cloud` launchers
- `toInputEnv` prefixes every key with `WORKFORCE_INPUT_` and merges into `env`
- `inputs` also forwarded to launcher input
4. **Cloud POST body** (`packages/deploy/src/modes/cloud.ts:49-57`)
- `body: JSON.stringify({ persona, bundle, ...(inputs && Object.keys.length > 0 ? { inputs } : {}) })`
5. **Tests** (`packages/deploy/src/modes/input-values.test.ts`, `packages/cli/src/deploy-command.test.ts`)
- Parser: single, multiple, malformed → all covered
- Validation: env propagation, undeclared rejection, non-string rejection
- Cloud: live `fetch` capture asserts POST body contains `inputs: { TOPIC: 'Deploy v1' }`
- Dev launcher: end-to-end child process observes `WORKFORCE_INPUT_TOPIC`/`WORKFORCE_INPUT_REGION` in env
6. **Spec doc** (`docs/plans/deploy-v1.md:188-190, 289, 295`) — `--input` flag listed in CLI surface and §3.8 normative paragraph.
All five acceptance bullets are satisfied with both implementation and test coverage. The undeclared-key error message format matches the test regex (`Unknown input 'UNKNOWN'; persona declares: TOPIC, REGION`).
SIGNOFF_FINAL: COMPLETE Track-I

Final gate (typecheck + tests)

FINAL_I_TSC=0
FINAL_I_TESTS=0
> workforce@0.1.0 typecheck /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> corepack pnpm -r typecheck && corepack pnpm run typecheck:examples
Scope: 8 of 9 workspace projects
packages/daytona-runner typecheck$ tsc -p tsconfig.json --noEmit
packages/persona-kit typecheck$ tsc -p tsconfig.json --noEmit
packages/daytona-runner typecheck: Done
packages/persona-kit typecheck: Done
packages/runtime typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck: Done
packages/runtime typecheck: Done
packages/deploy typecheck$ tsc -p tsconfig.json --noEmit
packages/deploy typecheck: Done
packages/cli typecheck$ tsc -p tsconfig.json --noEmit
packages/cli typecheck: Done
packages/agentworkforce typecheck$ node --check bin/agentworkforce.js
packages/agentworkforce typecheck: Done
> workforce@0.1.0 typecheck:examples /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> tsc -p examples/tsconfig.json --noEmit
packages/cli test: # Subtest: computeTuiView: matches mode honors visibleCap
packages/cli test: ok 166 - computeTuiView: matches mode honors visibleCap
packages/cli test: ---
packages/cli test: duration_ms: 0.033
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: # Subtest: loadRecents returns [] when the file is absent or corrupt
packages/cli test: ok 167 - loadRecents returns [] when the file is absent or corrupt
packages/cli test: ---
packages/cli test: duration_ms: 0.35175
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: 1..167
packages/cli test: # tests 167
packages/cli test: # suites 0
packages/cli test: # pass 167
packages/cli test: # fail 0
packages/cli test: # cancelled 0
packages/cli test: # skipped 0
packages/cli test: # todo 0
packages/cli test: # duration_ms 39466.787541
packages/cli test: Done
packages/agentworkforce test$ node --check bin/agentworkforce.js && node --test test/*.test.js
packages/agentworkforce test: TAP version 13
packages/agentworkforce test: # Subtest: agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ok 1 - agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ---
packages/agentworkforce test: duration_ms: 87.809666
packages/agentworkforce test: type: 'test'
packages/agentworkforce test: ...
packages/agentworkforce test: 1..1
packages/agentworkforce test: # tests 1
packages/agentworkforce test: # suites 0
packages/agentworkforce test: # pass 1
packages/agentworkforce test: # fail 0
packages/agentworkforce test: # cancelled 0
packages/agentworkforce test: # skipped 0
packages/agentworkforce test: # todo 0
packages/agentworkforce test: # duration_ms 193.364041
packages/agentworkforce test: Done

Self-reflection report

REFLECT_GAPS:
- "Update persona spec docs in `docs/plans/deploy-v1.md` §3 to mention `--input` as the deploy-time override mechanism." — MISSING. `docs/plans/deploy-v1.md` has zero matches for `--input` / `input` / `override`; the file is unchanged in this diff.
- Test bullet "Single `--input` parses and forwards." — MISSING. No test files added/modified in the diff (only `cli.ts`, `deploy/src/index.ts`, `modes/cloud.ts`, `types.ts`); no new vitest cases under `packages/cli` or `packages/deploy`.
- Test bullet "Multiple `--input` flags accumulate." — MISSING. No tests added covering `parseDeployInputFlags` in `packages/cli/src/cli.ts:3771`.
- Test bullet "Malformed flag (`--input foo`) → clean error." — MISSING. `expectDeployInputValue` / `parseDeployInputValue` (cli.ts:3795/3803) untested.
- Test bullet "Undeclared input key → clean error citing persona's declared inputs." — MISSING. `validateDeployInputs` in `packages/deploy/src/index.ts:96` has no test asserting the `Unknown input '<key>'; persona declares: …` message.
- Test bullet "`--mode dev` env vars actually reach the child process." — MISSING. No test asserts `WORKFORCE_INPUT_<KEY>` makes it into the dev launcher's child process env via `wrapLauncher` (`packages/deploy/src/index.ts:124`).
- Test bullet "`--mode cloud` POST body includes the `inputs` field." — MISSING. `postCloudDeployment` (`packages/deploy/src/modes/cloud.ts:36`) has no test verifying the body contains `inputs`.
- Implementation bullet "Plumb through `packages/deploy/src/index.ts`'s `deploy()` function as `DeployOptions.inputs?: Record<string, string>`." — PARTIAL. The type is added (`types.ts:24`) and `deploy()` reads `opts.inputs`, but the CLI does NOT pass `opts.inputs` through `runDeploy` — it sets `process.env.WORKFORCE_DEPLOY_INPUTS_JSON` in `cli.ts:3745` and the new `deploy()` wrapper reads it back from env (`index.ts:67`). Programmatic SDK callers using `DeployOptions.inputs` are covered; CLI flow is a roundabout env-var handoff rather than direct plumbing.
- Validation strength: spec says "Value must be a string (basic type check; persona-kit may add more later)." — PARTIAL/redundant. `validateDeployInputs` checks `typeof value !== 'string'` but `inputs` is already typed `Record<string,string>` and the CLI always assigns strings (cli.ts:3808), so the check is unreachable in practice. No declared-but-required-missing handling here (that's Track F's runtime job, so acceptable).
Summary: implementation core is in place across CLI parsing, `DeployOptions.inputs`, validation, and forwarding to all three modes (dev/sandbox env, cloud POST body). The notable gaps are: zero tests added (six explicit test bullets unmet), `docs/plans/deploy-v1.md §3` not updated, and the CLI→`deploy()` plumbing routes through an env-var shim instead of a direct `opts.inputs` pass.

Known gaps after this PR

⚠️Memory is not wired. is a stub in v1; see § Loud hole. Memory wiring lands in a follow-up workflow (not yet specced).

⚠️M3 destroy/list CLI commands not implemented. Separate workflow.

⚠️ ** not on npm** under scope. Handled by a separate agent per platform-team OIDC setup; not blocking morning state because cloud consumes via workspace ref.

Co-Authored-By: Ricky deploy-v1 schema cascade noreply@agentworkforce.com

@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 162e8328-e312-4761-8d57-8ee946ca7be2

📥 Commits

Reviewing files that changed from the base of the PR and between 77660a0 and 8fb4518.

📒 Files selected for processing (2)
  • packages/deploy/src/deploy.ts
  • packages/deploy/src/modes/cloud.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/deploy/src/modes/cloud.ts

📝 Walkthrough

Walkthrough

This PR implements deploy-time persona input overrides via repeatable --input KEY=value CLI flags. Inputs are validated against persona schemas, injected into runners as WORKFORCE_INPUT_<KEY> environment variables, and included in cloud deployment API requests.

Changes

Deploy Input Overrides Feature

Layer / File(s)Summary
Input type contracts
packages/deploy/src/types.ts
DeployOptions adds optional inputs: Record<string,string>; ModeLaunchInput adds inputs and cloudUrl for mode launchers.
CLI input flag parsing
packages/cli/src/deploy-command.ts, packages/cli/src/deploy-command.test.ts
parseDeployArgs recognizes repeatable --input KEY=value / --input=<key>=<value>, validates format, accumulates into inputs, and returns in DeployOptions. Tests cover single/multiple flags and malformed input exit behavior.
Feature specification and design
docs/plans/deploy-v1.md
Docs add "Deploy-time persona inputs" and update CLI usage and deploy flow to describe validation, env var naming, and cloud payload behavior.
Deploy orchestration and input validation
packages/deploy/src/index.ts
New exported deploy wrapper performs preflightPersona, validates opts.inputs against persona-declared keys, rejects unknown/non-string values, and wraps mode launchers to inject WORKFORCE_INPUT_<KEY> env vars and inputs payloads.
Cloud deployment with input support
packages/deploy/src/modes/cloud.ts
Cloud launcher now POSTs deployments to ${cloudUrl}/api/v1/workspaces/:id/deployments with persona, bundle, parsed package.json, and optional inputs; enforces 30s timeout, parses response, logs status, and maps status to exit code.
Deploy callsite forwarding
packages/deploy/src/deploy.ts
deploy forwards cloudUrl into launcher.launch when opts.cloudUrl is set.
End-to-end input integration tests
packages/deploy/src/modes/input-values.test.ts
Tests cover forwarding of validated inputs into dev launcher env and payloads, child-runner env observation, unknown-key and non-string rejections, and that cloud POST includes inputs.

Sequence Diagram

sequenceDiagram
participant CLI as parseDeployArgs
participant Deploy as deploy
participant Persona as preflightPersona
participant Validator as validateDeployInputs
participant Wrapper as wrapInputResolvers
participant Launcher as dev/sandbox/cloudLauncher
participant Cloud as Cloud API
CLI->>Deploy: deploy(opts with inputs)
Deploy->>Persona: preflightPersona(personaPath)
Deploy->>Validator: validateDeployInputs(inputs, persona)
Validator-->>Deploy: validated inputs
Deploy->>Wrapper: wrapInputResolvers(validated inputs, cloudUrl)
Wrapper->>Launcher: launch(input {inputs, env, cloudUrl})
Launcher->>Cloud: POST /deployments { persona, bundle, packageJson, inputs? }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hopping flags into a neat little row,
--input whispers where the overrides go,
Validated keys, strings held tight,
Runners wake with envs alight,
Cloud POST sings the persona's glow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 5.56% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title 'feat(deploy): support deploy input overrides' clearly and concisely summarizes the main change—adding support for deploy-time input overrides via CLI flags.
Description check✅ PassedThe description is detailed and directly related to the changeset, covering spec references, implementation verification, test coverage, and known gaps.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/deploy-input-flags

Comment @coderabbitai help to get the list of available commands and usage tips.

@khaliqgant
khaliqgant marked this pull request as ready for review May 13, 2026 04:49

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/deploy/src/modes/cloud.ts (1)

9-22: ⚡ Quick win

Update the launcher docblock to match current behavior.

The header comment still says cloud mode is unavailable and describes multipart + polling, but the implementation now does a JSON POST and returns immediately.

🤖 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/deploy/src/modes/cloud.ts` around lines 9 - 22, The top docblock in
packages/deploy/src/modes/cloud.ts is outdated: update the comment for `--mode
cloud` to remove the multipart/polling description (steps 1–4) and explicitly
describe the current behavior: the CLI performs a single JSON POST to `POST
/api/v1/workspaces/:id/deployments` with the persona and bundle, the server
returns immediately, and the function returns a deployment handle without
polling; adjust wording to reflect that cloud deploys return immediately and
mention how stop() on the returned handle behaves (e.g., issues a DELETE) so the
docblock matches the implementation.
🤖 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 `@packages/deploy/src/modes/cloud.ts`:
- Around line 41-59: The fetch POST to
`${cloudUrl}/api/v1/workspaces/.../deployments` has no timeout; wrap the request
with an AbortController: create an AbortController before calling fetch, set a
timer (e.g. with setTimeout) that calls controller.abort() after a chosen
timeout, pass controller.signal in the fetch options, and clear the timer once
fetch resolves or throws; update the block that builds the request body
(references: cloudUrl, input, workspaceToken, readFile) to include the signal
and ensure any AbortError is handled/propagated appropriately so `workforce
deploy` cannot hang indefinitely.
---
Nitpick comments:
In `@packages/deploy/src/modes/cloud.ts`:
- Around line 9-22: The top docblock in packages/deploy/src/modes/cloud.ts is
outdated: update the comment for `--mode cloud` to remove the multipart/polling
description (steps 1–4) and explicitly describe the current behavior: the CLI
performs a single JSON POST to `POST /api/v1/workspaces/:id/deployments` with
the persona and bundle, the server returns immediately, and the function returns
a deployment handle without polling; adjust wording to reflect that cloud
deploys return immediately and mention how stop() on the returned handle behaves
(e.g., issues a DELETE) so the docblock matches the implementation.
🪄 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: 4b91f72e-dccb-4cd2-9744-1695b6274f0a

📥 Commits

Reviewing files that changed from the base of the PR and between 19ebbee and 77660a0.

📒 Files selected for processing (7)
  • docs/plans/deploy-v1.md
  • packages/cli/src/deploy-command.test.ts
  • packages/cli/src/deploy-command.ts
  • packages/deploy/src/index.ts
  • packages/deploy/src/modes/cloud.ts
  • packages/deploy/src/modes/input-values.test.ts
  • packages/deploy/src/types.ts

Comment threadpackages/deploy/src/modes/cloud.ts Outdated

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +53 to +54
const inputs = opts.inputs && Object.keys(opts.inputs).length > 0 ? opts.inputs : undefined;
if (!inputs) return deployInternal(opts, resolvers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 --cloud-url CLI flag silently ignored when no --input flags are provided

The new deploy() wrapper in index.ts only forwards opts.cloudUrl to the cloud launcher through wrapLauncher (line 110), which is only invoked when inputs are present (line 58). When there are no inputs, the wrapper calls deployInternal(opts, resolvers) directly, and deployInternal at packages/deploy/src/deploy.ts:177-183 never passes cloudUrl in the launcher.launch(...) call. As a result, the cloud launcher at packages/deploy/src/modes/cloud.ts:25 sees input.cloudUrl as undefined and falls back to process.env.WORKFORCE_CLOUD_URL. This means workforce deploy persona.json --mode cloud --cloud-url https://custom.example.com (without --input) silently ignores --cloud-url, and if WORKFORCE_CLOUD_URL env var is not set, the deployment fails with the "not yet available" error despite a valid cloud URL being specified.

Prompt for agents
The deploy() wrapper in packages/deploy/src/index.ts only wraps launchers (to inject cloudUrl into ModeLaunchInput) when inputs are present. When no inputs are provided, it calls deployInternal directly, and deployInternal in packages/deploy/src/deploy.ts:177-183 does not pass opts.cloudUrl to the launcher.
The cloud launcher (packages/deploy/src/modes/cloud.ts:25) reads input.cloudUrl as its primary source, falling back to env var. So --cloud-url is silently lost in the no-inputs path.
Two possible approaches:
1. Have deployInternal (deploy.ts) pass cloudUrl to launcher.launch() from opts.cloudUrl, so it always reaches launchers regardless of the wrapper.
2. Ensure the deploy() wrapper in index.ts also wraps launchers for cloudUrl when opts.cloudUrl is set, not just when inputs are present. This would mean the wrapper calls wrapInputResolvers even when inputs are empty but cloudUrl is present.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Pass opts.cloudUrl through launcher.launch in deployInternal so
--cloud-url reaches the cloud launcher even when --input is not used.
- Wrap the cloud deploy fetch in an AbortController with a 30s timeout
so a stalled network request can no longer hang `workforce deploy`
indefinitely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit 47dd049 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the feat/deploy-input-flags branch May 13, 2026 08:17
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(deploy): support deploy input overrides - #101

Merged
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags
May 13, 2026
Merged

feat(deploy): support deploy input overrides#101
khaliqgant merged 2 commits into
mainfrom
feat/deploy-input-flags

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

  • Track I: Track I — Deploy CLI flags
  • Final signoff: COMPLETE.
  • Eligible for auto-merge when CI green and upstream deps merged.

Spec reference

Source spec: workforce/docs/plans/deploy-v1-schema-cascade-spec.md

Track section: Track I — Deploy CLI flags

Final signoff

Verifying acceptance bullets against actual files:
**Spec (deploy-v1.md §3.8, §5 flag list):**
- Repeatable `--input KEY=value` flags ✅
- CLI rejects undeclared keys ✅
- Requires string values ✅
- dev + sandbox: inject `WORKFORCE_INPUT_<KEY>` env ✅
- cloud: send as `inputs` in POST body ✅
**Verified files:**
1. **CLI parser** (`packages/cli/src/deploy-command.ts:86, 109, 136-181`)
- `--input` documented in DEPLOY_USAGE
- Accepts both `--input KEY=val` (sep arg) and `--input=KEY=val` (joined) — repeatable via accumulator
- Malformed input dies with clean error (`expected <key>=<value>`)
2. **Validation** (`packages/deploy/src/index.ts:61-75`)
- `validateDeployInputs` checks string type → `Input '${key}' must be a string`
- Rejects undeclared keys → `Unknown input '${key}'; persona declares: ${list}`
- Runs against parsed persona's `inputs` declaration via `preflightPersona`
3. **Env injection — dev & sandbox** (`packages/deploy/src/index.ts:96-120`)
- `wrapLauncher` wraps `dev`, `sandbox`, AND `cloud` launchers
- `toInputEnv` prefixes every key with `WORKFORCE_INPUT_` and merges into `env`
- `inputs` also forwarded to launcher input
4. **Cloud POST body** (`packages/deploy/src/modes/cloud.ts:49-57`)
- `body: JSON.stringify({ persona, bundle, ...(inputs && Object.keys.length > 0 ? { inputs } : {}) })`
5. **Tests** (`packages/deploy/src/modes/input-values.test.ts`, `packages/cli/src/deploy-command.test.ts`)
- Parser: single, multiple, malformed → all covered
- Validation: env propagation, undeclared rejection, non-string rejection
- Cloud: live `fetch` capture asserts POST body contains `inputs: { TOPIC: 'Deploy v1' }`
- Dev launcher: end-to-end child process observes `WORKFORCE_INPUT_TOPIC`/`WORKFORCE_INPUT_REGION` in env
6. **Spec doc** (`docs/plans/deploy-v1.md:188-190, 289, 295`) — `--input` flag listed in CLI surface and §3.8 normative paragraph.
All five acceptance bullets are satisfied with both implementation and test coverage. The undeclared-key error message format matches the test regex (`Unknown input 'UNKNOWN'; persona declares: TOPIC, REGION`).
SIGNOFF_FINAL: COMPLETE Track-I

Final gate (typecheck + tests)

FINAL_I_TSC=0
FINAL_I_TESTS=0
> workforce@0.1.0 typecheck /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> corepack pnpm -r typecheck && corepack pnpm run typecheck:examples
Scope: 8 of 9 workspace projects
packages/daytona-runner typecheck$ tsc -p tsconfig.json --noEmit
packages/persona-kit typecheck$ tsc -p tsconfig.json --noEmit
packages/daytona-runner typecheck: Done
packages/persona-kit typecheck: Done
packages/runtime typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck: Done
packages/runtime typecheck: Done
packages/deploy typecheck$ tsc -p tsconfig.json --noEmit
packages/deploy typecheck: Done
packages/cli typecheck$ tsc -p tsconfig.json --noEmit
packages/cli typecheck: Done
packages/agentworkforce typecheck$ node --check bin/agentworkforce.js
packages/agentworkforce typecheck: Done
> workforce@0.1.0 typecheck:examples /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-deploy-inputs
> tsc -p examples/tsconfig.json --noEmit
packages/cli test: # Subtest: computeTuiView: matches mode honors visibleCap
packages/cli test: ok 166 - computeTuiView: matches mode honors visibleCap
packages/cli test: ---
packages/cli test: duration_ms: 0.033
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: # Subtest: loadRecents returns [] when the file is absent or corrupt
packages/cli test: ok 167 - loadRecents returns [] when the file is absent or corrupt
packages/cli test: ---
packages/cli test: duration_ms: 0.35175
packages/cli test: type: 'test'
packages/cli test: ...
packages/cli test: 1..167
packages/cli test: # tests 167
packages/cli test: # suites 0
packages/cli test: # pass 167
packages/cli test: # fail 0
packages/cli test: # cancelled 0
packages/cli test: # skipped 0
packages/cli test: # todo 0
packages/cli test: # duration_ms 39466.787541
packages/cli test: Done
packages/agentworkforce test$ node --check bin/agentworkforce.js && node --test test/*.test.js
packages/agentworkforce test: TAP version 13
packages/agentworkforce test: # Subtest: agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ok 1 - agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ---
packages/agentworkforce test: duration_ms: 87.809666
packages/agentworkforce test: type: 'test'
packages/agentworkforce test: ...
packages/agentworkforce test: 1..1
packages/agentworkforce test: # tests 1
packages/agentworkforce test: # suites 0
packages/agentworkforce test: # pass 1
packages/agentworkforce test: # fail 0
packages/agentworkforce test: # cancelled 0
packages/agentworkforce test: # skipped 0
packages/agentworkforce test: # todo 0
packages/agentworkforce test: # duration_ms 193.364041
packages/agentworkforce test: Done

Self-reflection report

REFLECT_GAPS:
- "Update persona spec docs in `docs/plans/deploy-v1.md` §3 to mention `--input` as the deploy-time override mechanism." — MISSING. `docs/plans/deploy-v1.md` has zero matches for `--input` / `input` / `override`; the file is unchanged in this diff.
- Test bullet "Single `--input` parses and forwards." — MISSING. No test files added/modified in the diff (only `cli.ts`, `deploy/src/index.ts`, `modes/cloud.ts`, `types.ts`); no new vitest cases under `packages/cli` or `packages/deploy`.
- Test bullet "Multiple `--input` flags accumulate." — MISSING. No tests added covering `parseDeployInputFlags` in `packages/cli/src/cli.ts:3771`.
- Test bullet "Malformed flag (`--input foo`) → clean error." — MISSING. `expectDeployInputValue` / `parseDeployInputValue` (cli.ts:3795/3803) untested.
- Test bullet "Undeclared input key → clean error citing persona's declared inputs." — MISSING. `validateDeployInputs` in `packages/deploy/src/index.ts:96` has no test asserting the `Unknown input '<key>'; persona declares: …` message.
- Test bullet "`--mode dev` env vars actually reach the child process." — MISSING. No test asserts `WORKFORCE_INPUT_<KEY>` makes it into the dev launcher's child process env via `wrapLauncher` (`packages/deploy/src/index.ts:124`).
- Test bullet "`--mode cloud` POST body includes the `inputs` field." — MISSING. `postCloudDeployment` (`packages/deploy/src/modes/cloud.ts:36`) has no test verifying the body contains `inputs`.
- Implementation bullet "Plumb through `packages/deploy/src/index.ts`'s `deploy()` function as `DeployOptions.inputs?: Record<string, string>`." — PARTIAL. The type is added (`types.ts:24`) and `deploy()` reads `opts.inputs`, but the CLI does NOT pass `opts.inputs` through `runDeploy` — it sets `process.env.WORKFORCE_DEPLOY_INPUTS_JSON` in `cli.ts:3745` and the new `deploy()` wrapper reads it back from env (`index.ts:67`). Programmatic SDK callers using `DeployOptions.inputs` are covered; CLI flow is a roundabout env-var handoff rather than direct plumbing.
- Validation strength: spec says "Value must be a string (basic type check; persona-kit may add more later)." — PARTIAL/redundant. `validateDeployInputs` checks `typeof value !== 'string'` but `inputs` is already typed `Record<string,string>` and the CLI always assigns strings (cli.ts:3808), so the check is unreachable in practice. No declared-but-required-missing handling here (that's Track F's runtime job, so acceptable).
Summary: implementation core is in place across CLI parsing, `DeployOptions.inputs`, validation, and forwarding to all three modes (dev/sandbox env, cloud POST body). The notable gaps are: zero tests added (six explicit test bullets unmet), `docs/plans/deploy-v1.md §3` not updated, and the CLI→`deploy()` plumbing routes through an env-var shim instead of a direct `opts.inputs` pass.

Known gaps after this PR

⚠️Memory is not wired. is a stub in v1; see § Loud hole. Memory wiring lands in a follow-up workflow (not yet specced).

⚠️M3 destroy/list CLI commands not implemented. Separate workflow.

⚠️ ** not on npm** under scope. Handled by a separate agent per platform-team OIDC setup; not blocking morning state because cloud consumes via workspace ref.

Co-Authored-By: Ricky deploy-v1 schema cascade noreply@agentworkforce.com

@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 162e8328-e312-4761-8d57-8ee946ca7be2

📥 Commits

Reviewing files that changed from the base of the PR and between 77660a0 and 8fb4518.

📒 Files selected for processing (2)
  • packages/deploy/src/deploy.ts
  • packages/deploy/src/modes/cloud.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/deploy/src/modes/cloud.ts

📝 Walkthrough

Walkthrough

This PR implements deploy-time persona input overrides via repeatable --input KEY=value CLI flags. Inputs are validated against persona schemas, injected into runners as WORKFORCE_INPUT_<KEY> environment variables, and included in cloud deployment API requests.

Changes

Deploy Input Overrides Feature

Layer / File(s)Summary
Input type contracts
packages/deploy/src/types.ts
DeployOptions adds optional inputs: Record<string,string>; ModeLaunchInput adds inputs and cloudUrl for mode launchers.
CLI input flag parsing
packages/cli/src/deploy-command.ts, packages/cli/src/deploy-command.test.ts
parseDeployArgs recognizes repeatable --input KEY=value / --input=<key>=<value>, validates format, accumulates into inputs, and returns in DeployOptions. Tests cover single/multiple flags and malformed input exit behavior.
Feature specification and design
docs/plans/deploy-v1.md
Docs add "Deploy-time persona inputs" and update CLI usage and deploy flow to describe validation, env var naming, and cloud payload behavior.
Deploy orchestration and input validation
packages/deploy/src/index.ts
New exported deploy wrapper performs preflightPersona, validates opts.inputs against persona-declared keys, rejects unknown/non-string values, and wraps mode launchers to inject WORKFORCE_INPUT_<KEY> env vars and inputs payloads.
Cloud deployment with input support
packages/deploy/src/modes/cloud.ts
Cloud launcher now POSTs deployments to ${cloudUrl}/api/v1/workspaces/:id/deployments with persona, bundle, parsed package.json, and optional inputs; enforces 30s timeout, parses response, logs status, and maps status to exit code.
Deploy callsite forwarding
packages/deploy/src/deploy.ts
deploy forwards cloudUrl into launcher.launch when opts.cloudUrl is set.
End-to-end input integration tests
packages/deploy/src/modes/input-values.test.ts
Tests cover forwarding of validated inputs into dev launcher env and payloads, child-runner env observation, unknown-key and non-string rejections, and that cloud POST includes inputs.

Sequence Diagram

sequenceDiagram
participant CLI as parseDeployArgs
participant Deploy as deploy
participant Persona as preflightPersona
participant Validator as validateDeployInputs
participant Wrapper as wrapInputResolvers
participant Launcher as dev/sandbox/cloudLauncher
participant Cloud as Cloud API
CLI->>Deploy: deploy(opts with inputs)
Deploy->>Persona: preflightPersona(personaPath)
Deploy->>Validator: validateDeployInputs(inputs, persona)
Validator-->>Deploy: validated inputs
Deploy->>Wrapper: wrapInputResolvers(validated inputs, cloudUrl)
Wrapper->>Launcher: launch(input {inputs, env, cloudUrl})
Launcher->>Cloud: POST /deployments { persona, bundle, packageJson, inputs? }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hopping flags into a neat little row,
--input whispers where the overrides go,
Validated keys, strings held tight,
Runners wake with envs alight,
Cloud POST sings the persona's glow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 5.56% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title 'feat(deploy): support deploy input overrides' clearly and concisely summarizes the main change—adding support for deploy-time input overrides via CLI flags.
Description check✅ PassedThe description is detailed and directly related to the changeset, covering spec references, implementation verification, test coverage, and known gaps.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/deploy-input-flags

Comment @coderabbitai help to get the list of available commands and usage tips.

@khaliqgant
khaliqgant marked this pull request as ready for review May 13, 2026 04:49

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/deploy/src/modes/cloud.ts (1)

9-22: ⚡ Quick win

Update the launcher docblock to match current behavior.

The header comment still says cloud mode is unavailable and describes multipart + polling, but the implementation now does a JSON POST and returns immediately.

🤖 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/deploy/src/modes/cloud.ts` around lines 9 - 22, The top docblock in
packages/deploy/src/modes/cloud.ts is outdated: update the comment for `--mode
cloud` to remove the multipart/polling description (steps 1–4) and explicitly
describe the current behavior: the CLI performs a single JSON POST to `POST
/api/v1/workspaces/:id/deployments` with the persona and bundle, the server
returns immediately, and the function returns a deployment handle without
polling; adjust wording to reflect that cloud deploys return immediately and
mention how stop() on the returned handle behaves (e.g., issues a DELETE) so the
docblock matches the implementation.
🤖 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 `@packages/deploy/src/modes/cloud.ts`:
- Around line 41-59: The fetch POST to
`${cloudUrl}/api/v1/workspaces/.../deployments` has no timeout; wrap the request
with an AbortController: create an AbortController before calling fetch, set a
timer (e.g. with setTimeout) that calls controller.abort() after a chosen
timeout, pass controller.signal in the fetch options, and clear the timer once
fetch resolves or throws; update the block that builds the request body
(references: cloudUrl, input, workspaceToken, readFile) to include the signal
and ensure any AbortError is handled/propagated appropriately so `workforce
deploy` cannot hang indefinitely.
---
Nitpick comments:
In `@packages/deploy/src/modes/cloud.ts`:
- Around line 9-22: The top docblock in packages/deploy/src/modes/cloud.ts is
outdated: update the comment for `--mode cloud` to remove the multipart/polling
description (steps 1–4) and explicitly describe the current behavior: the CLI
performs a single JSON POST to `POST /api/v1/workspaces/:id/deployments` with
the persona and bundle, the server returns immediately, and the function returns
a deployment handle without polling; adjust wording to reflect that cloud
deploys return immediately and mention how stop() on the returned handle behaves
(e.g., issues a DELETE) so the docblock matches the implementation.
🪄 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: 4b91f72e-dccb-4cd2-9744-1695b6274f0a

📥 Commits

Reviewing files that changed from the base of the PR and between 19ebbee and 77660a0.

📒 Files selected for processing (7)
  • docs/plans/deploy-v1.md
  • packages/cli/src/deploy-command.test.ts
  • packages/cli/src/deploy-command.ts
  • packages/deploy/src/index.ts
  • packages/deploy/src/modes/cloud.ts
  • packages/deploy/src/modes/input-values.test.ts
  • packages/deploy/src/types.ts

Comment threadpackages/deploy/src/modes/cloud.ts Outdated

@devin-ai-integrationdevin-ai-integrationBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +53 to +54
const inputs = opts.inputs && Object.keys(opts.inputs).length > 0 ? opts.inputs : undefined;
if (!inputs) return deployInternal(opts, resolvers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 --cloud-url CLI flag silently ignored when no --input flags are provided

The new deploy() wrapper in index.ts only forwards opts.cloudUrl to the cloud launcher through wrapLauncher (line 110), which is only invoked when inputs are present (line 58). When there are no inputs, the wrapper calls deployInternal(opts, resolvers) directly, and deployInternal at packages/deploy/src/deploy.ts:177-183 never passes cloudUrl in the launcher.launch(...) call. As a result, the cloud launcher at packages/deploy/src/modes/cloud.ts:25 sees input.cloudUrl as undefined and falls back to process.env.WORKFORCE_CLOUD_URL. This means workforce deploy persona.json --mode cloud --cloud-url https://custom.example.com (without --input) silently ignores --cloud-url, and if WORKFORCE_CLOUD_URL env var is not set, the deployment fails with the "not yet available" error despite a valid cloud URL being specified.

Prompt for agents
The deploy() wrapper in packages/deploy/src/index.ts only wraps launchers (to inject cloudUrl into ModeLaunchInput) when inputs are present. When no inputs are provided, it calls deployInternal directly, and deployInternal in packages/deploy/src/deploy.ts:177-183 does not pass opts.cloudUrl to the launcher.
The cloud launcher (packages/deploy/src/modes/cloud.ts:25) reads input.cloudUrl as its primary source, falling back to env var. So --cloud-url is silently lost in the no-inputs path.
Two possible approaches:
1. Have deployInternal (deploy.ts) pass cloudUrl to launcher.launch() from opts.cloudUrl, so it always reaches launchers regardless of the wrapper.
2. Ensure the deploy() wrapper in index.ts also wraps launchers for cloudUrl when opts.cloudUrl is set, not just when inputs are present. This would mean the wrapper calls wrapInputResolvers even when inputs are empty but cloudUrl is present.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Pass opts.cloudUrl through launcher.launch in deployInternal so
--cloud-url reaches the cloud launcher even when --input is not used.
- Wrap the cloud deploy fetch in an AbortController with a 30s timeout
so a stalled network request can no longer hang `workforce deploy`
indefinitely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit 47dd049 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the feat/deploy-input-flags branch May 13, 2026 08:17
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@khaliqgant