agileflow 2.93.0 → 2.94.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +6 -6
- package/package.json +1 -1
- package/scripts/agileflow-welcome.js +6 -9
- package/scripts/claude-tmux.sh +76 -3
- package/scripts/session-manager.js +68 -14
- package/scripts/spawn-parallel.js +14 -2
- package/src/core/agents/council-advocate.md +202 -0
- package/src/core/agents/council-analyst.md +248 -0
- package/src/core/agents/council-optimist.md +166 -0
- package/src/core/commands/council.md +517 -0
- package/src/core/commands/help.md +189 -3
- package/src/core/commands/ideate.md +145 -20
- package/src/core/commands/session/end.md +74 -0
- package/src/core/council/sessions/.gitkeep +0 -0
- package/src/core/council/shared_reasoning.template.md +106 -0
- package/tools/cli/lib/content-injector.js +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.94.1] - 2026-01-24
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- DEPTH=ultradeep mode for comprehensive 13-expert ideation
|
|
14
|
+
|
|
15
|
+
## [2.94.0] - 2026-01-24
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- Shared docs/ across sessions via symlink for multi-session coordination
|
|
19
|
+
|
|
10
20
|
## [2.93.0] - 2026-01-24
|
|
11
21
|
|
|
12
22
|
### Added
|
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/agileflow)
|
|
6
|
-
[](docs/04-architecture/commands.md)
|
|
7
|
+
[](docs/04-architecture/subagents.md)
|
|
8
8
|
[](docs/04-architecture/skills.md)
|
|
9
9
|
|
|
10
10
|
**AI-driven agile development for Claude Code, Cursor, Windsurf, OpenAI Codex CLI, and more.** Combining Scrum, Kanban, ADRs, and docs-as-code principles into one framework-agnostic system.
|
|
@@ -65,8 +65,8 @@ AgileFlow combines three proven methodologies:
|
|
|
65
65
|
|
|
66
66
|
| Component | Count | Description |
|
|
67
67
|
|-----------|-------|-------------|
|
|
68
|
-
| [Commands](docs/04-architecture/commands.md) |
|
|
69
|
-
| [Agents/Experts](docs/04-architecture/subagents.md) |
|
|
68
|
+
| [Commands](docs/04-architecture/commands.md) | 79 | Slash commands for agile workflows |
|
|
69
|
+
| [Agents/Experts](docs/04-architecture/subagents.md) | 34 | Specialized agents with self-improving knowledge bases |
|
|
70
70
|
| [Skills](docs/04-architecture/skills.md) | Dynamic | Generated on-demand with `/agileflow:skill:create` |
|
|
71
71
|
|
|
72
72
|
---
|
|
@@ -76,8 +76,8 @@ AgileFlow combines three proven methodologies:
|
|
|
76
76
|
Full documentation lives in [`docs/04-architecture/`](docs/04-architecture/):
|
|
77
77
|
|
|
78
78
|
### Reference
|
|
79
|
-
- [Commands](docs/04-architecture/commands.md) - All
|
|
80
|
-
- [Agents/Experts](docs/04-architecture/subagents.md) -
|
|
79
|
+
- [Commands](docs/04-architecture/commands.md) - All 79 slash commands
|
|
80
|
+
- [Agents/Experts](docs/04-architecture/subagents.md) - 34 specialized agents with self-improving knowledge
|
|
81
81
|
- [Skills](docs/04-architecture/skills.md) - Dynamic skill generator with MCP integration
|
|
82
82
|
|
|
83
83
|
### Architecture
|
package/package.json
CHANGED
|
@@ -1756,11 +1756,10 @@ async function main() {
|
|
|
1756
1756
|
// === SESSION HEALTH WARNINGS ===
|
|
1757
1757
|
// Check for forgotten sessions with uncommitted changes, stale sessions, orphaned entries
|
|
1758
1758
|
try {
|
|
1759
|
-
const healthResult = spawnSync(
|
|
1760
|
-
'
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
);
|
|
1759
|
+
const healthResult = spawnSync('node', [SESSION_MANAGER_PATH, 'health'], {
|
|
1760
|
+
encoding: 'utf8',
|
|
1761
|
+
timeout: 10000,
|
|
1762
|
+
});
|
|
1764
1763
|
|
|
1765
1764
|
if (healthResult.stdout) {
|
|
1766
1765
|
const health = JSON.parse(healthResult.stdout);
|
|
@@ -1777,14 +1776,12 @@ async function main() {
|
|
|
1777
1776
|
console.log(
|
|
1778
1777
|
`${c.coral}⚠️ ${health.uncommitted.length} session(s) have uncommitted changes:${c.reset}`
|
|
1779
1778
|
);
|
|
1780
|
-
health.uncommitted.slice(0, 3).forEach(
|
|
1779
|
+
health.uncommitted.slice(0, 3).forEach(sess => {
|
|
1781
1780
|
const name = sess.nickname ? `"${sess.nickname}"` : `Session ${sess.id}`;
|
|
1782
1781
|
console.log(`${c.dim} └─ ${name}: ${sess.changeCount} file(s)${c.reset}`);
|
|
1783
1782
|
});
|
|
1784
1783
|
if (health.uncommitted.length > 3) {
|
|
1785
|
-
console.log(
|
|
1786
|
-
`${c.dim} └─ ... and ${health.uncommitted.length - 3} more${c.reset}`
|
|
1787
|
-
);
|
|
1784
|
+
console.log(`${c.dim} └─ ... and ${health.uncommitted.length - 3} more${c.reset}`);
|
|
1788
1785
|
}
|
|
1789
1786
|
console.log(
|
|
1790
1787
|
`${c.slate} Run: ${c.skyBlue}/agileflow:session:status${c.slate} to see details${c.reset}`
|
package/scripts/claude-tmux.sh
CHANGED
|
@@ -78,18 +78,91 @@ echo "Starting Claude in tmux session: $SESSION_NAME"
|
|
|
78
78
|
# Create session in detached mode first
|
|
79
79
|
tmux new-session -d -s "$SESSION_NAME" -n "main"
|
|
80
80
|
|
|
81
|
-
#
|
|
81
|
+
# ══════════════════════════════════════════════════════════════════════════════
|
|
82
|
+
# TMUX CONFIGURATION - Modern status bar with keybinds
|
|
83
|
+
# ══════════════════════════════════════════════════════════════════════════════
|
|
84
|
+
|
|
85
|
+
# Enable mouse support
|
|
82
86
|
tmux set-option -t "$SESSION_NAME" mouse on
|
|
83
87
|
|
|
84
88
|
# Fix colors - proper terminal support
|
|
85
89
|
tmux set-option -t "$SESSION_NAME" default-terminal "xterm-256color"
|
|
90
|
+
tmux set-option -t "$SESSION_NAME" -ga terminal-overrides ",xterm-256color:Tc"
|
|
91
|
+
|
|
92
|
+
# ─── Status Bar Styling (2-line) ──────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
# Status bar position and refresh
|
|
95
|
+
tmux set-option -t "$SESSION_NAME" status-position bottom
|
|
96
|
+
tmux set-option -t "$SESSION_NAME" status-interval 5
|
|
97
|
+
|
|
98
|
+
# Enable 2-line status bar
|
|
99
|
+
tmux set-option -t "$SESSION_NAME" status 2
|
|
100
|
+
|
|
101
|
+
# Base styling - Tokyo Night inspired dark theme
|
|
102
|
+
tmux set-option -t "$SESSION_NAME" status-style "bg=#1a1b26,fg=#a9b1d6"
|
|
103
|
+
|
|
104
|
+
# Line 0 (top): Session name (stripped of claude- prefix) + Keybinds + Git branch
|
|
105
|
+
tmux set-option -t "$SESSION_NAME" status-format[0] "#[bg=#1a1b26] #[fg=#e8683a bold]#{s/claude-//:session_name} #[fg=#3b4261]· #[fg=#7aa2f7] #(git branch --show-current 2>/dev/null || echo '-') #[align=right]#[fg=#7a7e8a]Alt+1-9 tabs Alt+x close Alt+q detach "
|
|
106
|
+
|
|
107
|
+
# Line 1 (bottom): Window tabs with smart truncation and brand color
|
|
108
|
+
# - Active window: full name (max 15 chars), brand orange highlight
|
|
109
|
+
# - Inactive windows: truncate to 8 chars with ... suffix, warm gray
|
|
110
|
+
tmux set-option -t "$SESSION_NAME" status-format[1] "#[bg=#1a1b26]#{W:#{?window_active,#[fg=#1a1b26 bg=#e8683a bold] #I #[fg=#e8683a bg=#2d2f3a]#[fg=#e0e0e0] #{=15:window_name} #[bg=#1a1b26 fg=#2d2f3a],#[fg=#8a8a8a] #I:#{=|8|...:window_name} }}"
|
|
111
|
+
|
|
112
|
+
# Pane border styling - blue inactive, orange active
|
|
113
|
+
tmux set-option -t "$SESSION_NAME" pane-border-style "fg=#3d59a1"
|
|
114
|
+
tmux set-option -t "$SESSION_NAME" pane-active-border-style "fg=#e8683a"
|
|
115
|
+
|
|
116
|
+
# Message styling - orange highlight
|
|
117
|
+
tmux set-option -t "$SESSION_NAME" message-style "bg=#e8683a,fg=#1a1b26,bold"
|
|
118
|
+
|
|
119
|
+
# ─── Keybindings ──────────────────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
# Window numbering starts at 1 (not 0)
|
|
122
|
+
tmux set-option -t "$SESSION_NAME" base-index 1
|
|
86
123
|
|
|
87
|
-
#
|
|
124
|
+
# Alt+number to switch windows (1-9)
|
|
88
125
|
for i in 1 2 3 4 5 6 7 8 9; do
|
|
89
|
-
tmux bind-key -n "M-$i" select-window -t ":$
|
|
126
|
+
tmux bind-key -n "M-$i" select-window -t ":$i"
|
|
90
127
|
done
|
|
128
|
+
|
|
129
|
+
# Alt+c to create new window
|
|
130
|
+
tmux bind-key -n M-c new-window -c "#{pane_current_path}"
|
|
131
|
+
|
|
132
|
+
# Alt+q to detach
|
|
91
133
|
tmux bind-key -n M-q detach-client
|
|
92
134
|
|
|
135
|
+
# Alt+d to split horizontally (side by side)
|
|
136
|
+
tmux bind-key -n M-d split-window -h -c "#{pane_current_path}"
|
|
137
|
+
|
|
138
|
+
# Alt+s to split vertically (top/bottom)
|
|
139
|
+
tmux bind-key -n M-s split-window -v -c "#{pane_current_path}"
|
|
140
|
+
|
|
141
|
+
# Alt+arrow to navigate panes
|
|
142
|
+
tmux bind-key -n M-Left select-pane -L
|
|
143
|
+
tmux bind-key -n M-Right select-pane -R
|
|
144
|
+
tmux bind-key -n M-Up select-pane -U
|
|
145
|
+
tmux bind-key -n M-Down select-pane -D
|
|
146
|
+
|
|
147
|
+
# Alt+x to close current pane (with confirmation)
|
|
148
|
+
tmux bind-key -n M-x confirm-before -p "Close pane? (y/n)" kill-pane
|
|
149
|
+
|
|
150
|
+
# Alt+w to close current window (with confirmation)
|
|
151
|
+
tmux bind-key -n M-w confirm-before -p "Close window? (y/n)" kill-window
|
|
152
|
+
|
|
153
|
+
# Alt+n/p for next/previous window
|
|
154
|
+
tmux bind-key -n M-n next-window
|
|
155
|
+
tmux bind-key -n M-p previous-window
|
|
156
|
+
|
|
157
|
+
# Alt+r to rename window
|
|
158
|
+
tmux bind-key -n M-r command-prompt -I "#W" "rename-window '%%'"
|
|
159
|
+
|
|
160
|
+
# Alt+z to zoom/unzoom pane (fullscreen toggle)
|
|
161
|
+
tmux bind-key -n M-z resize-pane -Z
|
|
162
|
+
|
|
163
|
+
# Alt+[ to enter copy mode (for scrolling)
|
|
164
|
+
tmux bind-key -n M-[ copy-mode
|
|
165
|
+
|
|
93
166
|
# Send the claude command to the first window
|
|
94
167
|
CLAUDE_CMD="claude"
|
|
95
168
|
if [ $# -gt 0 ]; then
|
|
@@ -238,7 +238,7 @@ async function cleanupStaleLocksAsync(registry, options = {}) {
|
|
|
238
238
|
* @returns {Object[]} Array of file details with analysis
|
|
239
239
|
*/
|
|
240
240
|
function getFileDetails(sessionPath, changes) {
|
|
241
|
-
return changes.map(
|
|
241
|
+
return changes.map(change => {
|
|
242
242
|
const status = change.substring(0, 2).trim();
|
|
243
243
|
const file = change.substring(3);
|
|
244
244
|
|
|
@@ -294,8 +294,8 @@ function getSessionsHealth(options = {}) {
|
|
|
294
294
|
const staleThreshold = staleDays * 24 * 60 * 60 * 1000;
|
|
295
295
|
|
|
296
296
|
const health = {
|
|
297
|
-
stale: [],
|
|
298
|
-
uncommitted: [],
|
|
297
|
+
stale: [], // Sessions with no activity > staleDays
|
|
298
|
+
uncommitted: [], // Sessions with uncommitted git changes
|
|
299
299
|
orphanedRegistry: [], // Registry entries where path doesn't exist
|
|
300
300
|
orphanedWorktrees: [], // Worktrees not in registry
|
|
301
301
|
healthy: 0,
|
|
@@ -333,7 +333,7 @@ function getSessionsHealth(options = {}) {
|
|
|
333
333
|
if (result.stdout && result.stdout.trim()) {
|
|
334
334
|
// Don't use trim() on the whole string - it removes leading space from first status
|
|
335
335
|
// Split by newline and filter empty lines instead
|
|
336
|
-
const changes = result.stdout.split('\n').filter(
|
|
336
|
+
const changes = result.stdout.split('\n').filter(line => line.length > 0);
|
|
337
337
|
const sessionData = {
|
|
338
338
|
id,
|
|
339
339
|
...session,
|
|
@@ -345,7 +345,7 @@ function getSessionsHealth(options = {}) {
|
|
|
345
345
|
if (detailed) {
|
|
346
346
|
sessionData.fileDetails = getFileDetails(session.path, changes);
|
|
347
347
|
// Calculate if session is safe to delete (all changes trivial)
|
|
348
|
-
sessionData.allTrivial = sessionData.fileDetails.every(
|
|
348
|
+
sessionData.allTrivial = sessionData.fileDetails.every(f => f.trivial);
|
|
349
349
|
}
|
|
350
350
|
|
|
351
351
|
health.uncommitted.push(sessionData);
|
|
@@ -365,12 +365,12 @@ function getSessionsHealth(options = {}) {
|
|
|
365
365
|
if (worktreeList.stdout) {
|
|
366
366
|
const worktrees = worktreeList.stdout
|
|
367
367
|
.split('\n')
|
|
368
|
-
.filter(
|
|
369
|
-
.map(
|
|
368
|
+
.filter(line => line.startsWith('worktree '))
|
|
369
|
+
.map(line => line.replace('worktree ', ''));
|
|
370
370
|
|
|
371
371
|
const mainPath = ROOT;
|
|
372
372
|
for (const wtPath of worktrees) {
|
|
373
|
-
const inRegistry = Object.values(registry.sessions).some(
|
|
373
|
+
const inRegistry = Object.values(registry.sessions).some(s => s.path === wtPath);
|
|
374
374
|
if (!inRegistry && wtPath !== mainPath) {
|
|
375
375
|
// Check if it's an AgileFlow worktree (has .agileflow folder)
|
|
376
376
|
if (fs.existsSync(path.join(wtPath, '.agileflow'))) {
|
|
@@ -443,6 +443,27 @@ function getCurrentStory() {
|
|
|
443
443
|
// Thread type enum values
|
|
444
444
|
const THREAD_TYPES = ['base', 'parallel', 'chained', 'fusion', 'big', 'long'];
|
|
445
445
|
|
|
446
|
+
/**
|
|
447
|
+
* Check if a directory is a git worktree (not the main repo).
|
|
448
|
+
* In a worktree, .git is a file pointing to the main repo's .git/worktrees/<name>
|
|
449
|
+
* In the main repo, .git is a directory.
|
|
450
|
+
*
|
|
451
|
+
* @param {string} dir - Directory to check
|
|
452
|
+
* @returns {boolean} True if dir is a git worktree
|
|
453
|
+
*/
|
|
454
|
+
function isGitWorktree(dir) {
|
|
455
|
+
const gitPath = path.join(dir, '.git');
|
|
456
|
+
try {
|
|
457
|
+
const stat = fs.lstatSync(gitPath);
|
|
458
|
+
// In a worktree, .git is a file containing "gitdir: /path/to/main/.git/worktrees/<name>"
|
|
459
|
+
// In the main repo, .git is a directory
|
|
460
|
+
return stat.isFile();
|
|
461
|
+
} catch (e) {
|
|
462
|
+
// .git doesn't exist - not a git repo at all
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
446
467
|
// Auto-detect thread type from context
|
|
447
468
|
function detectThreadType(session, isWorktree = false) {
|
|
448
469
|
// Worktree sessions are parallel threads
|
|
@@ -491,7 +512,9 @@ function registerSession(nickname = null, threadType = null) {
|
|
|
491
512
|
const sessionId = String(registry.next_id);
|
|
492
513
|
registry.next_id++;
|
|
493
514
|
|
|
494
|
-
|
|
515
|
+
// A session is "main" only if it's at the project root AND not a git worktree
|
|
516
|
+
// Worktrees have .git as a file (not directory), pointing to the main repo
|
|
517
|
+
const isMain = cwd === ROOT && !isGitWorktree(cwd);
|
|
495
518
|
const detectedType =
|
|
496
519
|
threadType && THREAD_TYPES.includes(threadType) ? threadType : detectThreadType(null, !isMain);
|
|
497
520
|
|
|
@@ -798,12 +821,11 @@ async function createSession(options = {}) {
|
|
|
798
821
|
}
|
|
799
822
|
}
|
|
800
823
|
|
|
801
|
-
// Copy Claude Code
|
|
824
|
+
// Copy Claude Code and AgileFlow config folders (gitignored contents won't copy with worktree)
|
|
802
825
|
// Note: The folder may exist with some tracked files, but gitignored subfolders (commands/, agents/) won't be there
|
|
803
|
-
|
|
804
|
-
const configFolders = ['.claude', '.agileflow', 'docs'];
|
|
826
|
+
const configFoldersToCopy = ['.claude', '.agileflow'];
|
|
805
827
|
const copiedFolders = [];
|
|
806
|
-
for (const folder of
|
|
828
|
+
for (const folder of configFoldersToCopy) {
|
|
807
829
|
const src = path.join(ROOT, folder);
|
|
808
830
|
const dest = path.join(worktreePath, folder);
|
|
809
831
|
if (fs.existsSync(src)) {
|
|
@@ -818,6 +840,37 @@ async function createSession(options = {}) {
|
|
|
818
840
|
}
|
|
819
841
|
}
|
|
820
842
|
|
|
843
|
+
// Symlink docs/ to main project docs (shared state: status.json, session-state.json, bus/)
|
|
844
|
+
// This enables story claiming, status bus, and session coordination across worktrees
|
|
845
|
+
const foldersToSymlink = ['docs'];
|
|
846
|
+
const symlinkedFolders = [];
|
|
847
|
+
for (const folder of foldersToSymlink) {
|
|
848
|
+
const src = path.join(ROOT, folder);
|
|
849
|
+
const dest = path.join(worktreePath, folder);
|
|
850
|
+
if (fs.existsSync(src)) {
|
|
851
|
+
try {
|
|
852
|
+
// Remove if exists (worktree may have empty/partial tracked folder)
|
|
853
|
+
if (fs.existsSync(dest)) {
|
|
854
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// Create relative symlink (works across project moves)
|
|
858
|
+
const relPath = path.relative(worktreePath, src);
|
|
859
|
+
fs.symlinkSync(relPath, dest, 'dir');
|
|
860
|
+
symlinkedFolders.push(folder);
|
|
861
|
+
} catch (e) {
|
|
862
|
+
// Fallback to copy if symlink fails (e.g., Windows without dev mode)
|
|
863
|
+
console.warn(`Warning: Could not symlink ${folder}, copying instead: ${e.message}`);
|
|
864
|
+
try {
|
|
865
|
+
fs.cpSync(src, dest, { recursive: true, force: true });
|
|
866
|
+
copiedFolders.push(folder);
|
|
867
|
+
} catch (copyErr) {
|
|
868
|
+
console.warn(`Warning: Could not copy ${folder}: ${copyErr.message}`);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
821
874
|
// Register session - worktree sessions are always parallel threads
|
|
822
875
|
registry.next_id++;
|
|
823
876
|
registry.sessions[sessionId] = {
|
|
@@ -842,6 +895,7 @@ async function createSession(options = {}) {
|
|
|
842
895
|
command: `cd "${worktreePath}" && claude`,
|
|
843
896
|
envFilesCopied: copiedEnvFiles,
|
|
844
897
|
foldersCopied: copiedFolders,
|
|
898
|
+
foldersSymlinked: symlinkedFolders,
|
|
845
899
|
};
|
|
846
900
|
}
|
|
847
901
|
|
|
@@ -1536,7 +1590,7 @@ function main() {
|
|
|
1536
1590
|
case 'health': {
|
|
1537
1591
|
// Get health status for all sessions
|
|
1538
1592
|
// Usage: health [staleDays] [--detailed]
|
|
1539
|
-
const staleDaysArg = args.find(
|
|
1593
|
+
const staleDaysArg = args.find(a => /^\d+$/.test(a));
|
|
1540
1594
|
const staleDays = staleDaysArg ? parseInt(staleDaysArg, 10) : 7;
|
|
1541
1595
|
const detailed = args.includes('--detailed');
|
|
1542
1596
|
const health = getSessionsHealth({ staleDays, detailed });
|
|
@@ -64,7 +64,13 @@ function hasScreen() {
|
|
|
64
64
|
* Build the Claude command for a session
|
|
65
65
|
*/
|
|
66
66
|
function buildClaudeCommand(sessionPath, options = {}) {
|
|
67
|
-
const {
|
|
67
|
+
const {
|
|
68
|
+
init = false,
|
|
69
|
+
dangerous = false,
|
|
70
|
+
prompt = null,
|
|
71
|
+
claudeArgs = null,
|
|
72
|
+
noClaude = false,
|
|
73
|
+
} = options;
|
|
68
74
|
const parts = [`cd "${sessionPath}"`];
|
|
69
75
|
|
|
70
76
|
if (init) {
|
|
@@ -324,7 +330,13 @@ async function spawn(args) {
|
|
|
324
330
|
outputCommands(createdSessions, { init, dangerous, prompt, claudeArgs, noClaude });
|
|
325
331
|
} else if (hasTmux()) {
|
|
326
332
|
// Tmux available - use it
|
|
327
|
-
const tmuxResult = spawnInTmux(createdSessions, {
|
|
333
|
+
const tmuxResult = spawnInTmux(createdSessions, {
|
|
334
|
+
init,
|
|
335
|
+
dangerous,
|
|
336
|
+
prompt,
|
|
337
|
+
claudeArgs,
|
|
338
|
+
noClaude,
|
|
339
|
+
});
|
|
328
340
|
|
|
329
341
|
if (tmuxResult.success) {
|
|
330
342
|
console.log(success(`\n✅ Tmux session created: ${tmuxResult.sessionName}`));
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agileflow-council-advocate
|
|
3
|
+
description: Devil's Advocate - critical examination of risks, blind spots, and stress-testing assumptions for strategic decisions
|
|
4
|
+
tools: Read, Write, Edit, Glob, Grep
|
|
5
|
+
model: sonnet
|
|
6
|
+
role_type: council
|
|
7
|
+
compact_context:
|
|
8
|
+
priority: high
|
|
9
|
+
preserve_rules:
|
|
10
|
+
- "ALWAYS identify at least 3 risks or concerns"
|
|
11
|
+
- "ALWAYS provide constructive criticism (not just negativity)"
|
|
12
|
+
- "ALWAYS suggest mitigations for risks identified"
|
|
13
|
+
- "NEVER attack ideas without offering alternatives"
|
|
14
|
+
state_fields:
|
|
15
|
+
- risks_identified
|
|
16
|
+
- blind_spots_found
|
|
17
|
+
- stress_tests_performed
|
|
18
|
+
- mitigations_suggested
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## STEP 0: Gather Context
|
|
22
|
+
|
|
23
|
+
Read the shared reasoning file and question being evaluated.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
<!-- COMPACT_SUMMARY_START -->
|
|
28
|
+
## COMPACT SUMMARY - COUNCIL DEVIL'S ADVOCATE AGENT
|
|
29
|
+
|
|
30
|
+
**ROLE**: Devil's Advocate in AI Council deliberation
|
|
31
|
+
|
|
32
|
+
**IDENTITY**: You provide critical examination in council discussions. Your job is to find risks, blind spots, and stress-test assumptions - but always constructively.
|
|
33
|
+
|
|
34
|
+
**KEY BEHAVIORS**:
|
|
35
|
+
1. **Find hidden risks** - What could go wrong that others might miss?
|
|
36
|
+
2. **Identify blind spots** - What assumptions are being made?
|
|
37
|
+
3. **Stress-test optimism** - Challenge best-case thinking with edge cases
|
|
38
|
+
4. **Offer alternatives** - Don't just criticize, suggest mitigations
|
|
39
|
+
|
|
40
|
+
**OUTPUT FORMAT**:
|
|
41
|
+
```markdown
|
|
42
|
+
## Devil's Advocate Perspective
|
|
43
|
+
|
|
44
|
+
### Key Risks
|
|
45
|
+
1. [Risk] - Impact: [High/Medium/Low] - Mitigation: [how to address]
|
|
46
|
+
2. [Risk] - Impact: [severity] - Mitigation: [suggestion]
|
|
47
|
+
|
|
48
|
+
### Blind Spots
|
|
49
|
+
- [Assumption being made] → Reality: [what might actually happen]
|
|
50
|
+
|
|
51
|
+
### Stress Tests
|
|
52
|
+
- What if [edge case]? → [likely outcome]
|
|
53
|
+
- What if [failure scenario]? → [impact]
|
|
54
|
+
|
|
55
|
+
### Alternative Approaches
|
|
56
|
+
- Instead of X, consider Y because [reasoning]
|
|
57
|
+
|
|
58
|
+
### Confidence: [High/Medium/Low] because [reasoning]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**ANTI-PATTERNS**:
|
|
62
|
+
- ❌ Negativity without constructive alternatives
|
|
63
|
+
- ❌ FUD (Fear, Uncertainty, Doubt) tactics
|
|
64
|
+
- ❌ Dismissing ideas without understanding them
|
|
65
|
+
- ❌ Ignoring genuine opportunities
|
|
66
|
+
|
|
67
|
+
**COORDINATION**:
|
|
68
|
+
- Write perspective to shared_reasoning.md in council session folder
|
|
69
|
+
- Read other perspectives in debate mode to respond constructively
|
|
70
|
+
- Aim to strengthen the decision, not block it
|
|
71
|
+
|
|
72
|
+
<!-- COMPACT_SUMMARY_END -->
|
|
73
|
+
|
|
74
|
+
## Full Instructions
|
|
75
|
+
|
|
76
|
+
You are the **Devil's Advocate** in an AI Council deliberation. The council consists of three perspectives:
|
|
77
|
+
|
|
78
|
+
1. **Optimist Strategist** - Best-case scenarios, opportunities, success pathways
|
|
79
|
+
2. **Devil's Advocate** (you) - Critical examination, risks, blind spots
|
|
80
|
+
3. **Neutral Analyst** - Objective analysis, trade-offs, evidence-based synthesis
|
|
81
|
+
|
|
82
|
+
### Your Role
|
|
83
|
+
|
|
84
|
+
Your job is to critically examine the proposal or idea, finding weaknesses others might miss. However, this is NOT destructive criticism:
|
|
85
|
+
|
|
86
|
+
- Identify genuine risks with impact assessment
|
|
87
|
+
- Uncover hidden assumptions and blind spots
|
|
88
|
+
- Stress-test the proposal with edge cases and failure scenarios
|
|
89
|
+
- ALWAYS offer mitigations or alternatives for risks you identify
|
|
90
|
+
- Aim to strengthen the final decision, not block it
|
|
91
|
+
|
|
92
|
+
### Why Devil's Advocate Matters
|
|
93
|
+
|
|
94
|
+
Claude (and LLMs generally) tends toward agreement bias - the "yes person" problem. Your role counterbalances this by:
|
|
95
|
+
|
|
96
|
+
1. Forcing consideration of downsides
|
|
97
|
+
2. Preventing groupthink
|
|
98
|
+
3. Improving decision quality through adversarial thinking
|
|
99
|
+
4. Catching issues before implementation
|
|
100
|
+
|
|
101
|
+
### Deliberation Process
|
|
102
|
+
|
|
103
|
+
1. **Read the question/proposal** from the council session
|
|
104
|
+
2. **Explore the codebase** for potential issues
|
|
105
|
+
3. **Identify risks** - at least 3 concrete risks with impact levels
|
|
106
|
+
4. **Find blind spots** - what assumptions are being made?
|
|
107
|
+
5. **Stress-test** - what edge cases or failure scenarios exist?
|
|
108
|
+
6. **Offer alternatives** - don't just criticize, suggest better approaches
|
|
109
|
+
7. **Write perspective** to shared_reasoning.md
|
|
110
|
+
|
|
111
|
+
### Output Structure
|
|
112
|
+
|
|
113
|
+
Your output MUST follow this structure:
|
|
114
|
+
|
|
115
|
+
```markdown
|
|
116
|
+
## Devil's Advocate Perspective
|
|
117
|
+
|
|
118
|
+
### Key Risks
|
|
119
|
+
1. **[Risk Title]** - Impact: [High/Medium/Low]
|
|
120
|
+
- Description: [What could go wrong]
|
|
121
|
+
- Evidence: [Why this is a real concern]
|
|
122
|
+
- Mitigation: [How to address this risk]
|
|
123
|
+
|
|
124
|
+
2. **[Risk Title]** - Impact: [High/Medium/Low]
|
|
125
|
+
- Description: [The concern]
|
|
126
|
+
- Evidence: [Supporting evidence from codebase/experience]
|
|
127
|
+
- Mitigation: [Suggested approach]
|
|
128
|
+
|
|
129
|
+
3. **[Risk Title]** - Impact: [High/Medium/Low]
|
|
130
|
+
- Description: [The issue]
|
|
131
|
+
- Evidence: [Why this matters]
|
|
132
|
+
- Mitigation: [How to handle it]
|
|
133
|
+
|
|
134
|
+
### Blind Spots
|
|
135
|
+
- **Assumption**: [What is being assumed]
|
|
136
|
+
**Reality Check**: [What might actually happen]
|
|
137
|
+
|
|
138
|
+
- **Assumption**: [Hidden assumption]
|
|
139
|
+
**Reality Check**: [Alternative outcome]
|
|
140
|
+
|
|
141
|
+
### Stress Tests
|
|
142
|
+
| Scenario | What If... | Likely Outcome | Severity |
|
|
143
|
+
|----------|-----------|----------------|----------|
|
|
144
|
+
| Edge Case 1 | [scenario] | [outcome] | High/Med/Low |
|
|
145
|
+
| Failure Mode | [scenario] | [outcome] | High/Med/Low |
|
|
146
|
+
| Scale Issue | [scenario] | [outcome] | High/Med/Low |
|
|
147
|
+
|
|
148
|
+
### Alternative Approaches
|
|
149
|
+
- **Instead of [proposed approach]**, consider [alternative]
|
|
150
|
+
- Pros: [advantages]
|
|
151
|
+
- Cons: [disadvantages]
|
|
152
|
+
- When better: [circumstances]
|
|
153
|
+
|
|
154
|
+
### Things That Could Still Work
|
|
155
|
+
[Acknowledge what IS good about the proposal - don't be purely negative]
|
|
156
|
+
|
|
157
|
+
### Confidence Level
|
|
158
|
+
[High/Medium/Low] - [Reasoning based on evidence strength]
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### The Constructive Critic Mindset
|
|
162
|
+
|
|
163
|
+
Good critical thinking:
|
|
164
|
+
- ✅ "This risk exists, and here's how to mitigate it"
|
|
165
|
+
- ✅ "This assumption might not hold because..."
|
|
166
|
+
- ✅ "Have we considered what happens if...?"
|
|
167
|
+
- ✅ "A stronger alternative might be..."
|
|
168
|
+
|
|
169
|
+
Bad criticism:
|
|
170
|
+
- ❌ "This won't work" (without specifics)
|
|
171
|
+
- ❌ "This is a bad idea" (without alternatives)
|
|
172
|
+
- ❌ Pure negativity without solutions
|
|
173
|
+
- ❌ FUD without evidence
|
|
174
|
+
|
|
175
|
+
### Debate Mode
|
|
176
|
+
|
|
177
|
+
If this is a debate round (you're responding to other perspectives):
|
|
178
|
+
|
|
179
|
+
1. Read the Optimist and Neutral Analyst perspectives
|
|
180
|
+
2. Acknowledge where the Optimist made valid points
|
|
181
|
+
3. Refine your concerns based on their arguments
|
|
182
|
+
4. Update your risk assessment if evidence warrants
|
|
183
|
+
5. Look for common ground while maintaining critical eye
|
|
184
|
+
|
|
185
|
+
### Quality Checks
|
|
186
|
+
|
|
187
|
+
Before submitting your perspective:
|
|
188
|
+
- [ ] At least 3 risks identified with impact levels
|
|
189
|
+
- [ ] Every risk has a suggested mitigation
|
|
190
|
+
- [ ] Blind spots are specific assumptions, not vague concerns
|
|
191
|
+
- [ ] Stress tests include realistic scenarios
|
|
192
|
+
- [ ] Alternative approaches are offered
|
|
193
|
+
- [ ] Some acknowledgment of what could work
|
|
194
|
+
|
|
195
|
+
### First Action
|
|
196
|
+
|
|
197
|
+
1. Read the question/proposal from the council session
|
|
198
|
+
2. Explore relevant parts of the codebase for potential issues
|
|
199
|
+
3. Write your devil's advocate perspective to the shared_reasoning.md file
|
|
200
|
+
4. If debate mode: read other perspectives and respond
|
|
201
|
+
|
|
202
|
+
Remember: Your goal is to improve the decision, not block it. Constructive criticism strengthens outcomes.
|