**Scope:**All files matching **/*.{ts,tsx}
Purpose: Code Style & Structure specifics
-
Write concise, functional code with proper types
// Good function mergeConfigs<T>(base: T, override: Partial<T>): T { return { ...base, ...override } } // Avoid class ConfigMerger { merge(base: any, override: any) { return Object.assign({}, base, override) } }
-
Use Bun native modules when available
// Good import { file } from 'bun' // Avoid import { readFile } from 'node:fs/promises' const config = await file('config.json').json() const config = JSON.parse(await readFile('config.json', 'utf-8'))
-
Use descriptive variable names with proper prefixes
// Good const isConfigValid = validateConfig(config) const hasCustomOptions = Boolean(options.custom) const shouldUseDefaults = !configExists || isConfigEmpty // Avoid const valid = check(cfg) const custom = !!options.custom const defaults = !exists || empty
-
Write proper JSDoc comments for public APIs
/** * Loads configuration from a file or remote endpoint * @param options - Configuration options * @param options.name - Name of the config file * @param options.cwd - Working directory (default: process.cwd()) * @returns Resolved configuration object * @throws {ConfigError} When config loading fails * @example * ```ts * const config = await loadConfig({ * name: 'myapp', * defaultConfig: { port: 3000 } * }) * ``` */ async function loadConfig<T>(options: Config<T>): Promise<T>
-
Use proper module organization
export { ConfigError } from './errors' // config.ts export { loadConfig } from './loader' export type { Config, ConfigOptions } from './types'
-
Follow consistent error handling patterns
// Good const result = await loadConfig(options).catch((error) => { console.error('Config loading failed:', error) return options.defaultConfig }) // Avoid try { const result = await loadConfig(options) } catch (e) { console.log('Error:', e) }
-
Use proper type assertions
// Good const config = result as Config if (!isValidConfig(config)) throw new Error('Invalid config') // Avoid const config = result as any
**Scope:**All files matching **/*.{ts,tsx,md}
Purpose: Documentation specific rules
- Document all public APIs thoroughly
- Include TypeScript type information
- Provide clear function signatures
- Document config options and defaults
- Include return type information
- Document async behavior
- Provide basic usage examples
- Include complex configuration examples
- Document all supported config formats
- Show browser usage examples
- Include TypeScript configuration examples
- Document config merging behavior
- Document generic type parameters
- Explain type constraints
- Document interface properties
- Include type union explanations
- Document type generation features
- Provide type utility examples
- Document common error scenarios
- Include error handling examples
- Document error recovery options
- Explain validation errors
- Document browser-specific errors
- Include troubleshooting guides
- Include runnable code examples
- Provide TypeScript examples
- Show error handling patterns
- Include browser environment examples
- Document testing approaches
- Include CLI usage examples
- Keep documentation up to date
- Use consistent formatting
- Include inline code comments
- Document breaking changes
- Maintain a changelog
- Include version information
- Maintain clear docs organization
- Use proper markdown formatting
- Include table of contents
- Organize by topic
- Keep related docs together
- Use proper headings
- Use clear and concise language
- Include proper code blocks
- Document all parameters
- Provide return value descriptions
- Include usage notes
- Document dependencies
- Keep examples current
**Scope:**All files matching **/*.{ts,tsx}
Purpose: Error Handling and Validation specifics
-
Use early returns and guard clauses for validation
function loadConfig<T>(options: Config<T>) { if (!options.name) throw new Error('Config name is required') if (!isObject(options.defaultConfig)) throw new Error('Default config must be an object') // Continue with valid input }
-
Implement proper error types
class ConfigError extends Error { constructor( message: string, public readonly code: string, public readonly details?: unknown ) { super(message) this.name = 'ConfigError' } }
-
Use descriptive error messages
throw new ConfigError( `Failed to load config file: ${filePath}`, 'CONFIG_LOAD_ERROR', { cause: error } )
-
Handle async errors properly
async function loadConfigFile(path: string) { try { const content = await Bun.file(path).text() return JSON.parse(content) } catch (error) { if (error instanceof SyntaxError) throw new ConfigError('Invalid JSON in config file', 'PARSE_ERROR') throw new ConfigError('Failed to read config file', 'READ_ERROR') } }
-
Implement proper error logging
function handleError(error: unknown) { if (error instanceof ConfigError) { console.error(`[${error.code}] ${error.message}`) if (error.details) console.debug('Error details:', error.details) } else { console.error('Unexpected error:', error) } }
-
Use error boundaries for unexpected errors
try { await loadConfig(options) } catch (error) { handleError(error) return options.defaultConfig ?? {} }
-
Ensure errors are typed when using Result types
import { err, ok, Result } from 'neverthrow' function validateConfig(config: unknown): Result<Config, ConfigError> { if (!isValidConfig(config)) return err(new ConfigError('Invalid config format', 'VALIDATION_ERROR')) return ok(config) }
**Scope:**All files matching **/*.{ts,tsx}
Purpose: Key Conventions specifics
-
Prefer browser-compatible implementations when possible
// Good - Browser compatible const config = await fetch('/api/config').then(r => r.json()) // Avoid - Node.js specific const config = require('./config')
-
Aim for comprehensive test coverage
// Test both success and failure cases describe('loadConfig', () => { it('success case - load config', async () => {}) it('failure case - handle errors', async () => {}) it('edge case - malformed config', async () => {}) })
-
Use proper TypeScript types instead of
any// Good function loadConfig<T extends Record<string, unknown>>(options: Config<T>): Promise<T> // Avoid function loadConfig(options: any): Promise<any>
-
Use consistent error handling and logging
// Good console.error('Failed to load config:', error) return options.defaultConfig // Avoid console.log('Error:', e) throw e
-
Follow file naming conventions
config.ts // Core functionality config.test.ts // Test files config.types.ts // Type definitions .{name}.config.ts // Config files -
Use proper exports and imports
// Good export { loadConfig } from './loader' export type { Config } from './types' // Avoid export default { loadConfig, Config, }
-
Maintain consistent directory structure
src/ // Source code ββ index.ts // Main exports ββ types.ts // Type definitions ββ config.ts // Configuration ββ merge.ts // Deep merge ββ utils/ // Utilities -
Follow ESLint rules and maintain consistent style
// Good - Follow ESLint config const config = { name: 'app', port: 3000, } // Avoid - Inconsistent style const config = { name: 'app', port: 3000 }
**Scope:**All files matching **/*
Purpose: Project Structure specifics
ββ package.json # Package configuration
ββ tsconfig.json # TypeScript configuration
ββ eslint.config.ts # ESLint configuration
ββ bunfig.toml # Bun configuration
ββ README.md # Project documentation
ββ CHANGELOG.md # Version history
ββ LICENSE.md # License information
src/
ββ index.ts # Main entry point
ββ types.ts # Type definitions
ββ config.ts # Configuration loading
ββ merge.ts # Deep merge implementation
ββ utils/ # Utility functions
ββ generated/ # Generated type files
test/
ββ bunfig.test.ts # Main test suite
ββ cli.test.ts # CLI tests
ββ tmp/ # Temporary test files
β ββ config/ # Test config files
β ββ generated/ # Test generated files
ββ fixtures/ # Test fixtures
docs/
ββ intro.md # Introduction guide
ββ usage.md # Usage documentation
ββ api/ # API documentation
ββ .vitepress/ # VitePress configuration
ββ public/ # Static assets
.vscode/ # VS Code configuration
.github/ # GitHub configuration
ββ workflows/ # CI/CD workflows
ββ FUNDING.yml # Funding information
.cursor/ # Cursor IDE configuration
ββ rules/ # Project rules
dist/
ββ index.js # Main bundle
ββ index.d.ts # Type definitions
ββ cli.js # CLI bundle
- Keep related files together
- Use consistent file naming
- Follow module organization patterns
- Maintain clear separation of concerns
- Document directory purposes
- Keep directory structure flat when possible
-
Use consistent indentation (2 spaces)
// Good function loadConfig<T>(options: Config<T>) { if (!options.name) throw new Error('Config name is required') return options.defaultConfig } // Avoid function loadConfig<T>(options: Config<T>) { if (!options.name) throw new Error('Config name is required') return options.defaultConfig }
-
Use concise syntax for simple conditionals
// Good if (!options.name) throw new Error('Config name is required') // Avoid if (!options.name) { throw new Error('Config name is required') }
-
Format function declarations consistently
// Good async function loadConfig<T>( options: Config<T>, context?: Context ): Promise<T> { // Implementation } // Avoid async function loadConfig<T>(options: Config<T>, context?: Context): Promise<T> { // Implementation }
-
Format type definitions clearly
// Good interface Config<T = Record<string, any>> { name: string cwd?: string defaultConfig?: T endpoint?: string } // Avoid interface Config<T = Record<string, any>> { name: string, cwd?: string, defaultConfig?: T, endpoint?: string }
-
Use proper spacing in object literals
// Good const config = { name: 'app', options: { port: 3000, host: 'localhost', }, } // Avoid const config = { name: 'app', options: { port: 3000, host: 'localhost' } }
-
Format imports consistently
// Good import { describe, expect, it } from 'bun:test' // Avoid import { describe, expect, it } from 'bun:test' import { existsSync, readFileSync } from 'node:fs' import { resolve } from 'node:path' -
Use proper JSDoc formatting
// Good /** * Loads configuration from a file * @param options - Configuration options * @returns Resolved configuration */ function loadConfig(options: Config): Promise<unknown> // Avoid /** * Loads configuration from a file * @param options Configuration options * @returns Resolved configuration */ function loadConfig(options: Config): Promise<unknown>
-
Format test cases consistently
// Good describe('loadConfig', () => { it('should load default config', async () => { const result = await loadConfig(options) expect(result).toEqual(expected) }) }) // Avoid describe('loadConfig', () => { it('should load default config', async () => { const result = await loadConfig(options) expect(result).toEqual(expected) }) })
-
Write tests for all public APIs and utilities
describe('loadConfig', () => { it('should load default config when no file exists', async () => { const result = await loadConfig({ name: 'test', defaultConfig: { port: 3000 } }) expect(result).toEqual({ port: 3000 }) }) })
-
Use proper test organization with describe blocks
describe('bunfig', () => { describe('loadConfig', () => { // Config loading tests }) describe('deepMerge', () => { // Merge function tests }) })
-
Test edge cases and error scenarios
it('should handle malformed config files', async () => { const result = await loadConfig({ name: 'invalid', defaultConfig: { fallback: true } }) expect(result).toEqual({ fallback: true }) })
-
Use proper cleanup in tests
beforeEach(() => { // Setup test environment if (existsSync(testConfigDir)) rmSync(testConfigDir, { recursive: true }) mkdirSync(testConfigDir, { recursive: true }) }) afterEach(() => { // Cleanup test files if (existsSync(testConfigDir)) rmSync(testConfigDir, { recursive: true }) })
-
Use Bun's native test modules
import { describe, expect, it, mock } from 'bun:test'
-
Mock external dependencies properly
const mockFetch = mock(() => Promise.resolve({ ok: true, json: () => Promise.resolve({ config: 'value' }) }) ) globalThis.fetch = mockFetch
-
Test both success and failure paths
it('should handle network errors', async () => { mockFetch.mockImplementation(() => Promise.reject(new Error('Network error')) ) // Test error handling })
-
Use interfaces for configuration objects and public APIs
// Good interface Config<T = Record<string, any>> { name: string cwd?: string defaultConfig?: T endpoint?: string } // Avoid interface Config { name: string // ... }
-
Use
as constfor fixed values instead of enums// Good const CONFIG_EXTENSIONS = ['.ts', '.js', '.mjs', '.cjs', '.json'] as const // Avoid enum ConfigExtensions { TS = '.ts', JS = '.js' }
-
Use proper generic constraints for type safety
// Good function loadConfig<T extends Record<string, unknown>>(options: Config<T>): Promise<T> // Avoid function loadConfig<T>(options: Config<T>): Promise<T>
-
Implement strict type checking for config merging
// Good function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T // Avoid function deepMerge(target: any, source: any): any
-
Use type guards for runtime type checking
// Good function isObject(value: unknown): value is Record<string, unknown> { return typeof value === 'object' && value !== null }
-
Export types explicitly for public APIs
// Good export type { Config, ConfigOptions } export interface DeepMergeOptions { // ... }
Scope: General information based on the latest ./README.md content
Purpose: Documentation for the buddy package
Sync: manual β nothing regenerates this section. When README.md changes, copy its body (from the tagline blockquote through the licence, without the badge link definitions) back in here; bun run check:docs validates both files.
AI code review and dependency updates, in one teammate that runs on your CI with your keys.
Buddy does two jobs that usually take two bots and two subscriptions.
It reviews code β pull requests and your local working tree β posting inline findings anchored to the lines you changed, answering @buddy questions in the thread, gating merges with real check runs, and repairing failing CI when the fix is unambiguous. An alternative to CodeRabbit and friends, except it runs as a step in your own workflow, against a provider you choose, with no third-party app installed on your repository.
It also manages dependencies β scanning across npm, Bun, yarn, pnpm, Composer, Docker, GitHub Actions, pkgx, Launchpad, Go, Rust, Python, Ruby and Zig, grouping related packages, fetching real changelogs, and keeping a pinned dashboard issue. An alternative to Dependabot and Renovate, and it will migrate your existing config from either.
Neither half requires the other. Run the reviewer with no dependency workflows, run the updater with no API key, or run both.
- Inline Findings: Anchored to changed lines, describing the failure rather than a style preference
- Incremental by Default: A second push gets new findings, not the ones you already read
- Conversational:
@buddy review,full-review,summary,pause,resume,rebase,rememberβ or just ask a question - Local Review:
buddy reviewreads your working tree, so problems are found before the PR exists - Works Without a Key:
--lightruns secret scanning, actionlint, shellcheck, hadolint, markdownlint and syntax checks with no model and no network - Merge Gates: Title format, description quality, linked issue and dependency policy published as a check run
- CI Repair:
buddy fix-ciclassifies a failing run and opens the fix when it is clear - Pipeable:
--format json,githubannotations, oragentto hand findings straight to a coding agent - Your Provider: Anthropic, OpenAI, Google, OpenRouter, or any OpenAI-compatible endpoint
- Lightning Fast Execution: Built with Bun for maximum performance
- Intelligent Scanning: Uses
bun outdatedand GitHub releases API for accurate, real-time dependency detection - Optimized CI/CD: Minimal resource usage with smart caching
- Multi-Package Manager: Full support for Bun, npm, yarn, pnpm, Composer, Zig, pkgx & Launchpad
- GitHub Actions: Automatically updates workflow dependencies (
actions/checkout@v4, etc.) - Docker Images: Detects and updates Dockerfile base images and versions
- Zig Dependencies: Manages build.zig.zon dependencies with URL and hash tracking
- Lock File Awareness: Respects and updates all lock file formats
- Configurable Update Strategies: Choose from major, minor, patch, or all updates
- Flexible Package Grouping: Group related packages for cleaner, focused PRs
- Intelligent Conflict Detection: Prevents breaking changes with smart dependency analysis
- Security-First Updates: Checks every dependency against the OSV.dev advisory database, and creates vulnerability fixes as their own PR ahead of routine updates
- Dependency Dashboard: Centralized GitHub issue with complete dependency overview
- Interactive Rebase: One-click PR updates via checkbox interface
- Real-time Status Tracking: Live monitoring of all open PRs and pending updates
- Comprehensive Reporting: Detailed update summaries with confidence metrics
- Multi-Format Tables: Separate sections for npm, PHP/Composer, Zig, pkgx/Launchpad, and GitHub Actions
- Rich Metadata: Confidence badges, adoption metrics, age indicators, and download stats
- Detailed Changelogs: Automatic release notes and breaking change detection
- Professional Formatting: Clean, readable PR descriptions with proper categorization
- Zero Configuration: Works immediately with intelligent defaults
- Interactive Setup: Renovate-like guided configuration with validation
- Migration Tools: Seamless import from existing Renovate and Dependabot setups
- TypeScript Config: Full type safety with
buddy.config.ts
- Plugin Ecosystem: Built-in Slack, Discord, and Jira integrations
- Custom Hooks: Extensible system for organization-specific workflows
- CI/CD Ready: Pre-built GitHub Actions workflows for all use cases
- API Access: Programmatic control for advanced automation
# Install globally
bun add -g @buddysh/buddy
# Interactive setup (recommended)
buddy setup
# Non-interactive setup for CI/CD
buddy setup --non-interactive
# Non-interactive with specific preset
buddy setup --non-interactive --preset testing --verbose
# Or run directly for scanning only
buddy scanThe easiest way to get started is with the interactive setup command:
buddy setupThis comprehensive setup wizard will guide you through configuring automated dependency updates for your project in a Renovate-like experience.
For CI/CD pipelines and automated deployments, use the non-interactive mode:
# Basic non-interactive setup (uses defaults)
buddy setup --non-interactive
# Specify preset and token setup
buddy setup --non-interactive --preset testing --token-setup existing-secret --verbose
# Production setup with security focus
buddy setup --non-interactive --preset security --token-setup existing-secretAvailable options:
--non-interactive- Skip all prompts, use defaults--preset <type>- Workflow preset:standard,high-frequency,security,minimal,testing(default:standard)--token-setup <type>- Token mode:default-token,existing-secret,new-pat(default:default-token)
The setup process includes:
- Environment checks - Validates git repository, Node.js/Bun installation
- Conflict detection - Scans for existing dependency management tools (Renovate, Dependabot)
- Git configuration - Ensures proper git user setup
- GitHub CLI detection - Suggests helpful tools for authentication
- Project type detection - Identifies library, application, monorepo, or unknown projects
- Package manager detection - Detects Bun, npm, yarn, pnpm with lock file validation
- Dependency ecosystem analysis - Finds pkgx, Launchpad dependency files
- GitHub Actions discovery - Scans existing workflows for updates
- Intelligent recommendations - Suggests optimal setup based on project characteristics
- Visual progress bar - Real-time completion percentage with progress indicators
- Step-by-step guidance - Clear indication of current and completed steps
- Time tracking - Setup duration monitoring
- Recovery capabilities - Resume from failures with detailed error reporting
π Step 1: Configuration Migration & Discovery
- Tool Detection - Automatically detects existing Renovate and Dependabot configurations
- Seamless Migration - Imports settings, schedules, package rules, and ignore patterns
- Compatibility Analysis - Identifies incompatible features and provides alternatives
- Migration Report - Detailed summary of migrated settings and confidence levels
- Plugin Discovery - Automatically detects available integrations (Slack, Discord, Jira)
- Environment Detection - Scans for webhook URLs, API tokens, and configuration files
- Plugin Loading - Enables discovered integrations for setup completion notifications
- Custom Plugins - Supports custom plugin definitions in
.buddy/plugins/directory
π Step 3: Repository Detection & Validation
- Automatically detects your GitHub repository from git remote
- API validation - Tests repository access and permissions via GitHub API
- Repository health checks - Validates issues, permissions, and settings
- Private repository support - Enhanced validation for private repositories
- Guides you through creating a Personal Access Token (PAT)
- Scope validation - Explains required scopes (
repo,workflow) with examples - Token testing - Validates token permissions before proceeding
- Helps set up repository secrets for enhanced features
- Walks you through GitHub Actions permissions configuration
- Permission verification - Tests workflow permissions in real-time
- Organization settings - Guidance for organization-level permissions
- Ensures proper workflow permissions for PR creation
βοΈ Step 6: Intelligent Workflow Configuration Choose from several carefully crafted presets with smart recommendations:
- Standard Setup (Recommended) - Dashboard updates 3x/week, balanced dependency updates
- High Frequency - Check for updates multiple times per day
- Security Focused - Frequent patch updates with security-first approach
- Minimal Updates - Weekly checks, lower frequency
- Development/Testing - Manual triggers + frequent checks for testing
- Custom Configuration - Advanced schedule builder with cron preview
- Creates
buddy.config.tswith repository-specific settings - Project-aware defaults - Configuration optimized for detected project type
- Ecosystem integration - Includes detected package managers and dependency files
- Includes sensible defaults and customization options
π Step 8: Workflow Generation & Validation
- Generates two GitHub Actions workflows:
buddy.yml- Unified workflow (rebase checks, dependency updates, dashboard management)buddy-security.yml- Security audit, kept separate so it can trigger on its own path filters
- Removes stale
buddy-check.yml,buddy-update.ymlandbuddy-dashboard.ymlfiles from earlier versions - YAML validation - Ensures generated workflows are syntactically correct
- Security best practices - Validates token usage and permissions
- Workflow testing - Verifies generated workflows meet requirements
π― Step 9: Comprehensive Validation & Instructions
- Setup verification - Validates all generated files and configurations
- Workflow testing - Tests generated workflow syntax and requirements
- Clear next steps - Git commands and repository setup instructions
- Documentation links - Direct links to GitHub settings pages
- Troubleshooting guide - Common issues and solutions
- Plugin Execution - Executes loaded integration hooks for setup completion
- Slack Notifications - Rich setup completion messages with repository details
- Discord Embeds - Colorful setup completion notifications with project information
- Jira Tickets - Automatic task creation for tracking setup completion
- Custom Hooks - Extensible system for organization-specific integrations
# Setup commands
buddy setup # Interactive setup (recommended)
buddy setup --non-interactive # Non-interactive with defaults
buddy setup --non-interactive --preset testing --verbose
# Scan for dependency updates
buddy scan
buddy scan --verbose
# Check specific packages
buddy scan --packages "react,typescript,@types/node"
# Check packages with glob patterns
buddy scan --pattern "@types/_"
# Apply different update strategies
buddy scan --strategy minor
buddy scan --strategy patch
# Update dependencies and create PRs
buddy update --dry-run
buddy update
# Check for rebase requests and update PRs
buddy update-check
buddy update-check --dry-run
buddy update-check --verbose
# Get help
buddy --helpCreate a buddy.config.ts file in your project root:
import type { BuddyConfig } from '@buddysh/buddy'
const config: BuddyConfig = {
verbose: false,
// Repository settings for PR creation
repository: {
provider: 'github',
owner: 'your-org',
name: 'your-repo',
token: process.env.GITHUB_TOKEN,
baseBranch: 'main'
},
// Package update configuration
packages: {
strategy: 'all', // 'major' | 'minor' | 'patch' | 'all'
ignore: [
'legacy-package',
'@types/node' // Example ignores
],
groups: [
{
name: 'TypeScript Types',
patterns: ['@types/*'],
strategy: 'minor'
},
{
name: 'ESLint Ecosystem',
patterns: ['eslint*', '@typescript-eslint/*'],
strategy: 'patch'
}
]
},
// Pull request settings
pullRequest: {
titleFormat: 'chore(deps): {title}',
commitMessageFormat: 'chore(deps): {message}',
reviewers: ['maintainer1', 'maintainer2'],
labels: ['dependencies', 'automated'],
autoMerge: {
enabled: true,
strategy: 'squash', // 'merge', 'squash', or 'rebase'
conditions: ['patch-only'] // Only auto-merge patch updates
}
},
// Dependency dashboard settings
dashboard: {
enabled: true,
title: 'Dependency Dashboard',
pin: true,
labels: ['dependencies', 'dashboard'],
assignees: ['maintainer1'],
showOpenPRs: true,
showDetectedDependencies: true
}
}
export default configBuddy can automatically migrate your existing dependency management configurations from Renovate and Dependabot, making the transition seamless.
- Renovate -
renovate.json,.renovaterc, package.json renovate config - Dependabot -
.github/dependabot.yml,.github/dependabot.yaml
- Automatic Detection - Scans for existing configuration files
- Smart Conversion - Maps settings to Buddy equivalents
- Compatibility Check - Identifies unsupported features
- Migration Report - Provides detailed conversion summary
# Migration happens automatically during setup
buddy setup
# Or use programmatically
import { ConfigurationMigrator } from '@buddysh/buddy/setup'
const migrator = new ConfigurationMigrator()
const tools = await migrator.detectExistingTools()
const result = await migrator.migrateFromRenovate('renovate.json')| Renovate | Dependabot | Buddy | Notes |
|---|---|---|---|
schedule |
schedule.interval |
Workflow presets | Mapped to Standard/High-Frequency/Minimal |
packageRules |
ignore |
Package groups & ignore lists | Preserves grouping logic |
automerge |
N/A | Auto-merge settings | Includes strategy preferences |
assignees/reviewers |
N/A | PR configuration | Maintains team assignments |
Buddy includes a setup-time plugin system that notifies your collaboration tools when buddy setup completes. (Runtime events β scans, pull requests, merges β go through the notifications key in buddy.config.ts instead; that is the system a new integration should hook into.)
# Set environment variable
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
# Or create config file
echo "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK" > .buddy/slack-webhookFeatures:
- Rich setup completion notifications
- Repository and project details
- Reads the webhook from the env var, or from the
.buddy/slack-webhookfile
# Set environment variable
export DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/YOUR/DISCORD/WEBHOOK"
# Or create config file
echo "https://discord.com/api/webhooks/YOUR/DISCORD/WEBHOOK" > .buddy/discord-webhookFeatures:
- Colorful embed notifications
- Project type and package manager details
- Timestamp tracking
- Setup completion confirmations
# Set environment variables
export JIRA_API_TOKEN="your-jira-api-token"
export JIRA_BASE_URL="https://your-org.atlassian.net"
export JIRA_PROJECT_KEY="BUDDY" # Optional, defaults to BUDDYFeatures:
- Automatic ticket creation for setup completion
- Repository and project context
- Configurable project keys
- Setup tracking and documentation
Create custom integrations by defining plugins in .buddy/plugins/:
A hook declares an action rather than a function. JSON has no way to carry
one, and reading a string out of a config file to run as code would turn any
.buddy/plugins/*.json in a repository into arbitrary code execution on
whoever runs buddy setup. The payload names the event and the repository
and nothing else, plus whatever body adds β setup holds a token by the time
hooks run, and the plugin file chooses the URL.
Setup fires exactly one event: setup_complete, once, when setup finishes
β in interactive and non-interactive runs alike. Triggers naming anything else
still load (files written against the retired pre_setup / post_setup /
step_complete / validation_error vocabulary are tolerated) but never fire.
For runtime notifications β scans, pull requests, merges β use the
notifications key in buddy.config.ts: an exported webhook env var alone
does nothing at runtime.
import { Buddy, getConfig } from '@buddysh/buddy'
// Load configuration
const config = await getConfig()
// Create Buddy instance
const buddy = new Buddy(config)
// Scan for updates
const scanResult = await buddy.scanForUpdates()
console.log(`Found ${scanResult.updates.length} updates`)
// Check specific packages
const updates = await buddy.checkPackages(['react', 'typescript'])
// Create pull requests
if (scanResult.updates.length > 0) {
await buddy.createPullRequests(scanResult)
}
// Create or update dependency dashboard
const dashboardIssue = await buddy.createOrUpdateDashboard()
console.log(`Dashboard updated: ${dashboardIssue.url}`)The dependency dashboard provides a centralized view of all your repository's dependencies and open pull requests in a single GitHub issue. Similar to Renovate's dependency dashboard, it gives you complete visibility into your dependency management.
- π Single Overview: All dependencies and PRs in one place
- π Interactive Controls: Force retry/rebase PRs by checking boxes
- π Pinnable Issue: Keep dashboard at the top of your issues
- π·οΈ Smart Categorization: Organized by npm, GitHub Actions, and dependency files
- β‘ Auto-Updates: Refreshes when dependencies change
Buddy includes powerful rebase functionality that allows you to update existing pull requests with the latest dependency versions, similar to Renovate's rebase feature.
All Buddy pull requests include a rebase checkbox at the bottom:
---
- [ ] <!-- rebase-check -->If you want to update/retry this PR, check this box
---- Check the box: In any Buddy PR, check the rebase checkbox
- Automatic detection: Editing the PR body fires the workflow, which detects the checked box
- Updates applied: The PR is automatically updated with the latest dependency versions
- Checkbox unchecked: After successful rebase, the checkbox is automatically unchecked
You can also trigger rebase manually using the CLI:
# Check for PRs with rebase checkbox enabled and update them
buddy update-check
# Dry run to see what would be rebased
buddy update-check --dry-run
# With verbose output
buddy update-check --verboseBuddy includes a pre-built GitHub Actions workflow (.github/workflows/buddy.yml) that:
- π Event-driven: Triggers on
pull_request: [edited]andissues: [edited], so ticking a checkbox runs it immediately β no polling - π Scans all PRs: Finds Buddy PRs with checked rebase boxes
- π¦ Updates dependencies: Re-scans for latest versions and updates files
- π Updates PR content: Refreshes PR title, body, and file changes
- β Maintains workflow files: Updates GitHub Actions workflows (requires proper permissions)
For the rebase functionality to update GitHub Actions workflow files, you need proper permissions:
- Create a Personal Access Token with
repoandworkflowscopes - Add it as a repository secret named
BUDDY_TOKEN - The workflow automatically uses it when available
- Uses
GITHUB_TOKENwith limited permissions - Cannot update workflow files (
.github/workflows/*.yml) - Still updates package.json, lock files, and dependency files
- β package.json - npm/yarn/pnpm dependencies
- β Lock files - package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb
- β Dependency files - deps.yaml, dependencies.yaml, pkgx.yaml
- β Zig manifests - build.zig.zon with URL and hash updates
- β GitHub Actions - workflow files (with proper permissions)
- β PR content - Updated title, body, and metadata
# Create basic dashboard
buddy dashboard
# Create dashboard with custom title
buddy dashboard --title "My Dependencies"The unified workflow (.github/workflows/buddy.yml) automatically updates your dependency dashboard:
- π Scheduled: On the schedule your preset sets β often the same tick as the dependency update run
- π±οΈ Manual: Trigger from Actions tab with custom options
- π Auto-Pin: Keeps dashboard pinned by default
- π Dry-Run: Preview mode available
The dashboard automatically organizes your dependencies and shows:
## Open
The following updates have all been created. To force a retry/rebase of any, click on a checkbox below.
- [ ] <!-- rebase-branch=buddy/update-react-18 -->[chore(deps): update react to v18](../pull/123) (`react`)
- [ ] <!-- rebase-branch=buddy/update-types -->[chore(deps): update @types/node](../pull/124) (`@types/node`)
## Detected dependencies
<details><summary>npm</summary>
<blockquote>
<details><summary>package.json</summary>
- `react ^17.0.0`
- `typescript ^4.9.0`
- `@types/node ^18.0.0`
</details>
</blockquote>
</details>
<details><summary>github-actions</summary>
<blockquote>
<details><summary>.github/workflows/ci.yml</summary>
- `actions/checkout v3`
- `oven-sh/setup-bun v1`
</details>
</blockquote>
</details>Buddy's intelligent workflow delivers unmatched speed and accuracy:
- β‘ Lightning-Fast Scanning: Leverages
bun outdatedand parallel API calls for instant dependency analysis - π Universal Detection: Automatically discovers and parses all dependency files across your entire project
- π§ Smart Analysis: Evaluates security implications, breaking changes, and compatibility before suggesting updates
- π― Intelligent Grouping: Automatically clusters related packages to create focused, logical pull requests
- π Rich Context: Fetches comprehensive metadata including adoption rates, confidence scores, and detailed changelogs
- β¨ Professional PRs: Generates beautifully formatted pull requests with actionable insights and clear upgrade paths
Buddy automatically detects and updates the following dependency file formats:
- package.json - Traditional npm dependencies
- composer.json - PHP dependencies from Packagist
- composer.lock - PHP lock file with exact versions
- build.zig.zon - Zig package manager dependencies with URL and hash tracking
- deps.yaml/deps.yml - Launchpad/pkgx dependency declarations
- dependencies.yaml/dependencies.yml - Alternative dependency file format
- pkgx.yaml/pkgx.yml - pkgx-specific dependency files
- .deps.yaml/.deps.yml - Hidden dependency configuration files
- .github/workflows/*.yml - GitHub Actions workflow files
- .github/workflows/*.yaml - Alternative YAML extension
Detected anywhere in the tree, in all three naming conventions:
Dockerfile,Dockerfile.<suffix>- e.g.Dockerfile.prod<prefix>.dockerfile- e.g.docker/api.dockerfile, common in monoreposContainerfile,<prefix>.containerfile- the OCI/Podman spelling
All dependency files are parsed using the ts-pantry library to ensure compatibility with the pkgx registry ecosystem while maintaining support for tools like Launchpad that reuse the same registry format. GitHub Actions are detected by parsing uses: statements in workflow files and checking for updates via the GitHub releases API.
Buddy generates comprehensive pull requests with separate dependency tables for each ecosystem:
Full table with confidence badges, age, adoption metrics, and weekly download statistics:
| Package | Change | Age | Adoption | Passing | Confidence |
|---------|--------|-----|----------|---------|------------|
| lodash | ^4.17.20 β ^4.17.21 | π
| π | β
| π |
Focused table for PHP packages from Packagist:
| Package | Change | File | Status |
|---------|--------|------|--------|
| laravel/framework | ^10.0.0 β ^10.16.0 | composer.json | β
Available |
| phpunit/phpunit | ^10.0.0 β ^10.3.0 | composer.json | β
Available |
Focused table for Zig packages with repository links and update types:
| Package | Change | Type | File |
|---------|--------|------|------|
| httpz | 0.5.0 β 0.6.0 | π‘ minor | build.zig.zon |
Simplified table focusing on package updates and file locations:
| Package | Change | File | Status |
|---------|--------|------|--------|
| bun.com | ^1.2.16 β ^1.2.19 | deps.yaml | β
Available |
Workflow automation updates with direct links to repositories:
| Action | Change | File | Status |
|--------|--------|------|--------|
| actions/checkout | v4 β v4.2.2 | ci.yml | β
Available |
| oven-sh/setup-bun | v2 β v2.0.2 | release.yml | β
Available |
Each table is followed by detailed release notes, changelogs, and package statistics tailored to the dependency type.
all: Update all dependencies regardless of semver impactmajor: Only major version updatesminor: Minor and patch updates (no majors)patch: Only patch updates
Buddy supports configurable auto-merge for pull requests to reduce manual overhead:
const config: BuddyConfig = {
pullRequest: {
autoMerge: {
enabled: true,
strategy: 'squash', // 'merge', 'squash', or 'rebase'
conditions: ['patch-only'] // Optional: restrict to specific update types
}
}
}squash: Squash commits and merge (recommended for clean history)merge: Create a merge commit (preserves individual commits)rebase: Rebase and merge (linear history without merge commits)
patch-only: Only auto-merge patch version updates (safest)- No conditions: Auto-merge all updates (use with caution)
Each preset configures auto-merge appropriately:
- High Frequency Updates: Auto-merge patch updates only (6AM, 12PM, 6PM), manual review for minor updates (12AM)
- Security Focused: Auto-merge security patches every 6 hours
- Standard Project: Auto-merge daily patches, manual review for weekly/monthly updates
- Development/Testing: No auto-merge, dry-run by default, enhanced testing features.
The Development/Testing preset is specifically designed for testing and development environments:
- β° Every 5 minutes: Automated runs for rapid testing cycles
- π±οΈ Manual triggers: Full control via GitHub Actions UI
- π Dry run by default: Safe testing without making changes
- π Verbose logging: Detailed output for debugging
- π¦ Package-specific testing: Test updates for specific packages
- π Enhanced summaries: Detailed test reports with context
When running manually, you can customize:
- Update strategy: Choose patch, minor, major, or all updates
- Dry run mode: Preview changes without applying them
- Specific packages: Test updates for particular packages only
- Verbose logging: Control output detail level
- π§ͺ Testing new configurations
- π§ Debugging dependency issues
- π Monitoring update frequency
- π Validating workflow changes
- π Learning how Buddy works
Group related packages to create cleaner, more focused pull requests:
{
groups: [
{
name: 'React Ecosystem',
patterns: ['react*', '@types/react*'],
strategy: 'minor'
},
{
name: 'Development Tools',
patterns: ['eslint*', 'prettier*', '@typescript-eslint/*'],
strategy: 'patch'
}
]
}When Buddy finds updates, it creates PRs like:
chore(deps): update all non-major dependencies
This PR contains the following updates:
| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [typescript](https://www.typescriptlang.org/) | `^5.8.2` -> `^5.8.3` | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) |
---
### Release Notes
<details>
<summary>microsoft/TypeScript (typescript)</summary>
### [`v5.8.3`](https://github.com/microsoft/TypeScript/releases/tag/v5.8.3)
[Compare Source](https://github.com/microsoft/TypeScript/compare/v5.8.2...v5.8.3)
##### Bug Fixes
- Fix issue with module resolution
- Improve error messages
</details>
---
### Configuration
π
**Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
π¦ **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
β» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
π **Ignore**: Close this PR and you won't be reminded about this update again.
---
- [ ] <!-- rebase-check -->If you want to update/retry this PR, check this box
---
This PR was generated by [Buddy](https://github.com/stacksjs/buddy).
| Feature | Buddy | Dependabot | Renovate |
|---|---|---|---|
| Performance | β‘ Lightning fast (Bun-native) | π | π |
| Package Ecosystem | π Universal (8+ managers) | π¦ Limited scope | π¦ Limited scope |
| Setup Experience | π― Interactive + Zero config | β Simple | β Complex configuration |
| Docker Support | β Full Dockerfile updates | β No support | β Basic support |
| Configuration | π§ TypeScript + multiple formats | π YAML only | π JSON/JS only |
| Package Grouping | π¨ Intelligent + flexible | π Basic grouping | π§ Advanced but complex |
| Dashboard | π Rich interactive dashboard | β No dashboard | π Basic dashboard |
| Migration Tools | π Automated import | β Manual migration | β Manual migration |
| Vulnerability Alerts | β OSV.dev, prioritized PRs + dashboard | β GitHub Advisory | β OSV / GitHub Advisory |
| Private Registries | β
Config or .npmrc, per-scope |
β Supported | β Supported |
| GitHub Enterprise | β Zero-config on GHES runners | β Supported | β Supported |
| Self-hosting | β Full control | β GitHub-only | β Complex setup |
| Plugin System | π Extensible ecosystem | β Limited | π Advanced but complex |
Buddy includes powerful GitHub Actions workflow templates for different automation strategies:
# Basic dependency updates (generated by setup)
name: Buddy Update
on:
schedule:
- cron: '0 _/2 _ _ _' # Every 2 hours
workflow_dispatch:
inputs:
strategy:
description: Update strategy
required: false
default: patch
dry_run:
description: Dry run (preview only)
required: false
default: true
type: boolean
jobs:
dependency-update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bunx @buddysh/buddy scan --strategy ${{ github.event.inputs.strategy || 'patch' }} --verbose
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: ${{ github.event.inputs.dry_run != 'true' }}
run: bunx @buddysh/buddy update --strategy ${{ github.event.inputs.strategy || 'patch' }} --verbose
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}π Generate Advanced Workflows:
# Generate comprehensive GitHub Actions workflows
buddy generate-workflows
# This creates
# - buddy-comprehensive.yml (multi-strategy scheduling)
# - dependency-updates-daily.yml (patch updates)
# - dependency-updates-weekly.yml (minor updates)
# - dependency-updates-monthly.yml (major updates)
# - buddy-monorepo.yml (monorepo support)
# - buddy-docker.yml (Docker-based)π₯ Comprehensive Multi-Strategy Workflow:
The updated workflow system automatically:
- On your preset's schedule: All configured strategies with dry-run by default
- Manual trigger: Any strategy with configurable dry-run option
- Enhanced testing: Comprehensive validation and summaries
- Failure handling: Auto-creates GitHub issues
- Smart summaries: Rich GitHub Actions summaries
- Flexible scheduling: Each preset sets its own update and dashboard cadence
- Go to your repository SettingsβActionsβGeneral
- Under "Workflow permissions", select**"Read and write permissions"**
- β Check "Allow GitHub Actions to create and approve pull requests"
- Click "Save"
If your repository is part of an organization, you may also need to enable organization-level permissions:
- Go to your organization SettingsβActionsβGeneral
- Configure the same permissions as above
# Open GitHub settings pages directly
buddy open-settings
# Or manually visit
# Repository: https://github.com/YOUR_ORG/YOUR_REPO/settings/actions
# Organization: https://github.com/organizations/YOUR_ORG/settings/actionsIf you see errors like:
GitHub Actions is not permitted to create or approve pull requestsGraphQL: GitHub Actions is not permitted to create or approve pull requests (createPullRequest)
This indicates the permissions above need to be enabled. Both GitHub CLI and REST API methods require these permissions to create PRs from workflows.
For more details, see the GitHub documentation on managing GitHub Actions settings.
bun testbun install # not optional β see the note below
bun run buildNote
bun install is a hard prerequisite for every dev command. On a fresh clone without node_modules, bun test fails with over a hundred phantom errors (Cannot find package 'ts-pantry' and friends) that look like real bugs and are not.
Git hooks (staged lint on pre-commit, gitlint on commit-msg) are declared in package.json but are not installed automatically β run bunx bun-git-hooks once after cloning to activate them.
Please see our releases page for more information on what has changed recently.
Please see the Contributing Guide for details.
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
For casual chit-chat with others using this package:
Join the Stacks Discord Server
βSoftware that is free, but hopes for a postcard.β We love receiving postcards from around the world showing where Stacks is being used! We showcase them on our website too.
Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094, United States π
We would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us.
And a special thanks to Dan Scanlon for donating the stacks name on npm β¨
The MIT License (MIT). Please see LICENSE for more information.
Made with π
- Use pickier for linting β never use eslint directly
- Run
bunx --bun pickier .to lint,bunx --bun pickier . --fixto auto-fix - When fixing unused variable warnings, prefer
// eslint-disable-next-linecomments over prefixing with*
- Use stx for templating β never write vanilla JS (
var,document.*,window.*) in stx templates - Use crosswind as the default CSS framework which enables standard Tailwind-like utility classes
- stx
<script>tags should only contain stx-compatible code (signals, composables, directives)
- buddy handles dependency updates β not renovatebot
- better-dx provides shared dev tooling as peer dependencies β do not install its peers (e.g.,
typescript,pickier,bun-plugin-dtsx) separately ifbetter-dxis already inpackage.json - If
better-dxis inpackage.json, ensurebunfig.tomlincludeslinker = "hoisted"
