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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ This is enforced by commitlint via lefthook pre-commit hooks.
See [CLAUDE.md](./CLAUDE.md) for a detailed architecture overview. Key directories:

- `src/router/` — Webhook receiver (enqueues jobs to Redis)
- `src/triggers/` — Event handlers (Trello, GitHub, JIRA)
- `src/triggers/` — Event handlers (Trello, JIRA, Linear, GitHub)
- `src/agents/` — AI agent implementations
- `src/gadgets/` — Tools agents can use
- `src/api/` — Dashboard API (tRPC)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Node.js 22+](https://img.shields.io/badge/node-%3E%3D22-brightgreen)](https://nodejs.org/)

> **Cascade orchestrates AI agents (Claude Code, Codex, opencode, LLMist) across your workflows in GitHub, Trello, and Jira.**
> **Cascade orchestrates AI agents (Claude Code, Codex, opencode, LLMist) across your workflows in GitHub, Trello, Jira, and Linear.**

Cascade is an open-source platform that automates the full software development lifecycle. Connect your PM tool and GitHub repository, and Cascade drives work items from plan to merge:

Expand Down Expand Up @@ -38,7 +38,7 @@ For the full setup walkthrough — projects, credentials, webhooks, and triggers

## ⚡ Features

- **Multi-PM support** — Works with Trello and JIRA out of the box
- **Multi-PM support** — Works with Trello, JIRA, and Linear out of the box
- **11 agent types** — Splitting, planning, implementation, review, debug, respond-to-review, respond-to-CI, and more
- **Dual-persona GitHub model** — Separate implementer and reviewer bot accounts to prevent feedback loops
- **Web dashboard + CLI** — Monitor runs, manage projects, configure triggers
Expand Down Expand Up @@ -151,7 +151,7 @@ All project-level credentials (GitHub tokens, PM keys, LLM API keys) are stored

**Dual-persona GitHub model** — Cascade uses two separate GitHub bot accounts per project (implementer and reviewer) to prevent feedback loops. The implementer writes code and creates PRs; the reviewer reviews and approves them.

**Trigger system** — Events from Trello, JIRA, and GitHub webhooks are matched against registered `TriggerHandler` instances. Triggers are configured per-project in the database.
**Trigger system** — Events from Trello, JIRA, Linear, and GitHub webhooks are matched against registered `TriggerHandler` instances. Triggers are configured per-project in the database.

**Agent engines** — Agents run through a shared execution lifecycle with a pluggable engine registry. Default engine is `claude-code` (Anthropic Claude Code SDK). Alternatives: `llmist` (supports OpenRouter, Anthropic, OpenAI), `codex` (OpenAI Codex CLI), `opencode` (OpenCode server).

Expand Down
10 changes: 7 additions & 3 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CASCADE Architecture

CASCADE is a PM-to-Code automation platform that connects project management tools (Trello, JIRA), source control (GitHub), and monitoring (Sentry) to AI-powered agents that autonomously implement features, review PRs, debug failures, and manage backlogs. Webhooks from external providers flow through a router, get queued in Redis, and are processed by ephemeral worker containers that run agents against cloned repositories.
CASCADE is a PM-to-Code automation platform that connects project management tools (Trello, JIRA, Linear), source control (GitHub), and monitoring (Sentry) to AI-powered agents that autonomously implement features, review PRs, debug failures, and manage backlogs. Webhooks from external providers flow through a router, get queued in Redis, and are processed by ephemeral worker containers that run agents against cloned repositories.

> **Relationship to CLAUDE.md**: `CLAUDE.md` is the operational reference (commands, env vars, how-to). This document and its deep-dives cover the *system design* — how components fit together and why.

Expand All @@ -11,6 +11,7 @@ graph TB
subgraph External["External Providers"]
Trello
JIRA
Linear
GitHub
Sentry
end
Expand All @@ -30,6 +31,7 @@ graph TB

Trello -->|webhook| Router
JIRA -->|webhook| Router
Linear -->|webhook| Router
GitHub -->|webhook| Router
Sentry -->|webhook| Router

Expand All @@ -39,6 +41,7 @@ graph TB
Worker -->|PRs, comments| GitHub
Worker -->|status updates| Trello
Worker -->|status updates| JIRA
Worker -->|status updates| Linear

Router <--> DB
Worker <--> DB
Expand All @@ -65,7 +68,7 @@ The canonical path from webhook to pull request:

```mermaid
sequenceDiagram
participant P as Provider<br/>(Trello/GitHub/JIRA/Sentry)
participant P as Provider<br/>(Trello/JIRA/Linear/GitHub/Sentry)
participant R as Router
participant Q as Redis/BullMQ
participant W as Worker
Expand Down Expand Up @@ -110,10 +113,11 @@ sequenceDiagram
| `src/backends/` | LLM execution engines: Claude Code, LLMist, Codex, OpenCode |
| `src/gadgets/` | Tool implementations agents use (file ops, PM, SCM, alerting, shell) |
| `src/integrations/` | Unified integration interfaces, registry, bootstrap |
| `src/pm/` | PM abstraction layer: provider interface, Trello/JIRA adapters, lifecycle |
| `src/pm/` | PM abstraction layer: provider interface, Trello/JIRA/Linear adapters, lifecycle |
| `src/github/` | GitHub API client, dual-persona model, PR operations |
| `src/trello/` | Trello API client |
| `src/jira/` | JIRA API client (jira.js wrapper) |
| `src/linear/` | Linear GraphQL API client |
| `src/sentry/` | Sentry API client, alerting integration |
| `src/config/` | Configuration provider, caching, credential resolution, integration roles |
| `src/db/` | Drizzle ORM schema, repositories, migrations |
Expand Down
4 changes: 3 additions & 1 deletion docs/architecture/01-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The router is the webhook ingestion point. It receives HTTP POST requests from e
| `POST /trello/webhook` | Trello | HEAD/GET returns 200 for Trello's verification |
| `POST /github/webhook` | GitHub | Injects `X-GitHub-Event` header into payload |
| `POST /jira/webhook` | JIRA | HEAD/GET returns 200 for JIRA verification |
| `POST /linear/webhook` | Linear | HMAC-SHA256 via `linear-signature` header |
| `POST /sentry/webhook/:projectId` | Sentry | Project ID in URL for unambiguous routing |
| `GET /health` | Internal | Queue stats, active worker count |

Expand Down Expand Up @@ -94,7 +95,7 @@ The router passes job data to workers via Docker container env vars:
| Variable | Purpose |
|----------|---------|
| `JOB_ID` | Unique job identifier |
| `JOB_TYPE` | `trello`, `github`, `jira`, `sentry`, `manual-run`, `retry-run`, `debug-analysis` |
| `JOB_TYPE` | `trello`, `github`, `jira`, `linear`, `sentry`, `manual-run`, `retry-run`, `debug-analysis` |
| `JOB_DATA` | JSON-encoded job payload |
| `CASCADE_CREDENTIAL_KEYS` | Comma-separated list of credential env var names |
| Individual credential vars | Pre-loaded project credentials (e.g., `GITHUB_TOKEN_IMPLEMENTER`) |
Expand All @@ -106,6 +107,7 @@ type JobData =
| TrelloJobData // Trello webhook payload
| GitHubJobData // GitHub webhook payload
| JiraJobData // JIRA webhook payload
| LinearJobData // Linear webhook payload
| SentryJobData // Sentry webhook payload
| ManualRunJobData // Dashboard-initiated run
| RetryRunJobData // Retry a failed run
Expand Down
7 changes: 5 additions & 2 deletions docs/architecture/02-webhook-pipeline.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Webhook Pipeline

Webhooks from external providers (Trello, GitHub, JIRA, Sentry) are processed through a two-layer system: a **webhook handler factory** that handles HTTP concerns, and a **router platform adapter** that implements the business logic pipeline.
Webhooks from external providers (Trello, JIRA, Linear, GitHub, Sentry) are processed through a two-layer system: a **webhook handler factory** that handles HTTP concerns, and a **router platform adapter** that implements the business logic pipeline.

## Webhook Handler Factory

Expand All @@ -16,7 +16,7 @@ Each webhook endpoint provides a `WebhookHandlerConfig`:

```typescript
interface WebhookHandlerConfig {
source: string; // 'trello' | 'github' | 'jira' | 'sentry'
source: string; // 'trello' | 'github' | 'jira' | 'linear' | 'sentry'
parsePayload: (c: Context) => ParseResult;
verifySignature?: (ctx, rawBody, projectId?) => VerificationResult | null;
processWebhook: (payload, eventType?, headers?) => Promise<WebhookLogOverrides>;
Expand All @@ -37,6 +37,7 @@ The factory handles:
| `parseGitHubPayload()` | JSON or form-encoded body | `X-GitHub-Event` header |
| `parseTrelloPayload()` | JSON body | `action.type` field |
| `parseJiraPayload()` | JSON body | `webhookEvent` field |
| `parseLinearPayload()` | JSON body | `type` field |
| `parseSentryPayload()` | JSON body | `Sentry-Hook-Resource` header |

## Platform Adapters
Expand Down Expand Up @@ -81,6 +82,7 @@ interface ParsedWebhookEvent {
| `TrelloRouterAdapter` | `src/router/adapters/trello.ts` | `boardId` |
| `GitHubRouterAdapter` | `src/router/adapters/github.ts` | `repoFullName` |
| `JiraRouterAdapter` | `src/router/adapters/jira.ts` | JIRA project key |
| `LinearRouterAdapter` | `src/router/adapters/linear.ts` | Linear team ID |
| `SentryRouterAdapter` | `src/router/adapters/sentry.ts` | CASCADE `projectId` (from URL) |

## The 12-Step Pipeline
Expand Down Expand Up @@ -144,6 +146,7 @@ Each provider's verification function checks for a stored `webhook_secret` crede
| GitHub | `X-Hub-Signature-256` | HMAC-SHA256 |
| Trello | Custom verification | Trello-specific |
| JIRA | `X-Hub-Signature` | HMAC-SHA256 |
| Linear | `linear-signature` | HMAC-SHA256 (hex, no prefix) |
| Sentry | `Sentry-Hook-Signature` | HMAC-SHA256 |

If no webhook secret is configured for a project, verification is skipped (returns `null`).
20 changes: 16 additions & 4 deletions docs/architecture/03-trigger-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ interface TriggerHandler {
```typescript
interface TriggerContext {
project: ProjectConfig;
source: TriggerSource; // 'trello' | 'github' | 'jira' | 'sentry'
source: TriggerSource; // 'trello' | 'github' | 'jira' | 'linear' | 'sentry'
payload: unknown; // Raw webhook payload
personaIdentities?: PersonaIdentities; // GitHub bot identities
}
Expand All @@ -64,12 +64,16 @@ interface TriggerResult {

## Built-in Triggers

Registration happens in `src/triggers/builtins.ts`, which delegates to per-platform `register.ts` files:
Registration happens in `src/triggers/builtins.ts`. PM providers (Trello, JIRA, Linear) contribute triggers via the manifest registry; SCM and alerting providers use their own `register.ts` functions:

```typescript
function registerBuiltInTriggers(registry: TriggerRegistry): void {
registerTrelloTriggers(registry);
registerJiraTriggers(registry);
// PM providers register via the manifest registry (spec 006/009 pattern)
for (const manifest of listPMProviders()) {
for (const handler of manifest.triggerHandlers) {
registry.register(handler);
}
}
registerGitHubTriggers(registry);
registerSentryTriggers(registry);
}
Expand Down Expand Up @@ -109,6 +113,14 @@ function registerBuiltInTriggers(registry: TriggerRegistry): void {
| `PrReadyToMergeTrigger` | PR approved + checks pass | PM status update (no agent) |
| `PrConflictDetectedTrigger` | Merge conflict on PR | `resolve-conflicts` |

### Linear triggers (`src/triggers/linear/`)

| Handler | Event | Agent |
|---------|-------|-------|
| `LinearCommentMentionTrigger` | Bot @mentioned in issue comment | `respond-to-planning-comment` |
| `LinearStatusChangedTrigger` | Issue state transition | Per-status mapping |
| `LinearReadyToProcessLabelTrigger` | "cascade-ready" label added | `splitting` |

### Sentry triggers (`src/triggers/sentry/`)

| Handler | Event | Agent |
Expand Down
8 changes: 7 additions & 1 deletion docs/architecture/08-config-credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ The config provider loads project configuration from the database with in-memory
| `loadProjectConfigByBoardId(boardId)` | Trello board ID | `{ project, config }` |
| `loadProjectConfigByRepo(repo)` | GitHub `owner/repo` | `{ project, config }` |
| `loadProjectConfigByJiraProjectKey(key)` | JIRA project key | `{ project, config }` |
| `loadProjectConfigByLinearTeamId(teamId)` | Linear team ID | `{ project, config }` |
| `loadProjectConfigById(id)` | CASCADE project ID | `{ project, config }` |

### Caching

`src/config/configCache.ts` — in-memory cache with TTL populated at service startup. Caches:
- Full config object
- Per-project lookups by board ID, repo, JIRA key
- Per-project lookups by board ID, repo, JIRA key, Linear team ID
- Invalidated on config writes (via tRPC mutations)

## Config Schema
Expand Down Expand Up @@ -104,6 +105,11 @@ await withTrelloCredentials({ apiKey, token }, async () => {
await withJiraCredentials({ email, apiToken, baseUrl }, async () => {
// All JIRA API calls use these credentials
});

// Linear
await withLinearCredentials({ apiKey }, async () => {
// All Linear API calls use these credentials
});
```

## Credential Encryption
Expand Down
1 change: 1 addition & 0 deletions docs/cascade-directory.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ FEATURE_FLAGS=new-parser,strict-validation

```
TRELLO_API_KEY, TRELLO_TOKEN, GITHUB_TOKEN,
LINEAR_API_KEY, LINEAR_WEBHOOK_SECRET,
OPENROUTER_API_KEY, CASCADE_WORKSPACE_DIR,
CASCADE_LOCAL_MODE, CASCADE_INTERACTIVE, CONFIG_PATH,
PORT, LOG_LEVEL, LLMIST_LOG_FILE, LLMIST_LOG_TEE,
Expand Down
24 changes: 22 additions & 2 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,26 @@ node bin/cascade.js projects integration-set my-project \
--config '{"baseUrl":"https://yourorg.atlassian.net","projectKey":"PROJ","statuses":{"todo":"To Do","inProgress":"In Progress","inReview":"In Review"}}'
```

### Linear

1. Generate a **Personal API key** from https://linear.app/settings/api
2. (Optional) Create a webhook in your Linear workspace settings and note the signing secret

```bash
# Store Linear credentials (project-scoped)
node bin/cascade.js projects credentials-set my-project --key LINEAR_API_KEY --value lin_api_... --name "Linear API Key"

# Optional: webhook secret for signature verification
node bin/cascade.js projects credentials-set my-project --key LINEAR_WEBHOOK_SECRET --value ... --name "Linear Webhook Secret"

# Configure the integration
# teamId: your Linear team UUID (find it via Settings > API or the team URL)
# statuses: map Cascade lifecycle stages to Linear workflow state IDs
node bin/cascade.js projects integration-set my-project \
--category pm --provider linear \
--config '{"teamId":"TEAM_UUID","statuses":{"todo":"STATE_UUID","inProgress":"STATE_UUID","done":"STATE_UUID"},"labels":{"readyToProcess":"LABEL_UUID","processing":"LABEL_UUID"}}'
```

---

## 9. Set Up Webhooks
Expand All @@ -285,7 +305,7 @@ node bin/cascade.js webhooks create my-project \
--callback-url https://your-tunnel.ngrok.io
```

This creates webhooks on GitHub (and Trello if configured) pointing to your Router.
This creates webhooks on GitHub (and Trello if configured) pointing to your Router. For Linear, create the webhook manually in your Linear workspace settings, pointing to `https://your-router-host/linear/webhook`.

---

Expand Down Expand Up @@ -323,7 +343,7 @@ node bin/cascade.js projects trigger-discover --agent implementation

## 11. Test It

1. Create a card in your PM tool (Trello/Jira) with a clear description of what code change you want
1. Create a card in your PM tool (Trello/Jira/Linear) with a clear description of what code change you want
2. Move it to the status that triggers the implementation agent (or add the "Ready to Process" label)
3. Watch the dashboard — a new run should appear within seconds
4. The agent clones your repo, writes code, and opens a pull request
Expand Down
Loading