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
64 changes: 64 additions & 0 deletions skills/ppg-conductor/references/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ ppg spawn --name <name> --prompt-file /path/to/prompt.md --json --no-open
```

**Options:**

| Flag | Description |
|------|-------------|
| `-n, --name <name>` | Worktree/task name (default: auto-generated ID) |
Expand Down Expand Up @@ -195,6 +196,64 @@ ppg merge <wt-id> --force --json # Merge even if agents aren't

Cleanup sequence: kill tmux window, teardown env, `git worktree remove --force`, `git branch -D ppg/<name>`, set manifest status `cleaned`.

## ppg swarm

Run a predefined swarm template — spawns multiple agents from `.pg/swarms/` with prompts from `.pg/prompts/`.

```bash
# Run a swarm template (creates new worktree, spawns all agents)
ppg swarm code-review --var CONTEXT="Review the auth module" --json --no-open

# Run a swarm against an existing worktree (e.g., review a PR's worktree)
ppg swarm code-review --worktree wt-abc123 --var CONTEXT="Review PR #42" --json --no-open

# Override worktree name
ppg swarm code-review --name "auth-review" --var CONTEXT="Review auth changes" --json --no-open

# Target by worktree name
ppg swarm code-review --worktree feature-auth --var CONTEXT="Review auth feature" --json --no-open
```

**Options:**

| Flag | Description |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
|------|-------------|
| `-w, --worktree <ref>` | Target existing worktree by ID, name, or branch |
| `--var <KEY=value>` | Template variable (repeatable) |
| `-n, --name <name>` | Override worktree name (default: swarm name) |
| `-b, --base <branch>` | Base branch for new worktree(s) |
| `--no-open` | Suppress Terminal.app windows |
| `--json` | JSON output |

**JSON output (shared strategy):**
```json
{
"success": true,
"swarm": "code-review",
"strategy": "shared",
"worktree": { "id": "wt-abc123", "name": "code-review", "branch": "ppg/code-review", "path": "/path/.worktrees/wt-abc123", "tmuxWindow": "ppg-repo:1" },
"agents": [
{ "id": "ag-xyz12345", "tmuxTarget": "ppg-repo:1" },
{ "id": "ag-abc67890", "tmuxTarget": "ppg-repo:2" }
]
}
```

**Errors:** `NOT_INITIALIZED`, `INVALID_ARGS` (missing template or prompt file), `WORKTREE_NOT_FOUND`

## ppg list swarms

List available swarm templates.

```bash
ppg list swarms --json
```

**JSON output:**
```json
{ "swarms": [{ "name": "code-review", "description": "Multi-perspective code review", "strategy": "shared", "agents": 3 }] }
```

## ppg logs

View an agent's tmux pane output.
Expand Down Expand Up @@ -253,6 +312,7 @@ ppg wait --all --interval 10 --json # Poll every 10s (default: 5s)
```

**Options:**

| Flag | Description |
|------|-------------|
| `--all` | Wait for all agents across all worktrees |
Expand All @@ -273,6 +333,7 @@ ppg send <agent-id> "C-c" --keys # Send raw tmux keys (e.g., Ctrl-C)
```

**Options:**

| Flag | Description |
|------|-------------|
| `--keys` | Send raw tmux key names instead of literal text |
Expand All @@ -290,6 +351,7 @@ ppg restart <agent-id> --agent codex --json # Override agent type
```

**Options:**

| Flag | Description |
|------|-------------|
| `-p, --prompt <text>` | Override the original prompt |
Expand All @@ -310,6 +372,7 @@ ppg diff <wt-id> --name-only # Changed file names only
```

**Options:**

| Flag | Description |
|------|-------------|
| `--stat` | Show diffstat summary |
Expand All @@ -330,6 +393,7 @@ ppg clean --prune # Also run git worktree prune
```

**Options:**

| Flag | Description |
|------|-------------|
| `--all` | Also clean failed worktrees |
Expand Down
13 changes: 12 additions & 1 deletion skills/ppg-conductor/references/conductor.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,18 @@ ppg spawn --name "<name>" --prompt "<self-contained prompt>" --json --no-open

**Store a tracking table** with: worktree ID, agent IDs, name, and branch for each spawned task.

For swarm mode with different prompts, spawn the first agent (creates the worktree), then use `--worktree <wt-id>` for subsequent agents:
**Swarm templates** — If a matching swarm template exists in `.pg/swarms/`, prefer `ppg swarm` over manual multi-spawn:
```bash
# Use a predefined swarm template (much simpler than manual spawning)
ppg swarm code-review --var CONTEXT="Review the auth module" --json --no-open

# Run a swarm against an existing worktree (e.g., review a PR's worktree)
ppg swarm code-review --worktree wt-abc123 --var CONTEXT="Review PR #42" --json --no-open
```

Check available swarms: `ppg list swarms --json`

For **custom swarm mode** (when no template matches), spawn the first agent (creates the worktree), then use `--worktree <wt-id>` for subsequent agents:
```bash
# First agent — creates the worktree
ppg spawn --name "review" --prompt "Focus on code quality..." --json --no-open
Expand Down
18 changes: 15 additions & 3 deletions skills/ppg-conductor/references/modes.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,24 @@

**Spawn patterns:**

Option A — Single spawn with `--count` (same prompt, N agents):
Option A — **Swarm template** (preferred when a matching template exists):
```
# Check available swarm templates
ppg list swarms --json

# Run a predefined swarm
ppg swarm code-review --var CONTEXT="Review the auth module" --json --no-open

# Run against an existing worktree
ppg swarm code-review --worktree <wt-id> --var CONTEXT="Review PR #42" --json --no-open
```

Option B — Single spawn with `--count` (same prompt, N agents):
```
ppg spawn --name "security-review" --prompt "Review for security vulnerabilities..." --count 3 --json --no-open
```

Option B — Sequential spawns into same worktree (different prompts per agent):
Option C — Sequential spawns into same worktree (different prompts per agent):
```
# First spawn creates the worktree
ppg spawn --name "pr-review" --prompt "Review code quality and readability..." --json --no-open
Expand All @@ -27,7 +39,7 @@ ppg spawn --worktree <wt-id> --prompt "Review for performance issues..." --json
ppg spawn --worktree <wt-id> --prompt "Review test coverage gaps..." --json --no-open
```

**Option B is preferred** when each agent needs a distinct prompt (which is almost always the case).
**Option A is preferred** when a matching swarm template exists. **Option C is preferred** for custom swarm workflows where each agent needs a distinct prompt.

**Post-completion:**
1. Aggregate all results: `ppg aggregate --all --json`
Expand Down
56 changes: 56 additions & 0 deletions src/bundled/prompts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
export const bundledPrompts: Record<string, string> = {
'review-quality': `# Code Quality Review

## What to Review
{{CONTEXT}}

## Your Focus
You are a senior engineer reviewing code for quality, readability, and maintainability.

- Code clarity and naming conventions
- Function and module organization
- Error handling completeness
- DRY violations and unnecessary complexity
- API design and consistency
- Documentation gaps for non-obvious logic

## Output
Write a structured review to {{RESULT_FILE}} with specific file:line references and improvement suggestions.
`,
'review-security': `# Security Review

## What to Review
{{CONTEXT}}

## Your Focus
You are a security engineer reviewing code for vulnerabilities and risks.

- Input validation and sanitization
- Injection vulnerabilities (SQL, XSS, command)
- Authentication and authorization issues
- Sensitive data exposure
- Dependency vulnerabilities
- Secrets or credentials in code

## Output
Write a structured review to {{RESULT_FILE}} with severity ratings and remediation guidance.
`,
'review-regression': `# Regression & Risk Review

## What to Review
{{CONTEXT}}

## Your Focus
You are a QA engineer reviewing code for regression risks and test coverage gaps.

- Behavioral changes that could break existing functionality
- Edge cases and boundary conditions not covered
- Missing or inadequate test coverage
- Integration points that may be affected
- Data migration or compatibility concerns
- Performance regressions

## Output
Write a structured review to {{RESULT_FILE}} with risk ratings and recommended test additions.
`,
};
11 changes: 11 additions & 0 deletions src/bundled/swarms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const bundledSwarms: Record<string, string> = {
'code-review': `name: code-review
description: Multi-perspective code review
strategy: shared

agents:
- prompt: review-quality
- prompt: review-security
- prompt: review-regression
`,
};
19 changes: 17 additions & 2 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,25 @@ program
await mergeCommand(worktreeId, options);
});

program
.command('swarm')
.description('Run a swarm template — spawn multiple agents from a predefined workflow')
.argument('<template>', 'Swarm template name from .pg/swarms/')
.option('-w, --worktree <ref>', 'Target an existing worktree by ID, name, or branch')
.option('--var <key=value...>', 'Template variables', collectVars, [])
.option('-n, --name <name>', 'Override worktree name')
.option('-b, --base <branch>', 'Base branch for new worktree(s)')
.option('--no-open', 'Do not open Terminal windows')
.option('--json', 'Output as JSON')
.action(async (template, options) => {
const { swarmCommand } = await import('./commands/swarm.js');
await swarmCommand(template, options);
});

program
.command('list')
.description('List available templates')
.argument('<type>', 'What to list: templates')
.description('List available templates or swarms')
.argument('<type>', 'What to list: templates, swarms')
.option('--json', 'Output as JSON')
.action(async (type, options) => {
const { listCommand } = await import('./commands/list.js');
Expand Down
32 changes: 29 additions & 3 deletions src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { execa } from 'execa';
import { pgDir, resultsDir, logsDir, templatesDir, promptsDir, manifestPath } from '../lib/paths.js';
import { pgDir, resultsDir, logsDir, templatesDir, promptsDir, promptFile, swarmsDir, manifestPath } from '../lib/paths.js';
import { NotGitRepoError, TmuxNotFoundError } from '../lib/errors.js';
import { success, info } from '../lib/output.js';
import { writeDefaultConfig } from '../core/config.js';
import { createEmptyManifest, writeManifest } from '../core/manifest.js';
import { bundledPrompts } from '../bundled/prompts.js';
import { bundledSwarms } from '../bundled/swarms.js';

const CONDUCTOR_CONTEXT = `# PPG Conductor Context

Expand Down Expand Up @@ -74,6 +76,7 @@ export async function initCommand(options: { json?: boolean }): Promise<void> {
logsDir(projectRoot),
templatesDir(projectRoot),
promptsDir(projectRoot),
swarmsDir(projectRoot),
];

for (const dir of dirs) {
Expand Down Expand Up @@ -106,12 +109,34 @@ export async function initCommand(options: { json?: boolean }): Promise<void> {
info('Wrote sample template: default.md');
}

// 8. Write conductor context
// 8. Write bundled prompt files
for (const [name, content] of Object.entries(bundledPrompts)) {
const pPath = promptFile(projectRoot, name);
try {
await fs.access(pPath);
} catch {
await fs.writeFile(pPath, content, 'utf-8');
info(`Wrote prompt: ${name}.md`);
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// 9. Write bundled swarm templates
for (const [name, content] of Object.entries(bundledSwarms)) {
const sPath = path.join(swarmsDir(projectRoot), `${name}.yaml`);
try {
await fs.access(sPath);
} catch {
await fs.writeFile(sPath, content, 'utf-8');
info(`Wrote swarm template: ${name}.yaml`);
}
}

// 10. Write conductor context
const conductorPath = path.join(pgDir(projectRoot), 'conductor-context.md');
await fs.writeFile(conductorPath, CONDUCTOR_CONTEXT, 'utf-8');
info('Wrote conductor-context.md');

// 9. Register Claude Code plugin
// 11. Register Claude Code plugin
const pluginRegistered = await registerClaudePlugin();
if (pluginRegistered) {
info('Registered ppg Claude Code plugin');
Expand Down Expand Up @@ -186,6 +211,7 @@ async function updateGitignore(projectRoot: string): Promise<void> {
'.pg/logs/',
'.pg/manifest.json',
'.pg/prompts/',
'.pg/swarms/',
'.pg/conductor-context.md',
];

Expand Down
Loading