Skip to content

feat(sdk,cli): flow requirements and integration connect prompts on deploy/schedule/run --cloud - #465

Merged
khaliqgant merged 4 commits into
mainfrom
feat/deploy-integration-connect
Sep 18, 2026
Merged

khaliqgant merged 4 commits into
mainfrom
feat/deploy-integration-connect

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Sep 18, 2026 •

Copy link
Copy Markdown
Member

Why

Deploying examples/stale-issues (header tools: { slack: true }, body f.slack.post) to Cloud succeeds today and fails on the first run with helper_slack.credential_missing: neither flows deploy, flows schedule nor flows run --cloud asks whether the workspace has Slack connected, and the deploy wizard's required set is GitHub + ticket sources only. agentworkforce deploy already solves this for proactive agents with the relayfile connect-session prompt; this PR gives flows the same behaviour.

What

flowRequirements(definition | compiled spec, { sources, repository, projectCli }) (packages/sdk/src/flow-requirements.ts) → { integrations: [{ provider, from: 'tools'|'source'|'helper', detail }], harnesses, harnessUses, mcp }, from inert declarations only:

Requirement Read from
slack (tools.slack) tools.<helper>: true header flag
notion (tools.relayfile) first segment of each tools.relayfile mount
linear (f.linear) body use without a flag — the same root.<namespace> / root["namespace"] recognition preflightHelpers uses, so what preflight would refuse for a missing mount is what this names
github (on github issues) provider triggers via providerDeclaration (.on(github.issues()))
github (--on github) / github (deploy target) the --on sources; every deployment run lands in --repo
claude (agent "review"), codex (llm step), claude (step "b") cli: on each f.agent/f.llm call (basename-matched to claude/codex/gemini), else nearest flows.json cli, else Cloud's default claude; compiled specs use step → named agent → flow cli
mcp fs (tools.mcp) tools.mcp

flows check prints REQUIRES slack (tools.slack), github (deploy target), claude (agent "review") and carries requirements in --json.

Connect before submit (packages/sdk/src/cloud-connect.ts, cli/cloud-connect-cli.ts): before flows deploy, flows schedule and flows run --cloud submit, each required integration is checked with GET /api/v1/workspaces/<id>/integrations/<provider>/status?scope=workspace (list fallback on 404; unknown_provider is named, not treated as disconnected). A missing one prompts:

This flow needs Slack (tools.slack), which is not connected to this workspace.
Connect Slack now? (opens browser) [Y/n]
Opening https://…/connect
Slack connected.

Yes → POST …/integrations/connect-session { allowedIntegrations: ["slack"], scope: { kind: "workspace" } } → connectLink (also sessionUrl/url) opened detached in the browser (FLOWS_NO_BROWSER=1 prints only) → status polled every 2s for up to 5 minutes. --no-connect, --json, no TTY, or an answer of no refuse with integration_not_connected (exit 2) naming the provider, the declaration and both remedies. --draft skips the check, as Cloud does. A flow that requires nothing contacts nothing extra.

flows deploy now defaults --agents to the harnesses the source declares, sends requirements in the deploy body (Cloud ignores unknown fields today; AgentWorkforce/cloud#3788 reads it), prints requires:/connected: lines, and appends Connect it with: agent-relay cloud connect <harness> to flow_model_not_connected / cli_credentials_missing refusals — there is no status route for harness credentials, so the refusal is where the remedy is named.

Tests

  • tests/flow-requirements.test.ts — derivation on in-process definitions, a compiled spec, and the shipped stale-issues, software-factory, pr-review-pipeline examples; flows check output and --json.
  • tests/cloud-connect.test.ts — status/list/unknown-provider reads; prompt accept/decline/timeout/refused session; connect-session body and browser opening; cliConnectPrompt TTY/--json/--no-connect rules and answer parsing; harnessRemedy; flows deploy/run --cloud/schedule refusing before any submit, run --cloud submitting after a prompted connect, --draft skipping, --json refusing.
  • tests/cloud-deploy.test.ts, tests/cli.test.ts updated for the new calls/fields.

Not verified live: a real browser connect against production (the mocked contract mirrors workforce/packages/deploy/src/connect.ts and cloud's connect-session / [provider]/status routes).

🤖 Generated with Claude Code


Note

Medium Risk
Changes pre-submit behavior and Cloud API calls for all hosted CLI paths; failures are mostly early refusals, but interactive connect and new deploy fields need correct workspace/auth handling in CI and production.

Overview
Adds flowRequirements so the SDK can infer integrations, coding-agent harnesses, and MCP needs from static flow declarations (headers, default body, triggers, deploy context). flows check now prints a REQUIRES … line and exposes requirements in --json.

Before flows deploy, flows schedule, or flows run --cloud submit, the CLI checks workspace integration status and can prompt to connect via Cloud’s connect-session flow (browser + poll). --no-connect, --json, non-TTY, or --draft deploy skip or refuse instead of prompting; missing integrations exit 2 with integration_not_connected.

flows deploy defaults --agents from declared cli: harnesses, sends requirements in the deploy payload, prints requires: / connected:, and appends agent-relay cloud connect <harness> on harness credential refusals. Unsupported declared harnesses (e.g. gemini) are refused unless --agents overrides.

Reviewed by Cursor Bugbot for commit 123d0e2. Bugbot is set up for automated code reviews on this repo. Configure here.


Agent Relay sessions

  • claude session aa342204 · opened via gh pr create · last active 2026-09-18

Relayflow Lead and others added 2 commits September 18, 2026 05:15
…rom a flow; flows check prints REQUIRES

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…un --cloud submit

Every hosted verb derives what the flow requires (flowRequirements) and checks
each integration against the workspace's relayfile connection status. A missing
one is offered in the terminal through the same connect-session flow
agentworkforce deploy uses (POST …/integrations/connect-session → browser →
poll); --no-connect, --json or no TTY refuse with integration_not_connected.
A harness-credential refusal names agent-relay cloud connect <harness>.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 25 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 5d5313b2-2f4e-492f-a88e-bcb5432b2a4b

📥 Commits

Reviewing files that changed from the base of the PR and between a251bd6 and 123d0e2.

📒 Files selected for processing (18)
  • docs/CLOUD.md
  • packages/sdk/src/cli.ts
  • packages/sdk/src/cli/check-triggers.ts
  • packages/sdk/src/cli/check.ts
  • packages/sdk/src/cli/cloud-connect-cli.ts
  • packages/sdk/src/cli/cloud-deploy.ts
  • packages/sdk/src/cli/cloud-run.ts
  • packages/sdk/src/cli/cloud-schedule.ts
  • packages/sdk/src/cloud-connect.ts
  • packages/sdk/src/cloud-deploy.ts
  • packages/sdk/src/cloud-http.ts
  • packages/sdk/src/cloud-schedule.ts
  • packages/sdk/src/flow-requirements.ts
  • packages/sdk/src/index.ts
  • packages/sdk/tests/cli.test.ts
  • packages/sdk/tests/cloud-connect.test.ts
  • packages/sdk/tests/cloud-deploy.test.ts
  • packages/sdk/tests/flow-requirements.test.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@devin-ai-integration devin-ai-integration Bot 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 4 potential issues.

4 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment on lines +79 to +85
if (isCompiledSpec(flow)) {
for (const step of flow.steps) {
if (step.type !== 'llm' && step.type !== 'agent') continue;
const named = step.type === 'agent' && step.agent !== undefined ? flow.agents?.[step.agent]?.cli : undefined;
const cli = step.cli ?? named ?? flow.cli;
need(cli === undefined ? fallback : harnessFromCli(cli), `step "${step.id}"`);
}

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.

🔴 YAML helpers bypass connection checks

For YAML helper steps, flowRequirements records Claude instead of the helper provider. The hosted command submits without checking that integration, so helper execution can fail.

Learn more

YAML helper syntax is lowered by expandYamlHelpers into an agent step containing a versioned helper envelope. The compiled-spec branch treats that step as a normal agent and never recovers the envelope's provider. It therefore reports a Claude harness and no integration. The pre-submit connection gate sees no integration and allows submission, although the helper worker later requires that provider's relayfile mount.

Example: A YAML step containing slack.post compiles to an agent with external surface /slack. flows schedule --no-connect skips Slack status entirely, creates the schedule, and its first helper execution can fail for missing Slack credentials.

Recommended fix: In the compiled-spec branch, call helperCall before normal agent handling. Declare the returned provider as an integration and skip harness inference for helper envelopes.

Devin Review


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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 123d0e2: the compiled-spec branch calls helperCall(step) first; a helper envelope declares its provider as an integration (slack (step "notify")) and skips harness inference. Test: reads a YAML helper step as its provider, never as a harness.

Comment thread packages/sdk/src/cloud-deploy.ts Outdated
Comment on lines +210 to +212
const declaredAgents = requirements.harnesses
.filter((harness): harness is FlowAgentHarness => (FLOW_AGENT_HARNESSES as readonly string[]).includes(harness));
const agents = input.agents ?? (declaredAgents.length > 0 ? declaredAgents : ['claude']);

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.

🔴 Gemini declarations activate Claude

When a source declares Gemini, declaredAgents drops it and agents can default to Claude. Activation checks Claude while deployed runs still invoke Gemini.

Learn more

flowRequirements recognizes Gemini as a supported harness, but the deployment request accepts only FlowAgentHarness, whose current catalog excludes Gemini. Filtering silently changes the declared requirement rather than rejecting or preserving it. The source itself remains unchanged, so its cli: "gemini" call still needs Gemini at execution time.

Example: A flow with one f.agent(..., { cli: "gemini" }) produces requirements.harnesses = ["gemini"]. The filter produces an empty array, so inputs.agents becomes ["claude"]; activation can pass with Claude connected even though the run uses Gemini.

Recommended fix: Make the deployment harness catalog match FLOW_HARNESSES if Cloud supports Gemini. Otherwise reject unsupported declared harnesses before HTTP instead of filtering them and substituting Claude.

Devin Review


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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 123d0e2: a declared harness outside FLOW_AGENT_HARNESSES (gemini) now refuses unsupported_source before HTTP, naming the declaration (gemini (agent "review")), unless --agents overrides it. Nothing is substituted. Test: refuses a declared harness Cloud cannot run instead of substituting Claude.

Comment thread packages/sdk/src/flow-requirements.ts Outdated
Comment on lines +102 to +103
const bodies = [flow.body, ...(flow.handlers ?? []).map(handler => handler.body)]
.flatMap(body => typeof body === 'function' ? [Function.prototype.toString.call(body)] : []);

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.

🟡 Unused handlers block hosted commands

When only a handler body uses an integration, flowRequirements still requires it. Hosted launches execute the default body, so unrelated credentials can block submission.

Learn more

Authored handlers currently declare triggers, but Cloud deployment and schedule dispatch invoke the flow's default body. Scanning handler bodies treats code that Cloud does not execute as a runtime dependency. The connection gate can then refuse a valid hosted command because that unused handler dependency is absent.

Example: A flow's default body runs f.run("true"), while its schedule.every("5m") handler contains f.slack.post(...). flows schedule --no-connect refuses unless Slack is connected, although every scheduled fire executes only the default body.

Recommended fix: Separate trigger requirements from executable-body requirements. For the current hosted dispatch contract, inspect provider declarations on handlers but scan helper and harness calls only in the default body.

Devin Review


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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 123d0e2: helper and worker calls are read from the default body only; a handler contributes only its provider trigger. Documented in docs/CLOUD.md (hosted dispatch runs the default body, flows #301). Test: scans the default body only.

Comment thread packages/sdk/src/cli/cloud-run.ts Outdated
Comment on lines +29 to +31
const connections = await ensureFlowConnections({
path, prompt: cliConnectPrompt(io, { noConnect, json }),
}, { signal: controller.signal });

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.

🟡 Invalid commands connect integrations first

With required integrations, runCloudCli checks and can connect them before validating authored input. runCloudScheduleCli likewise connects before validating schedule arguments, causing side effects for refused commands.

Learn more

The connection workflow can create a browser session and alter workspace credentials. Local validation is deterministic and requires no Cloud request, but it currently runs afterward. The same ordering occurs in runCloudScheduleCli, before input parsing and schedule validation inside scheduleInCloud.

Example: A Slack flow invoked with malformed --input first offers to connect Slack. After the user completes that connection, JSON parsing fails and no run is submitted. A Slack schedule with --every 7m behaves similarly before rejecting the inexpressible interval.

Recommended fix: Prepare and validate the cloud submission, authored input, cron, interval, timezone, and declared schedule before calling ensureFlowConnections. Reuse the prepared result during submission to avoid loading the flow twice.

Devin Review


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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 123d0e2: run --cloud parses --input before ensureFlowConnections, and schedule runs the new validateScheduleArgs (cron/every/tz, both-flags) plus input parsing first, so a refused command never opens a browser. Test: refuses bad arguments before it connects anything asserts zero Cloud calls.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4405869. Configure here.

Comment thread packages/sdk/src/flow-requirements.ts
Comment thread packages/sdk/src/cli/cloud-connect-cli.ts Outdated
Relayflow Lead and others added 2 commits September 18, 2026 05:39
…l into an unrelated exception

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ead of becoming claude, validate before connecting

Addresses the first review round: a compiled helper envelope names its
provider rather than a harness; a source declaring a harness Cloud cannot run
is refused before HTTP instead of silently deploying with claude; run --cloud
and schedule validate their arguments before any connect prompt; only the
default body is scanned for helper and worker calls (handlers are not
dispatched yet, flows #301); the harness remedy sees the derived harnesses
even when no integration is required.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Review swarm: maintainability

No fresh transcript was produced for run 00d06139-cf80-45b3-a0f3-c59c9eafe526 (MISSING).

@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Review swarm: history

No fresh transcript was produced for run 00d06139-cf80-45b3-a0f3-c59c9eafe526 (MISSING).

@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Review swarm: structure

No fresh transcript was produced for run 00d06139-cf80-45b3-a0f3-c59c9eafe526 (MISSING).

@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Review swarm: FAILED

  • maintainability: MISSING
  • history: MISSING
  • structure: MISSING

Cloud run: 00d06139-cf80-45b3-a0f3-c59c9eafe526

Sign up for free to 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