agentf 0.3.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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/bin/agentf +8 -0
  3. data/lib/agentf/agent_policy.rb +54 -0
  4. data/lib/agentf/agents/architect.rb +67 -0
  5. data/lib/agentf/agents/base.rb +53 -0
  6. data/lib/agentf/agents/debugger.rb +75 -0
  7. data/lib/agentf/agents/designer.rb +69 -0
  8. data/lib/agentf/agents/documenter.rb +58 -0
  9. data/lib/agentf/agents/explorer.rb +65 -0
  10. data/lib/agentf/agents/reviewer.rb +64 -0
  11. data/lib/agentf/agents/security.rb +84 -0
  12. data/lib/agentf/agents/specialist.rb +68 -0
  13. data/lib/agentf/agents/tester.rb +79 -0
  14. data/lib/agentf/agents.rb +19 -0
  15. data/lib/agentf/cli/architecture.rb +83 -0
  16. data/lib/agentf/cli/arg_parser.rb +50 -0
  17. data/lib/agentf/cli/code.rb +165 -0
  18. data/lib/agentf/cli/install.rb +112 -0
  19. data/lib/agentf/cli/memory.rb +393 -0
  20. data/lib/agentf/cli/metrics.rb +103 -0
  21. data/lib/agentf/cli/router.rb +111 -0
  22. data/lib/agentf/cli/update.rb +204 -0
  23. data/lib/agentf/commands/architecture.rb +183 -0
  24. data/lib/agentf/commands/debugger.rb +238 -0
  25. data/lib/agentf/commands/designer.rb +179 -0
  26. data/lib/agentf/commands/explorer.rb +208 -0
  27. data/lib/agentf/commands/memory_reviewer.rb +186 -0
  28. data/lib/agentf/commands/metrics.rb +272 -0
  29. data/lib/agentf/commands/security_scanner.rb +98 -0
  30. data/lib/agentf/commands/tester.rb +232 -0
  31. data/lib/agentf/commands.rb +17 -0
  32. data/lib/agentf/context_builder.rb +35 -0
  33. data/lib/agentf/installer.rb +580 -0
  34. data/lib/agentf/mcp/server.rb +310 -0
  35. data/lib/agentf/memory.rb +530 -0
  36. data/lib/agentf/packs.rb +74 -0
  37. data/lib/agentf/service/providers.rb +158 -0
  38. data/lib/agentf/tools/component_spec.rb +28 -0
  39. data/lib/agentf/tools/error_analysis.rb +19 -0
  40. data/lib/agentf/tools/file_match.rb +21 -0
  41. data/lib/agentf/tools/test_template.rb +17 -0
  42. data/lib/agentf/tools.rb +12 -0
  43. data/lib/agentf/version.rb +5 -0
  44. data/lib/agentf/workflow_contract.rb +158 -0
  45. data/lib/agentf/workflow_engine.rb +424 -0
  46. data/lib/agentf.rb +87 -0
  47. metadata +164 -0
@@ -0,0 +1,424 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "agents"
4
+ require_relative "commands"
5
+ require_relative "context_builder"
6
+ require_relative "workflow_contract"
7
+ require_relative "agent_policy"
8
+
9
+ module Agentf
10
+ class WorkflowEngine
11
+ PROVIDERS = {
12
+ opencode: Agentf::Service::Providers::OpenCode,
13
+ copilot: Agentf::Service::Providers::Copilot
14
+ }.freeze
15
+
16
+ attr_reader :memory, :base_path, :provider
17
+
18
+ def initialize(memory: nil, base_path: nil, provider: :opencode)
19
+ @memory = memory || Agentf::Memory::RedisMemory.new
20
+ @base_path = base_path || Agentf.config.base_path
21
+ @name = "WORKFLOW_ENGINE"
22
+ @provider_ref = provider
23
+ @provider = build_provider(@provider_ref, pack: Agentf.config.default_pack)
24
+
25
+ @explorer_commands = Commands::Explorer.new(base_path: @base_path)
26
+ @tester_commands = Commands::Tester.new(base_path: @base_path)
27
+ @debugger_commands = Commands::Debugger.new(base_path: @base_path)
28
+ @designer_commands = Commands::Designer.new(base_path: @base_path)
29
+ @security_commands = Commands::SecurityScanner.new
30
+ @architecture_commands = Commands::Architecture.new(base_path: @base_path)
31
+ @metrics_commands = Agentf.config.metrics_enabled ? Commands::Metrics.new(memory: @memory) : nil
32
+ @context_builder = ContextBuilder.new(memory: @memory)
33
+ @agent_policy = Agentf::AgentPolicy.new
34
+ @workflow_contract = Agentf::WorkflowContract.new(
35
+ enabled: Agentf.config.workflow_contract_enabled,
36
+ mode: Agentf.config.workflow_contract_mode
37
+ )
38
+
39
+ @agents = {
40
+ "ARCHITECT" => Agents::Architect.new(@memory),
41
+ "SPECIALIST" => Agents::Specialist.new(@memory),
42
+ "REVIEWER" => Agents::Reviewer.new(@memory),
43
+ "DOCUMENTER" => Agents::Documenter.new(@memory),
44
+ "EXPLORER" => Agents::Explorer.new(@memory, commands: @explorer_commands),
45
+ "TESTER" => Agents::Tester.new(@memory, commands: @tester_commands),
46
+ "DEBUGGER" => Agents::Debugger.new(@memory, commands: @debugger_commands),
47
+ "DESIGNER" => Agents::Designer.new(@memory, commands: @designer_commands),
48
+ "SECURITY" => Agents::Security.new(@memory, commands: @security_commands)
49
+ }
50
+
51
+ @workflow_state = {}
52
+ end
53
+
54
+ def execute(task, context: nil)
55
+ log "=" * 60
56
+ log "EXECUTING #{provider.name} WORKFLOW"
57
+ log "=" * 60
58
+
59
+ resolved_context = context || {}
60
+ selected_pack = resolve_pack(task: task, context: resolved_context)
61
+ @provider = build_provider(@provider_ref, pack: selected_pack)
62
+
63
+ @workflow_state = {
64
+ "task" => task,
65
+ "provider" => @provider.name,
66
+ "pack" => selected_pack,
67
+ "workflow_contract" => {
68
+ "enabled" => @workflow_contract.enabled?,
69
+ "mode" => @workflow_contract.mode,
70
+ "events" => [],
71
+ "blocked" => false
72
+ },
73
+ "context" => resolved_context,
74
+ "results" => [],
75
+ "completed_agents" => []
76
+ }
77
+
78
+ return @workflow_state if run_contract_stage("spec").fetch("blocked")
79
+
80
+ plan = provider.build_plan(task: task, context: resolved_context, logger: method(:log))
81
+ return @workflow_state if run_contract_stage("plan", plan: plan).fetch("blocked")
82
+
83
+ @workflow_state.merge!(
84
+ "provider" => plan["provider"],
85
+ "workflow_type" => plan["workflow_type"],
86
+ "tdd" => initialize_tdd_state(plan["workflow_type"]),
87
+ "plan" => plan
88
+ )
89
+
90
+ attach_initial_brain_context
91
+ persist_feature_intent(task: task, workflow_type: plan["workflow_type"], context: @workflow_state["context"])
92
+
93
+ plan["agents_needed"].each do |agent_name|
94
+ run_pre_specialist_tdd_cycle if agent_name == "SPECIALIST"
95
+ agent_result = execute_agent(agent_name)
96
+ @workflow_state["results"] << { "agent" => agent_name, "result" => agent_result }
97
+ @workflow_state["completed_agents"] << agent_name
98
+ end
99
+
100
+ return @workflow_state if run_contract_stage("execute").fetch("blocked")
101
+
102
+ architecture_review = perform_architecture_review
103
+ @workflow_state["architecture_review"] = architecture_review
104
+
105
+ return @workflow_state if run_contract_stage("review").fetch("blocked")
106
+
107
+ run_contract_stage("finalize")
108
+ summary = summarize_workflow
109
+ @workflow_state["summary"] = summary
110
+ record_workflow_metrics
111
+
112
+ log ""
113
+ log "=" * 60
114
+ log "WORKFLOW COMPLETE"
115
+ log "=" * 60
116
+ log "Provider: #{plan['provider']}"
117
+ log "Workflow type: #{plan['workflow_type']}"
118
+ log "Agents executed: #{@workflow_state['completed_agents'].size}"
119
+ log "Overall status: #{summary['status']}"
120
+
121
+ @workflow_state
122
+ end
123
+
124
+ private
125
+
126
+ def build_provider(provider, pack:)
127
+ return provider if provider.respond_to?(:build_plan)
128
+
129
+ klass = PROVIDERS[provider.to_sym]
130
+ raise ArgumentError, "Unknown provider: #{provider}. Valid providers: #{PROVIDERS.keys.join(', ')}" unless klass
131
+
132
+ klass.new(pack: pack)
133
+ end
134
+
135
+ def resolve_pack(task:, context:)
136
+ requested = context["pack"].to_s.strip
137
+ return requested.downcase unless requested.empty?
138
+
139
+ default_pack = Agentf.config.default_pack.to_s.strip
140
+ return default_pack.downcase unless default_pack.empty? || default_pack.casecmp("generic").zero?
141
+
142
+ Agentf::Packs.infer(context.merge("task" => task))
143
+ end
144
+
145
+ def log(message)
146
+ puts "\n[#{@name}] #{message}"
147
+ end
148
+
149
+ def execute_agent(agent_name)
150
+ context = @workflow_state["context"]
151
+ enriched_context = context.merge(
152
+ "brain" => @context_builder.build(
153
+ agent: agent_name,
154
+ workflow_state: @workflow_state,
155
+ limit: 8
156
+ )
157
+ )
158
+
159
+ if agent_name == "TESTER"
160
+ enriched_context["tdd_phase"] = @workflow_state.dig("tdd", "phase")
161
+ enriched_context["tdd_failure_signature"] = @workflow_state.dig("tdd", "failure_signature")
162
+ end
163
+
164
+ if agent_name == "SPECIALIST"
165
+ enriched_context["tdd_phase"] = "green"
166
+ enriched_context["expected_test_fix"] = @workflow_state.dig("tdd", "failure_signature")
167
+ end
168
+
169
+ result = @provider.execute_agent(
170
+ agent_name: agent_name,
171
+ task: @workflow_state["task"],
172
+ context: enriched_context,
173
+ agents: @agents,
174
+ commands: command_registry,
175
+ logger: method(:log)
176
+ )
177
+
178
+ policy_violations = @agent_policy.validate(
179
+ agent_name: agent_name,
180
+ boundaries: @agents.fetch(agent_name).class.policy_boundaries,
181
+ context: enriched_context,
182
+ result: result
183
+ )
184
+ append_policy_violations(policy_violations)
185
+
186
+ persist_agent_learning(agent_name: agent_name, result: result)
187
+ transition_tdd_phase(agent_name: agent_name, result: result)
188
+ result
189
+ end
190
+
191
+ def command_registry
192
+ {
193
+ "explorer" => @explorer_commands,
194
+ "tester" => @tester_commands,
195
+ "debugger" => @debugger_commands,
196
+ "designer" => @designer_commands,
197
+ "security" => @security_commands,
198
+ "architecture" => @architecture_commands
199
+ }
200
+ end
201
+
202
+ def attach_initial_brain_context
203
+ @workflow_state["context"]["brain"] = @context_builder.build(
204
+ agent: @name,
205
+ workflow_state: @workflow_state,
206
+ limit: 8
207
+ )
208
+ rescue StandardError
209
+ @workflow_state["context"]["brain"] = {}
210
+ end
211
+
212
+ def persist_feature_intent(task:, workflow_type:, context:)
213
+ acceptance_criteria = Array(context["acceptance_criteria"])
214
+ non_goals = Array(context["non_goals"])
215
+ tags = [workflow_type, @provider.name.downcase]
216
+
217
+ @memory.store_feature_intent(
218
+ title: task,
219
+ description: "Workflow intent captured by workflow engine",
220
+ acceptance_criteria: acceptance_criteria,
221
+ non_goals: non_goals,
222
+ tags: tags,
223
+ agent: @name
224
+ )
225
+ rescue StandardError => e
226
+ log "Intent capture skipped: #{e.message}"
227
+ end
228
+
229
+ def persist_agent_learning(agent_name:, result:)
230
+ return unless result.is_a?(Hash)
231
+
232
+ if result["error"]
233
+ @memory.store_pitfall(
234
+ title: "#{agent_name} execution failure",
235
+ description: result["error"],
236
+ context: @workflow_state["task"],
237
+ tags: [@workflow_state["workflow_type"], "workflow_error"],
238
+ agent: agent_name,
239
+ code_snippet: ""
240
+ )
241
+ return
242
+ end
243
+
244
+ if agent_name == "TESTER" && result["tdd_phase"] == "red" && result["passed"] == false
245
+ @memory.store_pitfall(
246
+ title: "TDD red phase captured",
247
+ description: result["failure_signature"] || "Intentional failing test captured",
248
+ context: @workflow_state["task"],
249
+ tags: [@workflow_state["workflow_type"], "tdd_red"],
250
+ agent: agent_name,
251
+ code_snippet: ""
252
+ )
253
+ return
254
+ end
255
+
256
+ if agent_name == "TESTER" && result["tdd_phase"] == "green" && result["passed"] == true
257
+ @memory.store_success(
258
+ title: "TDD green phase passed",
259
+ description: "Resolved failing test signature: #{result['failure_signature']}",
260
+ context: @workflow_state["task"],
261
+ tags: [@workflow_state["workflow_type"], "tdd_green"],
262
+ agent: agent_name,
263
+ code_snippet: ""
264
+ )
265
+ return
266
+ end
267
+
268
+ @memory.store_lesson(
269
+ title: "#{agent_name} completed workflow step",
270
+ description: "Agent step completed for #{@workflow_state['workflow_type']} workflow",
271
+ context: @workflow_state["task"],
272
+ tags: [@workflow_state["workflow_type"], "workflow_step"],
273
+ agent: agent_name,
274
+ code_snippet: ""
275
+ )
276
+ rescue StandardError => e
277
+ log "Learning persistence skipped: #{e.message}"
278
+ end
279
+
280
+ def summarize_workflow
281
+ results = @workflow_state["results"]
282
+ errors = results.select { |r| r["result"]["error"] }
283
+ reviews = results.select { |r| r["agent"] == "REVIEWER" }
284
+ approved = reviews.any? { |r| r["result"]["approved"] }
285
+ contract_blocked = @workflow_state.dig("workflow_contract", "blocked") == true
286
+
287
+ {
288
+ "status" => contract_blocked ? "blocked" : (errors.any? ? "failed" : (approved ? "approved" : "completed")),
289
+ "total_agents" => results.size,
290
+ "errors" => errors.size,
291
+ "approved" => approved,
292
+ "tdd" => @workflow_state["tdd"],
293
+ "contract_blocked" => contract_blocked
294
+ }
295
+ end
296
+
297
+ def initialize_tdd_state(workflow_type)
298
+ enabled = %w[feature bugfix refactor].include?(workflow_type)
299
+ {
300
+ "enabled" => enabled,
301
+ "phase" => enabled ? "red" : "disabled",
302
+ "failure_signature" => nil,
303
+ "red_executed" => false,
304
+ "green_executed" => false
305
+ }
306
+ end
307
+
308
+ def run_pre_specialist_tdd_cycle
309
+ tdd = @workflow_state["tdd"]
310
+ return unless tdd["enabled"]
311
+ return if tdd["red_executed"]
312
+
313
+ red_context = @workflow_state["context"].merge(
314
+ "tdd_phase" => "red",
315
+ "brain" => @context_builder.build(agent: "TESTER", workflow_state: @workflow_state, limit: 8)
316
+ )
317
+
318
+ red_result = @provider.execute_agent(
319
+ agent_name: "TESTER",
320
+ task: @workflow_state["task"],
321
+ context: red_context,
322
+ agents: @agents,
323
+ commands: command_registry,
324
+ logger: method(:log)
325
+ )
326
+
327
+ tdd["red_executed"] = true
328
+ tdd["failure_signature"] = red_result["failure_signature"]
329
+ @workflow_state["results"] << { "agent" => "TESTER_TDD_RED", "result" => red_result }
330
+ persist_agent_learning(agent_name: "TESTER", result: red_result)
331
+ rescue StandardError => e
332
+ log "TDD red phase skipped: #{e.message}"
333
+ end
334
+
335
+ def transition_tdd_phase(agent_name:, result:)
336
+ tdd = @workflow_state["tdd"]
337
+ return unless tdd["enabled"]
338
+
339
+ if agent_name == "SPECIALIST"
340
+ tdd["phase"] = "green"
341
+ elsif agent_name == "TESTER" && tdd["phase"] == "green"
342
+ tdd["green_executed"] = true
343
+ end
344
+
345
+ return unless agent_name == "TESTER" && result["tdd_phase"] == "green"
346
+
347
+ tdd["failure_signature"] ||= result["failure_signature"]
348
+ end
349
+
350
+ def record_workflow_metrics
351
+ return unless @metrics_commands
352
+
353
+ result = @metrics_commands.record_workflow(@workflow_state)
354
+ return if result["status"] == "recorded"
355
+
356
+ log "Metrics capture skipped: #{result['error']}"
357
+ rescue StandardError => e
358
+ log "Metrics capture skipped: #{e.message}"
359
+ end
360
+
361
+ def perform_architecture_review
362
+ result = @architecture_commands.review_layer_violations
363
+ @memory.store_lesson(
364
+ title: "Architecture review completed",
365
+ description: "Layer violations: #{Array(result['violations']).length}",
366
+ context: @workflow_state["task"],
367
+ tags: [@workflow_state["workflow_type"], "architecture_review"],
368
+ agent: @name
369
+ )
370
+ result
371
+ rescue StandardError => e
372
+ { "error" => e.message, "violations" => [] }
373
+ end
374
+
375
+ def run_contract_stage(stage, plan: nil)
376
+ evaluation = @workflow_contract.check(stage: stage, workflow_state: @workflow_state, plan: plan)
377
+ @workflow_state["workflow_contract"]["events"] << evaluation
378
+ persist_contract_event(evaluation)
379
+
380
+ if evaluation["blocked"]
381
+ @workflow_state["workflow_contract"]["blocked"] = true
382
+ log "Workflow blocked by contract at #{stage}: #{evaluation['violations'].map { |v| v['code'] }.join(', ')}"
383
+ elsif evaluation["violations"].any?
384
+ log "Workflow contract warnings at #{stage}: #{evaluation['violations'].map { |v| v['code'] }.join(', ')}"
385
+ end
386
+
387
+ evaluation
388
+ end
389
+
390
+ def persist_contract_event(evaluation)
391
+ @memory.store_episode(
392
+ type: "lesson",
393
+ title: "Workflow contract #{evaluation['stage']} #{evaluation['ok'] ? 'passed' : 'violated'}",
394
+ description: "mode=#{evaluation['mode']} blocked=#{evaluation['blocked']}",
395
+ context: JSON.generate(evaluation),
396
+ tags: ["workflow_contract", evaluation["stage"], evaluation["ok"] ? "pass" : "violation"],
397
+ agent: @name,
398
+ metadata: { "workflow_contract_event" => true }
399
+ )
400
+ rescue StandardError => e
401
+ log "Contract event persistence skipped: #{e.message}"
402
+ end
403
+
404
+ def append_policy_violations(policy_violations)
405
+ return if policy_violations.empty?
406
+
407
+ @workflow_state["policy_violations"] ||= []
408
+ @workflow_state["policy_violations"].concat(policy_violations)
409
+ policy_violations.each do |violation|
410
+ @memory.store_episode(
411
+ type: "pitfall",
412
+ title: "Agent policy violation: #{violation['code']}",
413
+ description: violation["message"],
414
+ context: @workflow_state["task"],
415
+ tags: ["agent_policy", violation["agent"].to_s.downcase],
416
+ agent: @name,
417
+ metadata: { "policy_violation" => true, "severity" => violation["severity"] }
418
+ )
419
+ end
420
+ rescue StandardError => e
421
+ log "Policy violation persistence skipped: #{e.message}"
422
+ end
423
+ end
424
+ end
data/lib/agentf.rb ADDED
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dotenv/load"
4
+ require "json"
5
+ require "time"
6
+ require "securerandom"
7
+ require "pathname"
8
+ require_relative "agentf/version"
9
+
10
+ module Agentf
11
+ class Error < StandardError; end
12
+
13
+ # Global configuration
14
+ class Config
15
+ attr_reader :redis_url
16
+ attr_accessor :project_name, :base_path, :metrics_enabled, :workflow_contract_enabled,
17
+ :workflow_contract_mode, :default_pack, :gem_path
18
+
19
+ def initialize
20
+ @redis_url = normalize_redis_url(ENV.fetch("REDIS_URL", "redis://localhost:6379"))
21
+ @project_name = ENV.fetch("AGENTF_PROJECT_NAME", "default")
22
+ @base_path = Dir.pwd
23
+ @metrics_enabled = parse_boolean(ENV.fetch("AGENTF_METRICS_ENABLED", "true"), default: true)
24
+ @workflow_contract_enabled = parse_boolean(
25
+ ENV.fetch("AGENTF_WORKFLOW_CONTRACT_ENABLED", "true"),
26
+ default: true
27
+ )
28
+ @workflow_contract_mode = normalize_contract_mode(
29
+ ENV.fetch("AGENTF_WORKFLOW_CONTRACT_MODE", "advisory")
30
+ )
31
+ @default_pack = ENV.fetch("AGENTF_DEFAULT_PACK", "generic").to_s.strip.downcase
32
+ @gem_path = ENV.fetch("AGENTF_GEM_PATH", nil)
33
+ end
34
+
35
+ def redis_url=(value)
36
+ @redis_url = normalize_redis_url(value)
37
+ end
38
+
39
+ private
40
+
41
+ def normalize_redis_url(value)
42
+ url = value.to_s.strip
43
+ return "redis://localhost:6379" if url.empty?
44
+
45
+ return url if url.match?(/\A[a-z][a-z0-9+\-.]*:\/\//i)
46
+
47
+ "redis://#{url}"
48
+ end
49
+
50
+ def parse_boolean(value, default:)
51
+ normalized = value.to_s.strip.downcase
52
+ return true if %w[1 true yes on].include?(normalized)
53
+ return false if %w[0 false no off].include?(normalized)
54
+
55
+ default
56
+ end
57
+
58
+ def normalize_contract_mode(value)
59
+ mode = value.to_s.strip.downcase
60
+ return mode if %w[advisory enforcing off].include?(mode)
61
+
62
+ "advisory"
63
+ end
64
+ end
65
+
66
+ def self.config
67
+ @config ||= Config.new
68
+ end
69
+
70
+ def self.configure
71
+ yield(config) if block_given?
72
+ end
73
+ end
74
+
75
+ # Load submodules
76
+ require_relative "agentf/memory"
77
+ require_relative "agentf/tools"
78
+ require_relative "agentf/commands"
79
+ require_relative "agentf/service/providers"
80
+ require_relative "agentf/context_builder"
81
+ require_relative "agentf/packs"
82
+ require_relative "agentf/agent_policy"
83
+ require_relative "agentf/workflow_contract"
84
+ require_relative "agentf/workflow_engine"
85
+ require_relative "agentf/installer"
86
+ require_relative "agentf/agents"
87
+ require_relative "agentf/cli/router"
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: agentf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Neal Deters
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-03-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: redis
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dotenv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.8'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: fakeredis
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.9.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.9.0
83
+ description: |2
84
+ A multi-agent system with Redis-backed memory for code execution,
85
+ testing, debugging, and design implementation. Designed for
86
+ frontend, backend, and API development workflows.
87
+ email:
88
+ executables:
89
+ - agentf
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - bin/agentf
94
+ - lib/agentf.rb
95
+ - lib/agentf/agent_policy.rb
96
+ - lib/agentf/agents.rb
97
+ - lib/agentf/agents/architect.rb
98
+ - lib/agentf/agents/base.rb
99
+ - lib/agentf/agents/debugger.rb
100
+ - lib/agentf/agents/designer.rb
101
+ - lib/agentf/agents/documenter.rb
102
+ - lib/agentf/agents/explorer.rb
103
+ - lib/agentf/agents/reviewer.rb
104
+ - lib/agentf/agents/security.rb
105
+ - lib/agentf/agents/specialist.rb
106
+ - lib/agentf/agents/tester.rb
107
+ - lib/agentf/cli/architecture.rb
108
+ - lib/agentf/cli/arg_parser.rb
109
+ - lib/agentf/cli/code.rb
110
+ - lib/agentf/cli/install.rb
111
+ - lib/agentf/cli/memory.rb
112
+ - lib/agentf/cli/metrics.rb
113
+ - lib/agentf/cli/router.rb
114
+ - lib/agentf/cli/update.rb
115
+ - lib/agentf/commands.rb
116
+ - lib/agentf/commands/architecture.rb
117
+ - lib/agentf/commands/debugger.rb
118
+ - lib/agentf/commands/designer.rb
119
+ - lib/agentf/commands/explorer.rb
120
+ - lib/agentf/commands/memory_reviewer.rb
121
+ - lib/agentf/commands/metrics.rb
122
+ - lib/agentf/commands/security_scanner.rb
123
+ - lib/agentf/commands/tester.rb
124
+ - lib/agentf/context_builder.rb
125
+ - lib/agentf/installer.rb
126
+ - lib/agentf/mcp/server.rb
127
+ - lib/agentf/memory.rb
128
+ - lib/agentf/packs.rb
129
+ - lib/agentf/service/providers.rb
130
+ - lib/agentf/tools.rb
131
+ - lib/agentf/tools/component_spec.rb
132
+ - lib/agentf/tools/error_analysis.rb
133
+ - lib/agentf/tools/file_match.rb
134
+ - lib/agentf/tools/test_template.rb
135
+ - lib/agentf/version.rb
136
+ - lib/agentf/workflow_contract.rb
137
+ - lib/agentf/workflow_engine.rb
138
+ homepage: https://github.com/nealdeters/agentf
139
+ licenses:
140
+ - MIT
141
+ metadata:
142
+ homepage_uri: https://github.com/nealdeters/agentf
143
+ source_code_uri: https://github.com/nealdeters/agentf
144
+ rubygems_mfa_required: 'true'
145
+ post_install_message:
146
+ rdoc_options: []
147
+ require_paths:
148
+ - lib
149
+ required_ruby_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: 3.3.0
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ requirements: []
160
+ rubygems_version: 3.0.3.1
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: A self-learning swarm of agents with shared memory
164
+ test_files: []