From c7e8235bf631d7ba5288cfbcc655cfdecb06e337 Mon Sep 17 00:00:00 2001 From: Zbigniew Sobiecki Date: Mon, 23 Mar 2026 15:12:34 +0000 Subject: [PATCH] docs: improve developer experience and onboarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add `dev:all` script (concurrently, with --kill-others-on-fail) to start router + dashboard + frontend in one command - Add `verify` script (lint + typecheck + unit tests) as the pre-PR check - Move both scripts to logical positions in package.json (dev:all after dev:web, verify after typecheck) - CONTRIBUTING.md: add missing `npm run build` step before dev servers; renumber setup steps 5→7; add trigger-discover step in Adding New Agents - README.md: add dev:all + verify to Commands table; update Contributing item 3 to use `npm run verify`; add MIT + Node.js badges - CLAUDE.md: add Quick Start as first Table of Contents entry Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 31 ++++++++++ CONTRIBUTING.md | 63 ++++++++++++++++---- README.md | 23 +++++-- package-lock.json | 149 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 + 5 files changed, 253 insertions(+), 16 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 038202ac..d00a1720 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,6 +13,37 @@ npm run dev # Router (webhook receiver, requires Redis) npm run dev:web # Dashboard frontend (separate terminal) ``` +## Table of Contents + +- [Quick Start](#quick-start) +- [Architecture](#architecture) +- [Development](#development) + - [Testing](#testing) + - [Linting](#linting) + - [Git Hooks](#git-hooks) +- [Key Directories](#key-directories) +- [Environment Variables](#environment-variables) +- [Database Configuration](#database-configuration) + - [Schema](#schema) + - [Database Scripts](#database-scripts) + - [Migration Workflow](#migration-workflow) + - [Credentials](#credentials) + - [Credential Encryption at Rest](#credential-encryption-at-rest) + - [GitHub Dual-Persona Model](#github-dual-persona-model) + - [Webhook Signature Verification](#webhook-signature-verification) + - [Integration Credential Resolution](#integration-credential-resolution) + - [Agent Trigger Configuration](#agent-trigger-configuration) + - [Review Agent Trigger Modes](#review-agent-trigger-modes) + - [PM Agent Trigger Modes](#pm-agent-trigger-modes) +- [Claude Code Engine](#claude-code-engine) +- [Codex Engine](#codex-engine) +- [Dashboard](#dashboard) +- [CLI (`cascade`)](#cli-cascade) +- [Adding New Triggers](#adding-new-triggers) +- [Adding New Agents](#adding-new-agents) +- [Agent Resilience Features](#agent-resilience-features) +- [Debugging Production Sessions](#debugging-production-sessions) + ## Architecture CASCADE runs as three services (no monolithic server mode): diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b8164c75..f56c68ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,12 @@ Thank you for your interest in contributing to Cascade! This guide will help you npm run db:migrate ``` -5. **Start Redis** (required for the router): +5. **Build the project**: + ```bash + npm run build + ``` + +6. **Start Redis** (required for the router): ```bash # macOS brew install redis && brew services start redis @@ -38,12 +43,22 @@ Thank you for your interest in contributing to Cascade! This guide will help you .cascade/setup.sh ``` -6. **Run the development servers**: +7. **Run the development servers**: + + Start all services in one terminal: + ```bash + npm run dev:all # Router + Dashboard API + Frontend (color-coded output) + ``` + + Or start each service in a separate terminal: ```bash - npm run dev # Router (webhook receiver) - npm run dev:web # Dashboard frontend (separate terminal) + npm run dev # Router (:3000) + node --env-file=.env dist/dashboard.js # Dashboard API (:3001) + npm run dev:web # Frontend (Vite, :5173) ``` + > **Note:** The Dashboard API must be running for the frontend to show data. The Vite dev server proxies `/trpc` and `/api` to `localhost:3001`. + ## Running Tests ```bash @@ -93,9 +108,7 @@ This is enforced by commitlint via lefthook pre-commit hooks. 3. **Ensure all checks pass**: ```bash - npm run lint - npm run typecheck - npm test + npm run verify # runs lint + typecheck + unit tests in one command ``` 4. **Open a PR** targeting the `dev` branch. PRs to `main` must come from `dev` (enforced by CI). @@ -121,9 +134,27 @@ See [CLAUDE.md](./CLAUDE.md) for a detailed architecture overview. Key directori ## Adding New Agents -1. Create the agent in `src/agents/` -2. Define its system prompt in `src/agents/prompts/` -3. Register it in the agent registry +Agents are defined using YAML definition files. Built-in definitions live in `src/agents/definitions/`. + +1. **Write a YAML definition** — model your file on an existing one in `src/agents/definitions/` (e.g. `implementation.yaml`) +2. **Import the definition**: + ```bash + cascade definitions import --file my-agent.yaml + ``` + Or use the **Agent Definitions** tab in the dashboard. +3. **Create an `agent_configs` row** to enable the agent for a project: + ```bash + cascade agents create --agent-type my-agent --project-id + ``` +4. **Discover available triggers** for the new agent type: + ```bash + cascade projects trigger-discover --agent my-agent # see available events + ``` + +5. **Configure triggers** — enable the events that should activate the agent: + ```bash + cascade projects trigger-set --agent my-agent --event pm:status-changed --enable + ``` ## The `.cascade/` Directory @@ -131,6 +162,18 @@ When Cascade works on a repository, it looks for a `.cascade/` directory at the See **[`.cascade/` Directory Guide](./docs/cascade-directory.md)** for the full reference. +## Troubleshooting + +| Problem | Cause | Fix | +|---------|-------|-----| +| `Cannot connect to Redis` | Redis not running | `redis-server` or `brew services start redis` | +| `ECONNREFUSED 5432` | PostgreSQL not running | `pg_ctl start` or start Docker | +| `dist/ not found` when running CLI | Build needed | `npm run build` | +| Frontend shows no data | Dashboard API not running | `node --env-file=.env dist/dashboard.js` | +| Node version error | Node < 22 | Install Node 22+ (`nvm use 22`) | +| Integration tests silently skip | No test database | `npm run test:db:up` first | +| `commitlint` hook fails | Non-conventional commit message | Use format `feat(scope): description` | + ## Getting Help - Open an [issue](https://github.com/mongrel-intelligence/cascade/issues) for bugs or feature requests diff --git a/README.md b/README.md index 0b5702ea..1dc3aadb 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ [![CI](https://github.com/mongrel-intelligence/cascade/actions/workflows/ci.yml/badge.svg)](https://github.com/mongrel-intelligence/cascade/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/mongrel-intelligence/cascade/graph/badge.svg)](https://codecov.io/gh/mongrel-intelligence/cascade) +[![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.** @@ -89,15 +91,22 @@ cp .env.example .env # Set DATABASE_URL and REDIS_URL npm run db:migrate ``` -Start each service in a separate terminal: +Start all three services with one command (requires a build first): ```bash -npm run dev # Router (webhook receiver, :3000) -npm run build && node --env-file=.env dist/dashboard.js # Dashboard API (:3001) -npm run dev:web # Dashboard frontend (Vite, :5173) +npm run build +npm run dev:all # Router + Dashboard API + Frontend, color-coded output ``` -> **Note:** The Vite dev server proxies `/trpc` and `/api` to `localhost:3001`, so the Dashboard API must be running for the frontend to work. See [CLAUDE.md](./CLAUDE.md#running-the-dashboard) for more details. +Or start each service in a separate terminal: + +```bash +npm run dev # Router (:3000) +node --env-file=.env dist/dashboard.js # Dashboard API (:3001) +npm run dev:web # Frontend (Vite, :5173) +``` + +> **Note:** The Vite dev server proxies `/trpc` and `/api` to `localhost:3001`, so the Dashboard API must be running for the frontend to work. ### Commands @@ -111,6 +120,8 @@ npm run dev:web # Dashboard frontend (Vite | `npm run build` | Compile TypeScript to `dist/` | | `npm run db:migrate` | Apply pending migrations | | `npm run db:studio` | Open Drizzle Studio | +| `npm run dev:all` | Start all services (router + dashboard + frontend) | +| `npm run verify` | Lint + typecheck + unit tests (pre-PR check) | --- @@ -156,7 +167,7 @@ For deeper documentation on all of these topics, see [CLAUDE.md](./CLAUDE.md). 1. Fork the repository and create a feature branch from `dev` 2. Make your changes with tests (`npm test`) -3. Ensure lint and typecheck pass (`npm run lint && npm run typecheck`) +3. Ensure all checks pass (`npm run verify`) 4. Open a pull request — Cascade will review its own PRs if configured to do so Please follow [Conventional Commits](https://www.conventionalcommits.org/) for commit messages. See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full guide. diff --git a/package-lock.json b/package-lock.json index 781e0f8f..d91a35b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,6 +61,7 @@ "@types/react-dom": "^19.2.3", "@vitest/coverage-v8": "^3.2.4", "commander": "^14.0.2", + "concurrently": "^9.2.1", "drizzle-kit": "^0.31.9", "jsdom": "^28.1.0", "lefthook": "^1.10.10", @@ -5117,6 +5118,121 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/concurrently/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/conventional-changelog-angular": { "version": "7.0.0", "dev": true, @@ -8939,6 +9055,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "funding": [ @@ -9008,6 +9134,19 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/siginfo": { "version": "2.0.0", "dev": true, @@ -9487,6 +9626,16 @@ "node": ">=20" } }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/trello.js": { "version": "1.2.8", "license": "MIT", diff --git a/package.json b/package.json index 8e448954..a22fdb1c 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "dev": "node --env-file=.env --import tsx/esm --watch src/router/index.ts", "dev:web": "cd web && npx vite", + "dev:all": "concurrently --kill-others-on-fail --names 'router,dashboard,web' --prefix-colors 'blue,green,cyan' \"npm run dev\" \"node --env-file=.env dist/dashboard.js\" \"npm run dev:web\"", "build": "tsc && npm run build:copy-yaml && npm run build:copy-system-prompts", "build:copy-yaml": "mkdir -p dist/agents/definitions && cp src/agents/definitions/*.yaml dist/agents/definitions/", "build:copy-system-prompts": "mkdir -p dist/agents/prompts && cp -r src/agents/prompts/templates dist/agents/prompts/", @@ -24,6 +25,7 @@ "lint": "biome check .", "lint:fix": "biome check --write .", "typecheck": "tsc --noEmit", + "verify": "npm run lint && npm run typecheck && npm test", "prepare": "lefthook install", "tool:download-session": "node --env-file=.env --import tsx tools/download-session.ts", "tool:run-local": "node --env-file=.env --import tsx tools/run-local.ts", @@ -100,6 +102,7 @@ "@types/react-dom": "^19.2.3", "@vitest/coverage-v8": "^3.2.4", "commander": "^14.0.2", + "concurrently": "^9.2.1", "drizzle-kit": "^0.31.9", "jsdom": "^28.1.0", "lefthook": "^1.10.10",