Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/deploy-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ jobs:
cascade-migrator:dev \
./node_modules/.bin/drizzle-kit migrate

- name: Run trigger config migration (dev)
run: |
docker run --rm \
-e DATABASE_URL="${{ secrets.DEV_DATABASE_URL }}" \
cascade-migrator:dev \
npx tsx tools/migrate-triggers.ts

- name: Pull and restart cascade-router-dev
run: |
cd /opt/services
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ jobs:
cascade-migrator:latest \
./node_modules/.bin/drizzle-kit migrate

- name: Run trigger config migration
run: |
docker run --rm \
-e DATABASE_URL="${{ secrets.DATABASE_URL }}" \
cascade-migrator:latest \
npx tsx tools/migrate-triggers.ts

- name: Pull latest worker image
run: docker pull ${{ env.WORKER_IMAGE }}:latest

Expand Down
145 changes: 59 additions & 86 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,120 +210,90 @@ cascade projects integration-credential-set <project-id> --category sms --role p

**Outbound SMS**: Agents use the `SendSms` gadget. SMS credentials are scoped automatically during agent execution (mirrors email integration).

### Review Agent Trigger Modes
### Agent Trigger Configuration

Triggers define which events activate which agents. Configuration is stored in the `agent_trigger_configs` table and managed via the unified `trigger-set` command.

The review agent supports three independent trigger modes via the `reviewTrigger` config in the SCM integration triggers. **All modes default to `false`** — existing behavior is preserved via a legacy fallback.
#### Trigger Format

| Mode | Description |
|------|-------------|
| `ownPrsOnly` | Trigger review when CI passes on PRs authored by the **implementer** persona |
| `externalPrs` | Trigger review when CI passes on PRs authored by **anyone** (including external contributors) |
| `onReviewRequested` | Trigger review when a CASCADE persona is **explicitly requested** as reviewer |
Triggers use a category-prefixed event format: `{category}:{event-name}`
- PM triggers: `pm:card-moved`, `pm:issue-transitioned`, `pm:label-added`
- SCM triggers: `scm:check-suite-success`, `scm:check-suite-failure`, `scm:pr-review-submitted`
- Email triggers: `email:received`
- SMS triggers: `sms:received`

#### Setting via CLI
#### CLI Commands

```bash
# Enable review for implementer PRs only (most common)
cascade projects review-trigger-set <project-id> --own-prs-only
# Discover available triggers for an agent
cascade projects trigger-discover --agent review
cascade projects trigger-discover --agent implementation

# Enable review for external contributor PRs
cascade projects review-trigger-set <project-id> --external-prs
# List configured triggers for a project
cascade projects trigger-list <project-id>
cascade projects trigger-list <project-id> --agent review

# Enable both CI-triggered modes
cascade projects review-trigger-set <project-id> --own-prs-only --external-prs
# Configure a trigger (unified command)
cascade projects trigger-set <project-id> --agent review --event scm:check-suite-success --enable
cascade projects trigger-set <project-id> --agent review --event scm:check-suite-success --disable
cascade projects trigger-set <project-id> --agent review --event scm:check-suite-success --params '{"authorMode":"own"}'

# Enable review when explicitly requested
cascade projects review-trigger-set <project-id> --on-review-requested
# Enable implementation trigger for card moved to Todo
cascade projects trigger-set <project-id> --agent implementation --event pm:card-moved --enable

# Disable a mode
cascade projects review-trigger-set <project-id> --no-own-prs-only
# Disable splitting trigger for JIRA issue transitions
cascade projects trigger-set <project-id> --agent splitting --event pm:issue-transitioned --disable
```

#### Setting via Dashboard

In the **Agent Configs** tab, the `review` agent section shows three toggles under the SCM integration:
- **Own PRs Only** — CI-triggered review for implementer-authored PRs
- **External PRs** — CI-triggered review for all other PR authors
- **On Review Requested** — review triggered when a persona is explicitly requested

#### Direct JSON Config
In the **Agent Configs** tab, each agent shows toggles for its supported triggers. Triggers with parameters (like `authorMode` for review) show additional input fields when enabled.

```bash
cascade projects integration-set <project-id> \
--category scm --provider github --config '{}' \
--triggers '{"reviewTrigger":{"ownPrsOnly":true,"externalPrs":false,"onReviewRequested":true}}'
```

#### Backward Compatibility

When `reviewTrigger` is absent, the system falls back to legacy booleans:
- `checkSuiteSuccess` → `ownPrsOnly` (default `true` for existing projects)
- `reviewRequested` → `onReviewRequested` (default `false`)
- `externalPrs` always `false` in legacy mode (no legacy equivalent)

### PM Agent Trigger Modes
#### Trigger Migration

Splitting, planning, and implementation agents each have independent toggles for their PM triggers. **All modes default to `true`** for backward compatibility.
When merging to `dev` or `main`, legacy trigger configs from `project_integrations.triggers` are automatically migrated to the new `agent_trigger_configs` table. The migration is idempotent and preserves existing configurations.

#### Trello card-moved triggers

| Flag | Description |
|------|-------------|
| `cardMovedToSplitting` | Trigger splitting agent when a card is moved to the Splitting list |
| `cardMovedToPlanning` | Trigger planning agent when a card is moved to the Planning list |
| `cardMovedToTodo` | Trigger implementation agent when a card is moved to the Todo list |
### Review Agent Trigger Modes

#### JIRA issue-transitioned triggers (per-agent)
The review agent supports multiple trigger events:

The `issueTransitioned` field supports both a legacy boolean (applies to all agents) and a nested per-agent object:
| Event | Description |
|-------|-------------|
| `scm:check-suite-success` | Trigger review when CI passes (use `authorMode` parameter: `own` or `external`) |
| `scm:review-requested` | Trigger review when a CASCADE persona is explicitly requested as reviewer |
| `scm:pr-opened` | Trigger review when a PR is opened |

| Agent | Field | Description |
|-------|-------|-------------|
| splitting | `issueTransitioned.splitting` | Trigger splitting when issue transitions to Splitting status |
| planning | `issueTransitioned.planning` | Trigger planning when issue transitions to Planning status |
| implementation | `issueTransitioned.implementation` | Trigger implementation when issue transitions to Todo status |
```bash
# Enable review for implementer PRs only (most common)
cascade projects trigger-set <project-id> --agent review --event scm:check-suite-success --enable --params '{"authorMode":"own"}'

#### Setting via CLI
# Enable review for external contributor PRs
cascade projects trigger-set <project-id> --agent review --event scm:check-suite-success --enable --params '{"authorMode":"external"}'

```bash
# Disable Trello card-moved trigger for splitting agent
cascade projects pm-trigger-set <project-id> --no-card-moved-to-splitting

# Disable JIRA issue-transitioned for implementation agent only
cascade projects pm-trigger-set <project-id> --no-issue-transitioned-implementation

# Enable JIRA triggers for splitting and planning, disable for implementation
cascade projects pm-trigger-set <project-id> \
--issue-transitioned-splitting \
--issue-transitioned-planning \
--no-issue-transitioned-implementation

# Disable all Trello card-moved triggers
cascade projects pm-trigger-set <project-id> \
--no-card-moved-to-splitting \
--no-card-moved-to-planning \
--no-card-moved-to-todo
# Enable review when explicitly requested
cascade projects trigger-set <project-id> --agent review --event scm:review-requested --enable
```

#### Setting via Dashboard
### PM Agent Trigger Modes

In the **Agent Configs** tab, the splitting, planning, and implementation agent sections each show:
- **Card moved to [list]** — Trello card-moved toggle (Trello projects only)
- **Issue Transitioned** — JIRA per-agent transition toggle (JIRA projects only)
- **Ready to Process label** — label-based trigger toggle
Splitting, planning, and implementation agents each support PM triggers:

#### Direct JSON Config
| Event | Providers | Description |
|-------|-----------|-------------|
| `pm:card-moved` | Trello | Trigger when card moved to agent's target list |
| `pm:issue-transitioned` | JIRA | Trigger when issue transitions to agent's target status |
| `pm:label-added` | All | Trigger when Ready to Process label is added |

```bash
# Disable JIRA issue-transitioned for implementation only
cascade projects integration-set <project-id> \
--category pm --provider jira --config '{"projectKey":"PROJ","statuses":{...}}' \
--triggers '{"issueTransitioned":{"splitting":true,"planning":true,"implementation":false}}'
```
# Enable card-moved trigger for implementation
cascade projects trigger-set <project-id> --agent implementation --event pm:card-moved --enable

#### Backward Compatibility
# Disable JIRA issue-transitioned for planning
cascade projects trigger-set <project-id> --agent planning --event pm:issue-transitioned --disable

The legacy `issueTransitioned: true/false` boolean is still supported — it applies to all agents uniformly.
# Enable label-added trigger for splitting
cascade projects trigger-set <project-id> --agent splitting --event pm:label-added --enable
```

## Claude Code Backend

Expand Down Expand Up @@ -483,6 +453,9 @@ cascade projects integrations <id>
cascade projects integration-set <id> --category pm --provider trello --config '{"boardId":"..."}'
cascade projects integration-credential-set <id> --category scm --role implementer_token --credential-id 5
cascade projects integration-credential-rm <id> --category scm --role implementer_token
cascade projects trigger-discover --agent <agent-type>
cascade projects trigger-list <id> [--agent <type>]
cascade projects trigger-set <id> --agent <type> --event <event> [--enable|--disable] [--params JSON]

# Credentials
cascade credentials list
Expand Down Expand Up @@ -527,7 +500,7 @@ src/cli/dashboard/
├── logout.ts
├── whoami.ts
├── runs/ # 6 commands
├── projects/ # 8 commands
├── projects/ # 13 commands
├── credentials/ # 4 commands
├── defaults/ # 2 commands
├── org/ # 2 commands
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"credentials:encrypt": "node --env-file=.env --import tsx tools/migrate-credentials-encrypt.ts",
"credentials:decrypt": "node --env-file=.env --import tsx tools/migrate-credentials-decrypt.ts",
"credentials:rotate-key": "node --env-file=.env --import tsx tools/rotate-credential-key.ts",
"tool:test-email": "npx tsx tools/test-email-integration.ts"
"tool:test-email": "npx tsx tools/test-email-integration.ts",
"tool:migrate-triggers": "node --env-file=.env --import tsx tools/migrate-triggers.ts"
},
"keywords": [
"trello",
Expand Down
2 changes: 2 additions & 0 deletions src/agents/definitions/implementation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ triggers:
label: Target List
options: [todo]
defaultValue: todo
# contextPipeline can be specified per-trigger to override strategies.contextPipeline
# Currently using strategy default: [directoryListing, contextFiles, squint, workItem]
- event: pm:issue-transitioned
label: Issue Transitioned
description: Trigger when issue transitions to Todo status
Expand Down
48 changes: 45 additions & 3 deletions src/agents/definitions/profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ import {
import { buildGadgetsForAgent } from '../shared/gadgets.js';
import type { FetchContextParams, PreExecuteParams } from './contextSteps.js';
import { resolveAgentDefinition } from './loader.js';
import type { AgentCapabilities, AgentDefinition } from './schema.js';
import type {
AgentCapabilities,
AgentDefinition,
ContextStepName,
SupportedTrigger,
} from './schema.js';
import { CONTEXT_STEP_REGISTRY, PRE_EXECUTE_REGISTRY } from './strategies.js';

// Re-export for backward compatibility
Expand Down Expand Up @@ -81,6 +86,32 @@ function getAllCapabilities(caps: AgentCapabilities): Capability[] {
return [...caps.required, ...caps.optional];
}

/**
* Resolve the context pipeline for a given trigger event.
* Uses the trigger-specific pipeline if defined, otherwise falls back to the default.
*
* @param triggers - Array of supported triggers from the agent definition
* @param defaultPipeline - Default pipeline from strategies.contextPipeline
* @param triggerEvent - Optional trigger event (e.g., 'pm:card-moved', 'scm:check-suite-success')
* @returns The context pipeline to use
*/
function resolveContextPipeline(
triggers: SupportedTrigger[],
defaultPipeline: ContextStepName[],
triggerEvent?: string,
): ContextStepName[] {
if (!triggerEvent) {
return defaultPipeline;
}

const trigger = triggers.find((t) => t.event === triggerEvent);
if (trigger?.contextPipeline && trigger.contextPipeline.length > 0) {
return trigger.contextPipeline;
}

return defaultPipeline;
}

// ============================================================================
// Profile Builder (Capability-driven)
// ============================================================================
Expand All @@ -97,8 +128,11 @@ function buildProfileFromDefinition(def: AgentDefinition, agentType: string): Ag
// Get gadget options from strategies
const gadgetOptions = def.strategies.gadgetOptions;

// Get context pipeline from strategies
const contextPipeline = def.strategies.contextPipeline;
// Get default context pipeline from strategies
const defaultContextPipeline = def.strategies.contextPipeline;

// Get triggers for dynamic context pipeline resolution
const triggers = def.triggers ?? [];

// Get task prompt template from prompts (required by schema)
const taskPromptTemplate = def.prompts.taskPrompt;
Expand All @@ -121,6 +155,14 @@ function buildProfileFromDefinition(def: AgentDefinition, agentType: string): Ag
...(def.backend.blockGitPush !== undefined && { blockGitPush: def.backend.blockGitPush }),
...(def.backend.requiresPR && { requiresPR: true }),
fetchContext: async (params) => {
// Resolve context pipeline: use trigger-specific pipeline if available,
// otherwise fall back to the default from strategies.contextPipeline
const contextPipeline = resolveContextPipeline(
triggers,
defaultContextPipeline,
params.input.triggerType,
);

const injections: ContextInjection[] = [];
for (const step of contextPipeline) {
const stepFn = resolveRegistry(CONTEXT_STEP_REGISTRY, step, 'contextPipeline step');
Expand Down
2 changes: 2 additions & 0 deletions src/agents/definitions/respond-to-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ triggers:
description: Trigger when CI checks fail
defaultEnabled: true
providers: [github]
# contextPipeline can be specified per-trigger to override strategies.contextPipeline
# Currently using strategy default: [prContext, directoryListing, contextFiles, squint, workItem]

strategies:
contextPipeline: [prContext, directoryListing, contextFiles, squint, workItem]
Expand Down
2 changes: 2 additions & 0 deletions src/agents/definitions/review.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ triggers:
description: Filter PRs by author type
options: [own, external, all]
defaultValue: own
# contextPipeline can be specified per-trigger to override strategies.contextPipeline
# Currently using strategy default: [prContext, contextFiles, squint]
- event: scm:review-requested
label: On Review Requested
description: Trigger review when a CASCADE persona is explicitly requested as reviewer
Expand Down
Loading