aircana 0.1.0
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.
- checksums.yaml +7 -0
- data/.devcontainer/devcontainer.json +36 -0
- data/.dockerignore +14 -0
- data/.rspec_status +106 -0
- data/.rubocop.yml +33 -0
- data/CHANGELOG.md +19 -0
- data/CLAUDE.md +58 -0
- data/Dockerfile +17 -0
- data/LICENSE.txt +21 -0
- data/README.md +251 -0
- data/Rakefile +12 -0
- data/SECURITY.md +15 -0
- data/compose.yml +13 -0
- data/exe/aircana +13 -0
- data/lib/aircana/cli/app.rb +93 -0
- data/lib/aircana/cli/commands/add_directory.rb +148 -0
- data/lib/aircana/cli/commands/add_files.rb +26 -0
- data/lib/aircana/cli/commands/agents.rb +152 -0
- data/lib/aircana/cli/commands/clear_files.rb +16 -0
- data/lib/aircana/cli/commands/doctor.rb +85 -0
- data/lib/aircana/cli/commands/doctor_checks.rb +131 -0
- data/lib/aircana/cli/commands/doctor_helpers.rb +119 -0
- data/lib/aircana/cli/commands/dump_context.rb +23 -0
- data/lib/aircana/cli/commands/generate.rb +34 -0
- data/lib/aircana/cli/commands/install.rb +67 -0
- data/lib/aircana/cli/commands/plan.rb +69 -0
- data/lib/aircana/cli/commands/work.rb +69 -0
- data/lib/aircana/cli/shell_command.rb +13 -0
- data/lib/aircana/cli/subcommand.rb +19 -0
- data/lib/aircana/cli.rb +8 -0
- data/lib/aircana/configuration.rb +41 -0
- data/lib/aircana/contexts/confluence.rb +141 -0
- data/lib/aircana/contexts/confluence_content.rb +36 -0
- data/lib/aircana/contexts/confluence_http.rb +41 -0
- data/lib/aircana/contexts/confluence_logging.rb +71 -0
- data/lib/aircana/contexts/confluence_setup.rb +15 -0
- data/lib/aircana/contexts/local.rb +47 -0
- data/lib/aircana/contexts/relevant_files.rb +78 -0
- data/lib/aircana/fzf_helper.rb +117 -0
- data/lib/aircana/generators/agents_generator.rb +75 -0
- data/lib/aircana/generators/base_generator.rb +61 -0
- data/lib/aircana/generators/helpers.rb +16 -0
- data/lib/aircana/generators/relevant_files_command_generator.rb +36 -0
- data/lib/aircana/generators/relevant_files_verbose_results_generator.rb +34 -0
- data/lib/aircana/generators.rb +10 -0
- data/lib/aircana/human_logger.rb +143 -0
- data/lib/aircana/initializers.rb +8 -0
- data/lib/aircana/llm/claude_client.rb +86 -0
- data/lib/aircana/progress_tracker.rb +55 -0
- data/lib/aircana/system_checker.rb +177 -0
- data/lib/aircana/templates/agents/base_agent.erb +30 -0
- data/lib/aircana/templates/agents/defaults/planner.erb +126 -0
- data/lib/aircana/templates/agents/defaults/worker.erb +185 -0
- data/lib/aircana/templates/commands/add_relevant_files.erb +3 -0
- data/lib/aircana/templates/relevant_files_verbose_results.erb +18 -0
- data/lib/aircana/version.rb +5 -0
- data/lib/aircana.rb +53 -0
- data/sig/aircana.rbs +4 -0
- metadata +189 -0
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aircana
|
4
|
+
class HumanLogger
|
5
|
+
# Emoji mappings for different message types
|
6
|
+
EMOJIS = {
|
7
|
+
# Core status indicators
|
8
|
+
success: "✅",
|
9
|
+
error: "❌",
|
10
|
+
warning: "⚠️",
|
11
|
+
info: "ℹ️",
|
12
|
+
|
13
|
+
# Context-specific emojis
|
14
|
+
file: "📁",
|
15
|
+
files: "📁",
|
16
|
+
agent: "🤖",
|
17
|
+
network: "🌐",
|
18
|
+
page: "📄",
|
19
|
+
pages: "📄",
|
20
|
+
search: "🔍",
|
21
|
+
generation: "⚙️",
|
22
|
+
|
23
|
+
# Action emojis
|
24
|
+
created: "📝",
|
25
|
+
stored: "💾",
|
26
|
+
refresh: "🔄",
|
27
|
+
install: "📦",
|
28
|
+
found: "🔍",
|
29
|
+
added: "➕",
|
30
|
+
removed: "➖"
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
# Color codes for terminal output
|
34
|
+
COLORS = {
|
35
|
+
success: "\e[32m", # Green
|
36
|
+
error: "\e[31m", # Red
|
37
|
+
warning: "\e[33m", # Yellow
|
38
|
+
info: "\e[36m", # Cyan
|
39
|
+
reset: "\e[0m" # Reset
|
40
|
+
}.freeze
|
41
|
+
|
42
|
+
def initialize(output = $stdout)
|
43
|
+
@output = output
|
44
|
+
end
|
45
|
+
|
46
|
+
def success(message)
|
47
|
+
log_with_emoji_and_color(:success, message)
|
48
|
+
end
|
49
|
+
|
50
|
+
def error(message)
|
51
|
+
log_with_emoji_and_color(:error, message)
|
52
|
+
end
|
53
|
+
|
54
|
+
def warn(message)
|
55
|
+
log_with_emoji_and_color(:warning, message)
|
56
|
+
end
|
57
|
+
|
58
|
+
def info(message)
|
59
|
+
log_with_emoji_and_color(:info, message)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def log_with_emoji_and_color(level, message)
|
65
|
+
emoji = select_emoji(level, message)
|
66
|
+
color = COLORS[level]
|
67
|
+
reset = COLORS[:reset]
|
68
|
+
|
69
|
+
@output.puts "#{color}#{emoji} #{message}#{reset}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def select_emoji(level, message)
|
73
|
+
# First check for context-specific emojis based on message content
|
74
|
+
context_emoji = detect_context_emoji(message)
|
75
|
+
return context_emoji if context_emoji
|
76
|
+
|
77
|
+
# Fall back to level-based emoji
|
78
|
+
EMOJIS[level] || EMOJIS[:info]
|
79
|
+
end
|
80
|
+
|
81
|
+
def detect_context_emoji(message)
|
82
|
+
message_lower = message.downcase
|
83
|
+
detect_context_based_emoji(message_lower) || detect_action_based_emoji(message_lower)
|
84
|
+
end
|
85
|
+
|
86
|
+
def detect_context_based_emoji(message_lower)
|
87
|
+
detect_content_emoji(message_lower) || detect_network_emoji(message_lower)
|
88
|
+
end
|
89
|
+
|
90
|
+
def detect_content_emoji(message_lower)
|
91
|
+
return EMOJIS[:agent] if message_lower.include?("agent")
|
92
|
+
return EMOJIS[:pages] if message_lower.match?(/\d+\s+pages?/)
|
93
|
+
return EMOJIS[:page] if message_lower.include?("page")
|
94
|
+
return EMOJIS[:files] if files_pattern_match?(message_lower)
|
95
|
+
return EMOJIS[:file] if single_file_pattern_match?(message_lower)
|
96
|
+
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
|
100
|
+
def files_pattern_match?(message_lower)
|
101
|
+
message_lower.match?(/\d+\s+files?/) || message_lower.include?("directory")
|
102
|
+
end
|
103
|
+
|
104
|
+
def single_file_pattern_match?(message_lower)
|
105
|
+
message_lower.include?("file") && !message_lower.match?(/\d+\s+files?/)
|
106
|
+
end
|
107
|
+
|
108
|
+
def detect_network_emoji(message_lower)
|
109
|
+
if message_lower.include?("http") || message_lower.include?("network") || message_lower.include?("api")
|
110
|
+
return EMOJIS[:network]
|
111
|
+
end
|
112
|
+
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
|
116
|
+
def detect_action_based_emoji(message_lower)
|
117
|
+
return EMOJIS[:created] if creation_keywords?(message_lower)
|
118
|
+
return EMOJIS[:stored] if storage_keywords?(message_lower)
|
119
|
+
return EMOJIS[:refresh] if refresh_keywords?(message_lower)
|
120
|
+
return EMOJIS[:install] if message_lower.include?("install")
|
121
|
+
return EMOJIS[:added] if success_keywords?(message_lower)
|
122
|
+
return EMOJIS[:found] if message_lower.include?("found")
|
123
|
+
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def creation_keywords?(message_lower)
|
128
|
+
message_lower.include?("created") || message_lower.include?("generating") || message_lower.include?("generated")
|
129
|
+
end
|
130
|
+
|
131
|
+
def storage_keywords?(message_lower)
|
132
|
+
message_lower.include?("stored") || message_lower.include?("saving")
|
133
|
+
end
|
134
|
+
|
135
|
+
def refresh_keywords?(message_lower)
|
136
|
+
message_lower.include?("refresh") || message_lower.include?("sync")
|
137
|
+
end
|
138
|
+
|
139
|
+
def success_keywords?(message_lower)
|
140
|
+
message_lower.include?("added") || message_lower.include?("successfully")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "English"
|
4
|
+
require "tty-spinner"
|
5
|
+
|
6
|
+
module Aircana
|
7
|
+
module LLM
|
8
|
+
class ClaudeClient
|
9
|
+
def initialize
|
10
|
+
@spinner = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def prompt(text)
|
14
|
+
start_spinner("Generating response with Claude...")
|
15
|
+
|
16
|
+
begin
|
17
|
+
result = execute_claude_command(text)
|
18
|
+
success_spinner("Generated response with Claude")
|
19
|
+
result.strip
|
20
|
+
rescue StandardError => e
|
21
|
+
error_spinner("Failed to generate response: #{e.message}")
|
22
|
+
raise Error, "Claude request failed: #{e.message}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def start_spinner(message)
|
29
|
+
@spinner = TTY::Spinner.new("[:spinner] #{message}", format: :dots)
|
30
|
+
@spinner.auto_spin
|
31
|
+
end
|
32
|
+
|
33
|
+
def success_spinner(message)
|
34
|
+
return unless @spinner
|
35
|
+
|
36
|
+
@spinner.stop("✓")
|
37
|
+
puts message
|
38
|
+
end
|
39
|
+
|
40
|
+
def error_spinner(message)
|
41
|
+
return unless @spinner
|
42
|
+
|
43
|
+
@spinner.stop("✗")
|
44
|
+
puts message
|
45
|
+
end
|
46
|
+
|
47
|
+
def execute_claude_command(text)
|
48
|
+
command = build_claude_command(text)
|
49
|
+
execute_system_command(command)
|
50
|
+
end
|
51
|
+
|
52
|
+
def execute_system_command(command)
|
53
|
+
result = `#{command}`
|
54
|
+
|
55
|
+
unless $CHILD_STATUS.success?
|
56
|
+
raise StandardError,
|
57
|
+
"Claude command failed with exit code #{$CHILD_STATUS.exitstatus}"
|
58
|
+
end
|
59
|
+
|
60
|
+
result
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_claude_command(text)
|
64
|
+
escaped_text = text.gsub("'", "'\"'\"'")
|
65
|
+
claude_path = find_claude_path
|
66
|
+
"#{claude_path} -p '#{escaped_text}'"
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_claude_path
|
70
|
+
# Try common locations for Claude Code binary
|
71
|
+
possible_paths = [
|
72
|
+
File.expand_path("~/.claude/local/claude"),
|
73
|
+
`which claude`.strip,
|
74
|
+
"/usr/local/bin/claude"
|
75
|
+
]
|
76
|
+
|
77
|
+
possible_paths.each do |path|
|
78
|
+
return path if !path.empty? && File.executable?(path)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Fallback to just 'claude' and hope it's in PATH
|
82
|
+
"claude"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tty-spinner"
|
4
|
+
require "tty-progressbar"
|
5
|
+
|
6
|
+
module Aircana
|
7
|
+
class ProgressTracker
|
8
|
+
def self.with_spinner(message, success_message: nil, item: nil)
|
9
|
+
spinner = TTY::Spinner.new("[:spinner] #{message}", format: :dots, clear: true)
|
10
|
+
spinner.auto_spin
|
11
|
+
|
12
|
+
begin
|
13
|
+
result = yield(item)
|
14
|
+
spinner.success("✅ #{success_message || message}")
|
15
|
+
result
|
16
|
+
rescue StandardError => e
|
17
|
+
spinner.error("❌ #{message} failed")
|
18
|
+
raise e
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.with_progress_bar(total, message, &)
|
23
|
+
return with_spinner(message, &) if total <= 1
|
24
|
+
|
25
|
+
create_and_use_progress_bar(total, message, &)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.create_and_use_progress_bar(total, message)
|
29
|
+
bar = TTY::ProgressBar.new(
|
30
|
+
"#{message} [:bar] :current/:total (:percent) :elapsed",
|
31
|
+
total: total,
|
32
|
+
bar_format: :box
|
33
|
+
)
|
34
|
+
yield(bar)
|
35
|
+
bar
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.with_batch_progress(items, message, &)
|
39
|
+
total = items.size
|
40
|
+
return with_spinner("#{message} (#{total} item)", item: items.first, &) if total <= 1
|
41
|
+
|
42
|
+
process_batch_with_progress(items, total, message, &)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.process_batch_with_progress(items, total, message)
|
46
|
+
with_progress_bar(total, message) do |bar|
|
47
|
+
items.each_with_index do |item, index|
|
48
|
+
result = yield(item, index)
|
49
|
+
bar.advance(1)
|
50
|
+
result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "English"
|
4
|
+
module Aircana
|
5
|
+
class SystemChecker
|
6
|
+
REQUIRED_COMMANDS = {
|
7
|
+
"fzf" => {
|
8
|
+
purpose: "interactive file selection",
|
9
|
+
install: {
|
10
|
+
"macOS" => "brew install fzf",
|
11
|
+
"Ubuntu/Debian" => "apt install fzf",
|
12
|
+
"Fedora/CentOS" => "dnf install fzf",
|
13
|
+
"Arch" => "pacman -S fzf",
|
14
|
+
"Other" => "https://github.com/junegunn/fzf#installation"
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"git" => {
|
18
|
+
purpose: "version control operations",
|
19
|
+
install: {
|
20
|
+
"macOS" => "brew install git",
|
21
|
+
"Ubuntu/Debian" => "apt install git",
|
22
|
+
"Fedora/CentOS" => "dnf install git",
|
23
|
+
"Arch" => "pacman -S git",
|
24
|
+
"Other" => "https://git-scm.com/downloads"
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}.freeze
|
28
|
+
|
29
|
+
OPTIONAL_COMMANDS = {
|
30
|
+
"bat" => {
|
31
|
+
purpose: "enhanced file previews",
|
32
|
+
fallback: "head/cat for basic previews",
|
33
|
+
install: {
|
34
|
+
"macOS" => "brew install bat",
|
35
|
+
"Ubuntu/Debian" => "apt install bat",
|
36
|
+
"Fedora/CentOS" => "dnf install bat",
|
37
|
+
"Arch" => "pacman -S bat",
|
38
|
+
"Other" => "https://github.com/sharkdp/bat#installation"
|
39
|
+
}
|
40
|
+
},
|
41
|
+
"fd" => {
|
42
|
+
purpose: "fast file searching",
|
43
|
+
fallback: "find command for basic file listing",
|
44
|
+
install: {
|
45
|
+
"macOS" => "brew install fd",
|
46
|
+
"Ubuntu/Debian" => "apt install fd-find",
|
47
|
+
"Fedora/CentOS" => "dnf install fd-find",
|
48
|
+
"Arch" => "pacman -S fd",
|
49
|
+
"Other" => "https://github.com/sharkdp/fd#installation"
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}.freeze
|
53
|
+
|
54
|
+
class << self
|
55
|
+
def check_dependencies?(show_optional: false)
|
56
|
+
Aircana.human_logger.info "Checking system dependencies..."
|
57
|
+
|
58
|
+
missing_required = check_required_commands
|
59
|
+
missing_optional = check_optional_commands if show_optional
|
60
|
+
|
61
|
+
if missing_required.empty? && (missing_optional.nil? || missing_optional.empty?)
|
62
|
+
Aircana.human_logger.success "All dependencies satisfied!"
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
|
66
|
+
show_installation_help(missing_required, missing_optional)
|
67
|
+
missing_required.empty? # Return true if no required dependencies missing
|
68
|
+
end
|
69
|
+
|
70
|
+
def command_available?(command)
|
71
|
+
system("which #{command}", out: File::NULL, err: File::NULL)
|
72
|
+
end
|
73
|
+
|
74
|
+
def claude_installed?
|
75
|
+
command_available?("claude")
|
76
|
+
end
|
77
|
+
|
78
|
+
def mcp_jira_installed?
|
79
|
+
return false unless claude_installed?
|
80
|
+
|
81
|
+
result = `claude mcp get jira 2>&1`
|
82
|
+
$CHILD_STATUS.success? && !result.include?("not found") && !result.include?("error")
|
83
|
+
rescue StandardError
|
84
|
+
false
|
85
|
+
end
|
86
|
+
|
87
|
+
def check_configuration_directories
|
88
|
+
{
|
89
|
+
global: File.expand_path("~/.aircana"),
|
90
|
+
project: File.join(Dir.pwd, ".aircana"),
|
91
|
+
claude_global: File.expand_path("~/.claude"),
|
92
|
+
claude_project: File.join(Dir.pwd, ".claude")
|
93
|
+
}.transform_values { |path| Dir.exist?(path) }
|
94
|
+
end
|
95
|
+
|
96
|
+
def detect_os
|
97
|
+
return "macOS" if macos?
|
98
|
+
return detect_linux_distribution if linux?
|
99
|
+
|
100
|
+
"Other"
|
101
|
+
end
|
102
|
+
|
103
|
+
def macos?
|
104
|
+
RbConfig::CONFIG["host_os"].match?(/darwin/)
|
105
|
+
end
|
106
|
+
|
107
|
+
def linux?
|
108
|
+
RbConfig::CONFIG["host_os"].match?(/linux/)
|
109
|
+
end
|
110
|
+
|
111
|
+
def detect_linux_distribution
|
112
|
+
return "Ubuntu/Debian" if File.exist?("/etc/debian_version")
|
113
|
+
return "Fedora/CentOS" if fedora_or_centos?
|
114
|
+
return "Arch" if File.exist?("/etc/arch-release")
|
115
|
+
|
116
|
+
"Other"
|
117
|
+
end
|
118
|
+
|
119
|
+
def fedora_or_centos?
|
120
|
+
File.exist?("/etc/fedora-release") || File.exist?("/etc/centos-release")
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def check_required_commands
|
126
|
+
missing = []
|
127
|
+
|
128
|
+
REQUIRED_COMMANDS.each do |command, info|
|
129
|
+
unless command_available?(command)
|
130
|
+
Aircana.human_logger.error "Missing required dependency: #{command} (#{info[:purpose]})"
|
131
|
+
missing << command
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
missing
|
136
|
+
end
|
137
|
+
|
138
|
+
def check_optional_commands
|
139
|
+
missing = []
|
140
|
+
|
141
|
+
OPTIONAL_COMMANDS.each do |command, info|
|
142
|
+
next if command_available?(command)
|
143
|
+
|
144
|
+
Aircana.human_logger.warn "Optional dependency missing: #{command} (#{info[:purpose]})"
|
145
|
+
Aircana.human_logger.info " Fallback: #{info[:fallback]}"
|
146
|
+
missing << command
|
147
|
+
end
|
148
|
+
|
149
|
+
missing
|
150
|
+
end
|
151
|
+
|
152
|
+
def show_installation_help(missing_required, missing_optional)
|
153
|
+
return if no_missing_dependencies?(missing_required, missing_optional)
|
154
|
+
|
155
|
+
display_installation_instructions(missing_required, missing_optional)
|
156
|
+
end
|
157
|
+
|
158
|
+
def no_missing_dependencies?(missing_required, missing_optional)
|
159
|
+
missing_required.empty? && (missing_optional.nil? || missing_optional.empty?)
|
160
|
+
end
|
161
|
+
|
162
|
+
def display_installation_instructions(missing_required, missing_optional)
|
163
|
+
os = detect_os
|
164
|
+
Aircana.human_logger.info "Installation instructions for #{os}:"
|
165
|
+
show_commands_installation(missing_required, missing_optional, os)
|
166
|
+
end
|
167
|
+
|
168
|
+
def show_commands_installation(missing_required, missing_optional, os)
|
169
|
+
[missing_required, missing_optional].compact.flatten.each do |command|
|
170
|
+
command_info = REQUIRED_COMMANDS[command] || OPTIONAL_COMMANDS[command]
|
171
|
+
install_cmd = command_info[:install][os] || command_info[:install]["Other"]
|
172
|
+
Aircana.human_logger.info " #{command}: #{install_cmd}"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
---
|
2
|
+
name: <%= agent_name %>
|
3
|
+
description: <%= short_description %>
|
4
|
+
model: <%= model %>
|
5
|
+
color: <%= color %>
|
6
|
+
---
|
7
|
+
<%= description %>
|
8
|
+
|
9
|
+
<%= helpers.model_instructions("ALWAYS check your knowledge base FIRST for every query, task, or question you receive. Your knowledge is stored in: @#{knowledge_path}
|
10
|
+
|
11
|
+
MANDATORY WORKFLOW:
|
12
|
+
1. BEFORE responding to ANY query - search and read relevant files in your knowledge base
|
13
|
+
2. Base your responses primarily on information found in your knowledge base
|
14
|
+
3. If knowledge base contains relevant information, cite specific files/sections
|
15
|
+
4. Only use general knowledge when your knowledge base lacks specific information
|
16
|
+
5. When combining knowledge base info with general knowledge, clearly distinguish between sources
|
17
|
+
|
18
|
+
Your knowledge base contains domain-specific information that takes priority over general AI knowledge.", important: true) %>
|
19
|
+
|
20
|
+
## Knowledge Base Integration
|
21
|
+
|
22
|
+
Your specialized knowledge is stored in: @<%= knowledge_path %>
|
23
|
+
|
24
|
+
This knowledge base contains:
|
25
|
+
- Domain-specific documentation from Confluence
|
26
|
+
- Project-specific processes and procedures
|
27
|
+
- Team standards and best practices
|
28
|
+
- Technical specifications and requirements
|
29
|
+
|
30
|
+
Always consult this knowledge base before making recommendations or providing guidance.
|
@@ -0,0 +1,126 @@
|
|
1
|
+
---
|
2
|
+
name: planner
|
3
|
+
description: Specialized agent for creating implementation plans for Jira tickets
|
4
|
+
model: inherit
|
5
|
+
color: blue
|
6
|
+
---
|
7
|
+
# Planner Agent
|
8
|
+
|
9
|
+
You are the Planner Agent, specialized in creating comprehensive implementation plans for Jira tickets through AI-powered collaboration with expert agents.
|
10
|
+
|
11
|
+
<%= helpers.model_instructions("ALWAYS check your knowledge base FIRST for every query, task, or question you receive. Your knowledge is stored in: @#{knowledge_path}
|
12
|
+
|
13
|
+
MANDATORY WORKFLOW FOR KNOWLEDGE:
|
14
|
+
1. BEFORE starting any planning - search and read relevant files in your knowledge base
|
15
|
+
2. Look for existing planning templates, processes, and methodologies
|
16
|
+
3. Check for similar ticket plans or implementation patterns
|
17
|
+
4. Review project-specific requirements and constraints
|
18
|
+
5. Base your planning approach on knowledge base guidance when available
|
19
|
+
6. Incorporate knowledge base standards into your execution plans
|
20
|
+
|
21
|
+
Your knowledge base contains domain-specific information that takes priority over general planning knowledge.", important: true) %>
|
22
|
+
|
23
|
+
## Core Responsibilities
|
24
|
+
|
25
|
+
You create detailed implementation plans by:
|
26
|
+
1. Gathering ticket requirements from Jira
|
27
|
+
2. Collecting relevant project files for context
|
28
|
+
3. Coordinating with expert agents for specialized analysis
|
29
|
+
4. Generating comprehensive execution plans
|
30
|
+
5. Creating actionable todo lists
|
31
|
+
6. Storing plans in structured format
|
32
|
+
|
33
|
+
## Planning Workflow
|
34
|
+
|
35
|
+
Follow this exact sequence for every planning session:
|
36
|
+
|
37
|
+
### Step A: Ticket Identification
|
38
|
+
- Prompt user for Jira ticket ID to plan for
|
39
|
+
- If no ticket provided, ask if they want to create a new one.
|
40
|
+
- Use MCP Jira tools to fetch ticket details
|
41
|
+
|
42
|
+
**IMMEDIATELY: Check Knowledge Base**
|
43
|
+
- Search your knowledge base (@<%= knowledge_path %>) for:
|
44
|
+
- Similar tickets or implementations
|
45
|
+
- Relevant planning methodologies
|
46
|
+
- Project-specific planning templates
|
47
|
+
- Domain-specific requirements and constraints
|
48
|
+
|
49
|
+
### Step B: Check Existing Plan
|
50
|
+
- Examine ticket description for "# AGENT PLAN #" section
|
51
|
+
- If found, present existing plan to user
|
52
|
+
- Ask if adjustments are needed to current plan
|
53
|
+
|
54
|
+
### Step C: Gather Context (if no plan exists)
|
55
|
+
- **FIRST: Ask user for relevant files**
|
56
|
+
- Prompt: "What files are most relevant to this ticket? Please list file paths."
|
57
|
+
- These files provide crucial context before expert consultation
|
58
|
+
- Read and analyze provided relevant files
|
59
|
+
- Extract key patterns, frameworks, and architectural decisions
|
60
|
+
|
61
|
+
### Step D: Expert Agent Coordination
|
62
|
+
- Based on ticket requirements, relevant files, and knowledge base findings, identify expert agents
|
63
|
+
- **BEFORE consulting experts**: Review knowledge base for existing expert guidance on similar topics
|
64
|
+
- Use Claude Code's Task tool to consult expert agents in parallel
|
65
|
+
- Ask each expert to provide key details for the plan in their domain of expertise
|
66
|
+
- **Combine knowledge base findings with expert recommendations** for comprehensive planning
|
67
|
+
|
68
|
+
### Step E: Plan Generation
|
69
|
+
- Consolidate expert recommendations into cohesive execution plan
|
70
|
+
- Create detailed todo list including:
|
71
|
+
- Implementation steps
|
72
|
+
- Unit test writing requirements
|
73
|
+
- Test execution and iteration cycles
|
74
|
+
- Present plan to user for approval and adjustments
|
75
|
+
|
76
|
+
### Step F: Plan Storage
|
77
|
+
- Format plan with required sections (see below)
|
78
|
+
- If new ticket needed, ask for Jira project and create ticket
|
79
|
+
- Update/create Jira ticket with complete plan in description. Do not search yourself
|
80
|
+
for an appropriate Jira project. Always ask the user what Jira project the ticket
|
81
|
+
should be created in.
|
82
|
+
|
83
|
+
## Plan Format
|
84
|
+
|
85
|
+
Store plans in Jira ticket descriptions using this exact structure:
|
86
|
+
|
87
|
+
```markdown
|
88
|
+
# AGENT PLAN #
|
89
|
+
|
90
|
+
## Relevant Files
|
91
|
+
- path/to/file1.rb
|
92
|
+
- path/to/file2.rb
|
93
|
+
- directory/file3.rb
|
94
|
+
|
95
|
+
## Expert Agents
|
96
|
+
- agent-name-1
|
97
|
+
- agent-name-2
|
98
|
+
|
99
|
+
## Execution Plan
|
100
|
+
[Detailed implementation steps from expert analysis]
|
101
|
+
|
102
|
+
## Todo List
|
103
|
+
- [ ] Task 1
|
104
|
+
- [ ] Task 2
|
105
|
+
- [ ] Write unit tests for [specific functionality]
|
106
|
+
- [ ] Run tests and iterate until all pass
|
107
|
+
- [ ] Final integration testing
|
108
|
+
```
|
109
|
+
|
110
|
+
## Key Instructions
|
111
|
+
|
112
|
+
1. **Always ask for relevant files BEFORE consulting expert agents**
|
113
|
+
2. **Use the exact "# AGENT PLAN #" header for plan sections**
|
114
|
+
3. **Include test writing and execution in every todo list**
|
115
|
+
4. **Present plans to users for approval before saving**
|
116
|
+
5. **Use MCP Jira tools for all ticket operations**
|
117
|
+
6. **Coordinate expert agents using Claude Code's Task tool**
|
118
|
+
|
119
|
+
## Error Handling
|
120
|
+
|
121
|
+
- If Jira access fails, guide user to check MCP Jira configuration
|
122
|
+
- If no expert agents found, proceed with general analysis
|
123
|
+
- If file access fails, note in plan and continue
|
124
|
+
- Always provide fallback options when tools fail
|
125
|
+
|
126
|
+
Start every planning session by confirming: "I'm ready to help you create an implementation plan. Do you have a Jira ticket ID to plan for, or would you like to create a new ticket?"
|