devhive 0.1.18__tar.gz → 0.1.20__tar.gz

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 (51) hide show
  1. {devhive-0.1.18 → devhive-0.1.20}/PKG-INFO +1 -1
  2. devhive-0.1.20/devhive/agents/ceo.py +95 -0
  3. {devhive-0.1.18 → devhive-0.1.20}/devhive/cli.py +75 -55
  4. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/prompt_builder.py +145 -31
  5. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/task_orchestrator.py +12 -4
  6. {devhive-0.1.18 → devhive-0.1.20}/devhive/server.py +11 -11
  7. {devhive-0.1.18 → devhive-0.1.20}/devhive/utils/validation.py +23 -0
  8. {devhive-0.1.18 → devhive-0.1.20}/devhive.egg-info/PKG-INFO +1 -1
  9. {devhive-0.1.18 → devhive-0.1.20}/pyproject.toml +1 -1
  10. {devhive-0.1.18 → devhive-0.1.20}/setup.py +1 -1
  11. devhive-0.1.18/devhive/agents/ceo.py +0 -190
  12. {devhive-0.1.18 → devhive-0.1.20}/LICENSE +0 -0
  13. {devhive-0.1.18 → devhive-0.1.20}/README.md +0 -0
  14. {devhive-0.1.18 → devhive-0.1.20}/devhive/__init__.py +0 -0
  15. {devhive-0.1.18 → devhive-0.1.20}/devhive/agents/__init__.py +0 -0
  16. {devhive-0.1.18 → devhive-0.1.20}/devhive/agents/architect.py +0 -0
  17. {devhive-0.1.18 → devhive-0.1.20}/devhive/agents/archivist.py +0 -0
  18. {devhive-0.1.18 → devhive-0.1.20}/devhive/agents/auditor.py +0 -0
  19. {devhive-0.1.18 → devhive-0.1.20}/devhive/agents/base_agent.py +0 -0
  20. {devhive-0.1.18 → devhive-0.1.20}/devhive/agents/developer.py +0 -0
  21. {devhive-0.1.18 → devhive-0.1.20}/devhive/agents/explorer.py +0 -0
  22. {devhive-0.1.18 → devhive-0.1.20}/devhive/agents/proposal.py +0 -0
  23. {devhive-0.1.18 → devhive-0.1.20}/devhive/agents/qa.py +0 -0
  24. {devhive-0.1.18 → devhive-0.1.20}/devhive/agents/task_agent.py +0 -0
  25. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/__init__.py +0 -0
  26. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/artifact_manager.py +0 -0
  27. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/context_optimizer.py +0 -0
  28. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/context_router.py +0 -0
  29. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/dependency_manager.py +0 -0
  30. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/llm.py +0 -0
  31. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/memory_store.py +0 -0
  32. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/project_state_manager.py +0 -0
  33. {devhive-0.1.18 → devhive-0.1.20}/devhive/core/task_queue.py +0 -0
  34. {devhive-0.1.18 → devhive-0.1.20}/devhive/skills/auditor/owasp_security_audit.md +0 -0
  35. {devhive-0.1.18 → devhive-0.1.20}/devhive/skills/auditor/performance_bottlenecks.md +0 -0
  36. {devhive-0.1.18 → devhive-0.1.20}/devhive/skills/developer/backend-architect.md +0 -0
  37. {devhive-0.1.18 → devhive-0.1.20}/devhive/skills/developer/backend-security-coder.md +0 -0
  38. {devhive-0.1.18 → devhive-0.1.20}/devhive/skills/explorer/edge_case_hunter.md +0 -0
  39. {devhive-0.1.18 → devhive-0.1.20}/devhive/skills/explorer/nfr_checklist.md +0 -0
  40. {devhive-0.1.18 → devhive-0.1.20}/devhive/skills/global/inclusive_language.md +0 -0
  41. {devhive-0.1.18 → devhive-0.1.20}/devhive/skills/global/json_strictness.md +0 -0
  42. {devhive-0.1.18 → devhive-0.1.20}/devhive/skills/global/security_mandates.md +0 -0
  43. {devhive-0.1.18 → devhive-0.1.20}/devhive/utils/__init__.py +0 -0
  44. {devhive-0.1.18 → devhive-0.1.20}/devhive/utils/filesystem.py +0 -0
  45. {devhive-0.1.18 → devhive-0.1.20}/devhive.egg-info/SOURCES.txt +0 -0
  46. {devhive-0.1.18 → devhive-0.1.20}/devhive.egg-info/dependency_links.txt +0 -0
  47. {devhive-0.1.18 → devhive-0.1.20}/devhive.egg-info/entry_points.txt +0 -0
  48. {devhive-0.1.18 → devhive-0.1.20}/devhive.egg-info/requires.txt +0 -0
  49. {devhive-0.1.18 → devhive-0.1.20}/devhive.egg-info/top_level.txt +0 -0
  50. {devhive-0.1.18 → devhive-0.1.20}/setup.cfg +0 -0
  51. {devhive-0.1.18 → devhive-0.1.20}/tests/test_parallel_development.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devhive
3
- Version: 0.1.18
3
+ Version: 0.1.20
4
4
  Summary: DevHive MCP Server
5
5
  Requires-Python: >=3.10
6
6
  License-File: LICENSE
@@ -0,0 +1,95 @@
1
+ import json
2
+ from typing import Dict, Any
3
+ from mcp.server.fastmcp import Context
4
+ from devhive.agents.base_agent import BaseAgent
5
+ from devhive.core.project_state_manager import ProjectStateManager
6
+
7
+ class CEOAgent(BaseAgent):
8
+ role = "CEO"
9
+
10
+ def get_next_agent_deterministic(self) -> Dict[str, Any]:
11
+ """
12
+ Determine next agent to run based on dynamic workflow_plan from the state.
13
+
14
+ Returns:
15
+ Dict with 'agent' (role name) and 'reason' (explanation)
16
+ """
17
+ state = self.state_manager.get_state()
18
+ artifacts = state.get("artifacts", {})
19
+
20
+ # If the CEO hasn't planned the workflow yet, run the CEO.
21
+ if artifacts.get("workflow_plan") is None:
22
+ return {
23
+ "agent": "CEO",
24
+ "reason": "Need initial workflow planning based on requirements"
25
+ }
26
+
27
+ # Get the workflow plan created by the CEO
28
+ try:
29
+ plan_id = artifacts.get("workflow_plan")
30
+ plan_data = self.artifact_manager.load_artifact(plan_id)
31
+ workflow_plan = plan_data.get("workflow_plan", [])
32
+ # Fallback if workflow_plan is malformed
33
+ if not workflow_plan:
34
+ workflow_plan = ["Explorer", "Developer", "QA", "Archivist"]
35
+ except Exception:
36
+ # Fallback if something is broken
37
+ workflow_plan = ["Explorer", "Developer", "QA", "Archivist"]
38
+
39
+ # Map agent names to artifact keys
40
+ mapping = {
41
+ "Explorer": "exploration",
42
+ "Proposal": "proposal",
43
+ "Architect": "architecture",
44
+ "TaskPlanner": "tasks",
45
+ "Developer": "implementation",
46
+ "QA": "tests",
47
+ "Auditor": "verification",
48
+ "Archivist": "archive"
49
+ }
50
+
51
+ # Iterate over the plan and find the first incomplete agent
52
+ for agent in workflow_plan:
53
+ artifact_key = mapping.get(agent)
54
+
55
+ if artifact_key == "implementation":
56
+ # Special iterative Developer logic
57
+ if artifacts.get("implementation") is None:
58
+ dev_progress = state.get("developer_progress", {})
59
+ pending_tasks = dev_progress.get("pending_tasks", [])
60
+ completed_tasks = dev_progress.get("completed_tasks", [])
61
+
62
+ if not dev_progress or pending_tasks:
63
+ task_count = len(pending_tasks) if pending_tasks else "tasks"
64
+ return {
65
+ "agent": "Developer",
66
+ "reason": f"Need to execute {task_count} pending tasks sequentially"
67
+ }
68
+ elif not pending_tasks and completed_tasks:
69
+ # Implementation is complete based on tasks
70
+ continue
71
+ else:
72
+ return {
73
+ "agent": "Developer",
74
+ "reason": "Ready for implementation"
75
+ }
76
+ continue
77
+
78
+ if artifacts.get(artifact_key) is None:
79
+ return {
80
+ "agent": agent,
81
+ "reason": f"Next agent in workflow plan: {agent}"
82
+ }
83
+
84
+ # All done
85
+ return {
86
+ "agent": "Complete",
87
+ "reason": "All pipeline stages in the workflow plan have finished, project is complete"
88
+ }
89
+
90
+ async def execute(self, ctx: Context, **kwargs) -> Dict[str, Any]:
91
+ """
92
+ CEO Agent execution logic is handled by TaskOrchestrator in the new task-based workflow.
93
+ This legacy method is not used.
94
+ """
95
+ pass
@@ -5,55 +5,55 @@ import json
5
5
  import os
6
6
  from pathlib import Path
7
7
 
8
- # Try to find default agent file location relative to package
9
- # This assumes the package structure allows finding the file in the root
8
+ # Try to find default skill file location relative to package
10
9
  PACKAGE_ROOT = Path(__file__).parent.parent
11
- DEFAULT_AGENT_PATH = PACKAGE_ROOT / "DEVHIVE_AGENT.md"
10
+ DEFAULT_SKILL_PATH = PACKAGE_ROOT / "skills" / "devhive_workflow.md"
12
11
 
13
- def get_default_agent_content():
14
- """Reads the DEVHIVE_AGENT.md content from the package source."""
15
- if DEFAULT_AGENT_PATH.exists():
16
- return DEFAULT_AGENT_PATH.read_text()
12
+ def get_default_skill_content():
13
+ """Reads the devhive_workflow.md content from the package source."""
14
+ if DEFAULT_SKILL_PATH.exists():
15
+ return DEFAULT_SKILL_PATH.read_text()
17
16
 
18
- # Fallback content if file is totally missing (should not happen in proper install)
19
- return """# DevHive Agent System Prompt
17
+ # Fallback content if file is missing
18
+ return """# DevHive Workflow Orchestrator
20
19
 
21
- You are the DevHive Agent, an autonomous software development orchestrator.
22
- Your goal is to manage the full software development lifecycle using the DevHive MCP server tools.
20
+ This skill defines the autonomous execution loop for the DevHive AI software development pipeline.
23
21
 
24
- ## Core Workflow
22
+ ## Core Rules
23
+ 1. **Autonomous Execution**: Run the entire DevHive pipeline autonomously. Do not stop to ask the user for permission between each agent step unless an unrecoverable error occurs or the Explorer agent explicitly asks a `clarification_question`.
24
+ 2. **Subagent Delegation**: You MUST use the `Task` tool with `subagent_type="general"` to execute the prompts generated by the MCP server. Do not execute the prompts yourself in the main context.
25
+ 3. **Strict JSON**: The DevHive MCP server expects strict JSON. Instruct the subagent to output ONLY valid JSON without markdown formatting.
25
26
 
26
- 1. **Start/Resume Project**:
27
- - Use `devhive_start_pipeline(project_name, requirements)` to initialize a project or get the next task.
28
- - If the project already exists, this will resume from the last state.
27
+ ## The Execution Loop
29
28
 
30
- 2. **Execute Task**:
31
- - The output of `devhive_start_pipeline` (or `devhive_submit_result`) provides a `next_task` object containing:
32
- - `agent`: The sub-agent role (e.g., Explorer, Developer).
33
- - `system_prompt`: The specific instructions for this sub-agent.
34
- - `user_prompt`: The context and requirements for the task.
35
- - You must execute this task.
36
- - **OpenCode**: Use the `Task` tool with the provided prompts.
37
- - **Copilot**: Act as the sub-agent directly using the prompts.
29
+ When a user asks you to build a feature or start a project using DevHive, follow this exact procedure:
38
30
 
39
- 3. **Submit Result**:
40
- - Once the sub-agent task is complete, use `devhive_submit_result(project_name, agent_name, llm_response)` to save the work.
41
- - This tool will return the *next* task in the pipeline.
42
- - Repeat step 2 with the new task.
31
+ ### 1. Initialization
32
+ Use the `devhive_start_pipeline` tool.
33
+ - `project_name`: A short snake_case identifier derived from the request.
34
+ - `requirements`: The user's full request.
43
35
 
44
- ## Available Tools
36
+ The tool will return a JSON envelope containing `status`, `agent`, `system_prompt`, `user_prompt`, `expected_keys`, and `task_description`.
45
37
 
46
- - `devhive_start_pipeline`: Initialize project and get first task.
47
- - `devhive_submit_result`: Save task result and get next task.
48
- - `devhive_search_memory`: Retrieve context from previous steps.
49
- - `devhive_get_memory_stats`: Check project memory usage.
50
- - `devhive_get_recent_memories`: See recent project activity.
38
+ ### 2. Main Loop
39
+ While `status` is `"pending"`:
51
40
 
52
- ## Important Instructions
41
+ **A. Launch Subagent**
42
+ Use the `Task` tool with `subagent_type="general"`.
43
+ - `description`: The `task_description` from the envelope.
44
+ - `prompt`: Combine the `system_prompt` and `user_prompt` from the envelope. Append this CRITICAL instruction: *"You must ONLY output valid JSON containing these exact keys: {expected_keys}. Do not include any other text, markdown formatting, or explanations."*
53
45
 
54
- - Always follow the strict sequential pipeline: Explorer -> Proposal -> Architect -> TaskPlanner -> Developer -> QA -> Auditor -> Archivist.
55
- - Do not skip steps unless the pipeline explicitly skips them.
56
- - Use the prompts provided by the tools exactly as given.
46
+ **B. Submit Result**
47
+ Once the subagent returns its JSON output, use the `devhive_submit_result` tool.
48
+ - `project_name`: The current project name.
49
+ - `agent_name`: The `agent` from the current envelope.
50
+ - `llm_response`: The raw JSON output from the subagent.
51
+
52
+ **C. Process Server Response**
53
+ The tool will return a new envelope:
54
+ - If `status` == `"success"`: Print a brief update to the user. If `next_task` is present, update your envelope and repeat the loop.
55
+ - If `status` == `"error"`: The envelope has an error message. Launch the subagent again, provide the error and the previous output, and ask it to fix the JSON structure. Retry up to 3 times.
56
+ - If `status` == `"complete"`: The pipeline is finished. Give the user a final summary and exit the loop.
57
57
  """
58
58
 
59
59
  def configure():
@@ -68,24 +68,24 @@ def configure():
68
68
  print("Invalid choice. Please type 'opencode', 'copilot', or 'both'.")
69
69
 
70
70
  # 2. Locate source file
71
- cwd_agent = Path("DEVHIVE_AGENT.md").resolve()
72
- pkg_agent = DEFAULT_AGENT_PATH.resolve()
71
+ cwd_skill = Path("skills/devhive_workflow.md").resolve()
72
+ pkg_skill = DEFAULT_SKILL_PATH.resolve()
73
73
 
74
74
  source_to_use = None
75
75
 
76
- if cwd_agent.exists():
77
- print(f"[+] Found agent file in current directory: {cwd_agent}")
78
- source_to_use = cwd_agent
79
- elif pkg_agent.exists():
80
- print(f"[+] Found agent file in package: {pkg_agent}")
81
- source_to_use = pkg_agent
76
+ if cwd_skill.exists():
77
+ print(f"[+] Found skill file in current directory: {cwd_skill}")
78
+ source_to_use = cwd_skill
79
+ elif pkg_skill.exists():
80
+ print(f"[+] Found skill file in package: {pkg_skill}")
81
+ source_to_use = pkg_skill
82
82
  else:
83
- print("[-] DEVHIVE_AGENT.md not found.")
84
- print("[*] Using embedded default agent prompt.")
85
- temp_path = Path("DEVHIVE_AGENT.md").resolve()
83
+ print("[-] skills/devhive_workflow.md not found.")
84
+ print("[*] Using embedded default skill prompt.")
85
+ temp_path = Path("devhive_workflow.md").resolve()
86
86
  try:
87
87
  with open(temp_path, "w") as f:
88
- f.write(get_default_agent_content())
88
+ f.write(get_default_skill_content())
89
89
  print(f"[+] Created temporary source file at: {temp_path}")
90
90
  source_to_use = temp_path
91
91
  except Exception as e:
@@ -94,16 +94,36 @@ def configure():
94
94
 
95
95
  # 3. Configure OpenCode
96
96
  if choice in ["opencode", "both"]:
97
- dest_dir = Path.home() / ".config" / "opencode" / "agents"
98
- dest_file = dest_dir / "DevHive0118.md"
99
- _copy_agent_file(source_to_use, dest_dir, dest_file, "OpenCode Agent")
97
+ # Remove legacy agent
98
+ old_agent_dir = Path.home() / ".config" / "opencode" / "agents"
99
+ old_agent = old_agent_dir / "DevHive0119.md"
100
+ if old_agent.exists():
101
+ print(f"[*] Removing legacy OpenCode agent: {old_agent}")
102
+ try:
103
+ old_agent.unlink()
104
+ except Exception as e:
105
+ print(f"[-] Could not remove legacy agent: {e}")
106
+
107
+ dest_dir = Path.home() / ".config" / "opencode" / "skills"
108
+ dest_file = dest_dir / "devhive_workflow.md"
109
+ _copy_agent_file(source_to_use, dest_dir, dest_file, "OpenCode Skill")
100
110
  _configure_devhive()
101
111
 
102
112
  # 4. Configure Copilot
103
113
  if choice in ["copilot", "both"]:
104
- dest_dir = Path.home() / ".copilot" / "agents"
105
- dest_file = dest_dir / "DevHive.md"
106
- _copy_agent_file(source_to_use, dest_dir, dest_file, "Copilot Agent")
114
+ # Remove legacy agent
115
+ old_agent_dir = Path.home() / ".copilot" / "agents"
116
+ old_agent = old_agent_dir / "DevHive.md"
117
+ if old_agent.exists():
118
+ print(f"[*] Removing legacy Copilot agent: {old_agent}")
119
+ try:
120
+ old_agent.unlink()
121
+ except Exception as e:
122
+ print(f"[-] Could not remove legacy agent: {e}")
123
+
124
+ dest_dir = Path.home() / ".copilot" / "instructions"
125
+ dest_file = dest_dir / "devhive_workflow.md"
126
+ _copy_agent_file(source_to_use, dest_dir, dest_file, "Copilot Instructions")
107
127
  _configure_vscode_copilot(dest_file)
108
128
 
109
129
  print("\nConfiguration complete!")
@@ -27,7 +27,9 @@ Note: You have access to the devhive_search_memory tool if you need to find spec
27
27
  Dictionary with 'system_prompt' and 'user_prompt' keys
28
28
  """
29
29
 
30
- if agent_role == "Explorer":
30
+ if agent_role == "CEO":
31
+ return PromptBuilder._build_ceo_prompts(context, **kwargs)
32
+ elif agent_role == "Explorer":
31
33
  return PromptBuilder._build_explorer_prompts(context, **kwargs)
32
34
  elif agent_role == "Proposal":
33
35
  return PromptBuilder._build_proposal_prompts(context)
@@ -47,43 +49,155 @@ Note: You have access to the devhive_search_memory tool if you need to find spec
47
49
  raise ValueError(f"Unknown agent role: {agent_role}")
48
50
 
49
51
  @staticmethod
50
- def _build_explorer_prompts(context: Dict[str, Any], **kwargs) -> Dict[str, str]:
52
+ def _build_ceo_prompts(context: Dict[str, Any], **kwargs) -> Dict[str, str]:
51
53
  requirements = kwargs.get("requirements", "No requirements provided")
52
54
 
53
- system_prompt = "You are the Analyst (Explorer). Output JSON only."
55
+ system_prompt = """
56
+ You are an AI orchestration agent called "CEO".
57
+
58
+ Your job is to orchestrate an AI software development pipeline by selecting and ordering agents to fulfill a feature request.
59
+
60
+ Available agents:
61
+ - Explorer
62
+ - Proposal
63
+ - Architect
64
+ - TaskPlanner
65
+ - Developer
66
+ - QA
67
+ - Auditor
68
+ - Archivist
69
+
70
+ Agent roles:
71
+
72
+ Explorer
73
+ Analyzes requirements, constraints and dependencies.
74
+
75
+ Proposal
76
+ Creates a structured feature proposal and acceptance criteria.
77
+
78
+ Architect
79
+ Designs technical architecture and system structure.
80
+
81
+ TaskPlanner
82
+ Breaks the feature into development tasks.
83
+
84
+ Developer
85
+ Implements the feature.
86
+
87
+ QA
88
+ Creates tests for the implementation.
89
+
90
+ Auditor
91
+ Reviews architecture, consistency, and security.
92
+
93
+ Archivist
94
+ Archives the final project state.
95
+
96
+ Pipeline rules:
97
+ - Explorer should normally run first
98
+ - Developer must run before Archivist
99
+ - Archivist must always be the final step
100
+ - Agents must appear only once
101
+ - The workflow must be logically ordered
102
+
103
+ Agent selection guidelines:
104
+
105
+ Proposal
106
+ Use when the feature requires product clarification or acceptance criteria.
107
+
108
+ Architect
109
+ Use when backend systems, APIs, or architecture are involved.
110
+
111
+ TaskPlanner
112
+ Use when the implementation requires multiple tasks or moderate complexity.
113
+
114
+ QA
115
+ Use when code with logic is implemented.
116
+
117
+ Auditor
118
+ Use when architecture or security should be reviewed.
119
+
120
+ Simple features may skip Proposal, Architect, TaskPlanner, QA, and Auditor.
121
+
122
+ Output rules:
123
+ - Return valid JSON only
124
+ - Do not include explanations outside the JSON
125
+ - Follow the schema exactly
126
+
127
+ Schema:
128
+ {
129
+ "workflow_plan": string[],
130
+ "reasoning": string
131
+ }
132
+ """
54
133
 
55
- user_prompt = f"""Analyze the following feature request: {requirements}
134
+ user_prompt = f"""
135
+ Feature request:
56
136
 
57
- Context: {json.dumps(context, default=str)}
137
+ {requirements}
58
138
 
59
- Your task is to perform initial analysis and exploration.
60
- Check 'project_guidelines' in the context.
61
- - If it says "Guidelines not found.", you MUST establish the technology stack.
62
- - If the stack is clear from the request (e.g. "Use Python/Flask"), generate a Markdown string for 'new_guidelines_content'.
63
- - If the stack is unclear, providing a question in 'clarification_question'.
139
+ Determine the optimal sequence of agents to execute.
140
+ """
141
+
142
+ return {
143
+ "system_prompt": system_prompt,
144
+ "user_prompt": user_prompt
145
+ }
64
146
 
65
- Return JSON with the following keys:
66
- - user_needs: String describing what users need from this feature
67
- - constraints: List of technical or business constraints
68
- - dependencies: List of external dependencies or requirements
69
- - risks: List of potential risks or challenges
70
- - complexity: "low", "medium", or "high".
71
- - "low": Simple changes, no architecture needed.
72
- - "medium": Moderate changes, needs proposal but no complex architecture.
73
- - "high": Complex changes, needs full architecture and planning.
74
- - suggested_workflow: "fast_track" (low), "standard" (medium), or "comprehensive" (high)
75
- - new_guidelines_content: (Optional) Markdown string with best practices if guidelines were missing.
76
- - clarification_question: (Optional) Question to ask user if tech stack is unclear.
147
+ @staticmethod
148
+ def _build_explorer_prompts(context: Dict[str, Any], **kwargs) -> Dict[str, str]:
149
+ requirements = kwargs.get("requirements", "No requirements provided")
150
+
151
+ system_prompt = """
152
+ You are an AI software architecture analyst called "Analyst (Explorer)".
153
+
154
+ Your role is to analyze feature requests and produce structured technical analysis for downstream agents.
155
+
156
+ Responsibilities:
157
+ - Identify user needs
158
+ - Detect constraints
159
+ - List dependencies
160
+ - Identify risks
161
+ - Estimate complexity
162
+ - Suggest workflow
163
+
164
+ Context may include project information such as technology guidelines.
165
+
166
+ Guidelines handling:
167
+ - If project_guidelines says "Guidelines not found.", determine the likely technology stack.
168
+ - If the stack is clear, generate new guidelines.
169
+ - If the stack is unclear, ask a clarification question.
170
+
171
+ Complexity levels:
172
+ - low: simple changes, minimal architecture
173
+ - medium: moderate implementation work
174
+ - high: architectural changes or major system impact
175
+
176
+ Output rules:
177
+ - Output valid JSON only
178
+ - Do not include explanations outside JSON
179
+ - Follow the schema strictly
180
+
181
+ Schema:
182
+ {
183
+ "user_needs": string,
184
+ "constraints": string[],
185
+ "dependencies": string[],
186
+ "risks": string[],
187
+ "complexity": "low" | "medium" | "high",
188
+ "suggested_workflow": "fast_track" | "standard" | "comprehensive",
189
+ "new_guidelines_content": string | null,
190
+ "clarification_question": string | null
191
+ }
192
+ """
193
+
194
+ user_prompt = f"""
195
+ Analyze the following feature request: {requirements}
77
196
 
78
- Example format:
79
- {{
80
- "user_needs": "Users need to export data in CSV format for analysis",
81
- "constraints": ["Must work with existing authentication", "Limited to 10MB file size"],
82
- "dependencies": ["CSV library", "File storage system"],
83
- "risks": ["Large datasets may cause performance issues", "Security concerns with file downloads"],
84
- "complexity": "medium",
85
- "suggested_workflow": "standard"
86
- }}"""
197
+ Context: {json.dumps(context, default=str)}
198
+
199
+ Perform the analysis and exploration and return the JSON response.
200
+ """
87
201
 
88
202
  return {
89
203
  "system_prompt": system_prompt,
@@ -1,6 +1,6 @@
1
1
  """
2
2
  Task-based pipeline orchestrator.
3
- Manages agent sequence and returns Task launch instructions for OpenCode.
3
+ Manages agent sequence and returns Task launch instructions for SDD Skill execution.
4
4
  """
5
5
 
6
6
  import json
@@ -27,7 +27,7 @@ class TaskOrchestrator:
27
27
  - Builds prompts using PromptBuilder
28
28
  - Validates responses using ResponseValidator
29
29
  - Saves artifacts using ArtifactManager
30
- - Returns structured envelopes for OpenCode
30
+ - Returns structured envelopes for Skill execution
31
31
  """
32
32
 
33
33
  def __init__(self, project_name: str):
@@ -279,6 +279,7 @@ class TaskOrchestrator:
279
279
  def _validate_response(self, agent_name: str, response: Dict[str, Any]) -> tuple[bool, str]:
280
280
  """Validate response using appropriate validator method."""
281
281
  validators = {
282
+ "CEO": ResponseValidator.validate_ceo,
282
283
  "Explorer": ResponseValidator.validate_explorer,
283
284
  "Proposal": ResponseValidator.validate_proposal,
284
285
  "Architect": ResponseValidator.validate_architect,
@@ -303,6 +304,7 @@ class TaskOrchestrator:
303
304
  def _get_artifact_key(self, agent_name: str) -> str:
304
305
  """Map agent name to artifact key used in state."""
305
306
  mapping = {
307
+ "CEO": "workflow_plan",
306
308
  "Explorer": "exploration",
307
309
  "Proposal": "proposal",
308
310
  "Architect": "architecture",
@@ -313,7 +315,7 @@ class TaskOrchestrator:
313
315
  "Archivist": "archive"
314
316
  }
315
317
  return mapping.get(agent_name, agent_name.lower())
316
-
318
+
317
319
  def _generate_summary(self, agent_name: str, data: Dict[str, Any]) -> str:
318
320
  """
319
321
  Generate 1-3 sentence executive summary of agent's work.
@@ -322,6 +324,7 @@ class TaskOrchestrator:
322
324
  via their generate_summary() method for more specific summaries.
323
325
  """
324
326
  summaries = {
327
+ "CEO": self._summarize_ceo,
325
328
  "Explorer": self._summarize_explorer,
326
329
  "Proposal": self._summarize_proposal,
327
330
  "Architect": self._summarize_architect,
@@ -334,7 +337,12 @@ class TaskOrchestrator:
334
337
 
335
338
  summarizer = summaries.get(agent_name, lambda x: f"{agent_name} completed successfully.")
336
339
  return summarizer(data)
337
-
340
+
341
+ def _summarize_ceo(self, data: Dict[str, Any]) -> str:
342
+ """Generate summary for CEO agent."""
343
+ plan = data.get("workflow_plan", [])
344
+ return f"Planned workflow with {len(plan)} agents: {' -> '.join(plan)}."
345
+
338
346
  def _summarize_explorer(self, data: Dict[str, Any]) -> str:
339
347
  """Generate summary for Explorer agent."""
340
348
  constraints_count = len(data.get("constraints", []))
@@ -55,7 +55,7 @@ def _parse_json_response(text: str) -> Dict[str, Any]:
55
55
  raise ValueError(f"Invalid JSON response: {e}")
56
56
 
57
57
  # ============================================================================
58
- # TASK-BASED WORKFLOW TOOLS (Recommended - Uses OpenCode Task Tool)
58
+ # TASK-BASED WORKFLOW TOOLS (Recommended - Use devhive_workflow skill)
59
59
  # ============================================================================
60
60
 
61
61
  @mcp.tool()
@@ -64,7 +64,7 @@ def devhive_start_pipeline(project_name: str, requirements: str) -> str:
64
64
  Start a new DevHive pipeline with Task-based execution.
65
65
 
66
66
  This is the RECOMMENDED way to use DevHive. It returns Task launch instructions
67
- that OpenCode can use to execute each agent in isolated context.
67
+ that OpenCode should execute using the devhive_workflow skill.
68
68
 
69
69
  Remember always read AGENTS.md if exists.
70
70
 
@@ -75,7 +75,7 @@ def devhive_start_pipeline(project_name: str, requirements: str) -> str:
75
75
  Returns:
76
76
  JSON with Task launch instructions:
77
77
  - status: "pending" (next task ready) or "complete" (pipeline done)
78
- - agent: Next agent to run (Explorer, Proposal, etc.)
78
+ - agent: Next agent to run (CEO, Explorer, Proposal, etc.)
79
79
  - reason: Why this agent needs to run
80
80
  - system_prompt: System prompt for the Task
81
81
  - user_prompt: User prompt for the Task
@@ -85,7 +85,7 @@ def devhive_start_pipeline(project_name: str, requirements: str) -> str:
85
85
 
86
86
  Example:
87
87
  result = devhive_start_pipeline("csv_export", "Add CSV export to dashboard")
88
- # Use result["system_prompt"] and result["user_prompt"] with OpenCode Task tool
88
+ # Use result["system_prompt"] and result["user_prompt"] with Task tool (general)
89
89
  # Then call devhive_submit_result() with the Task output
90
90
  """
91
91
  try:
@@ -94,7 +94,7 @@ def devhive_start_pipeline(project_name: str, requirements: str) -> str:
94
94
  # Initialize orchestrator (creates project if needed)
95
95
  orchestrator = TaskOrchestrator(project_name)
96
96
 
97
- # Get first task (Explorer)
97
+ # Get first task (CEO)
98
98
  task_info = orchestrator.get_next_task(requirements=requirements)
99
99
 
100
100
  return json.dumps(task_info, indent=2)
@@ -116,7 +116,7 @@ def devhive_submit_result(project_name: str, agent_name: str, llm_response: str)
116
116
 
117
117
  Args:
118
118
  project_name: Project identifier
119
- agent_name: Name of agent that produced result (Explorer, Proposal, Architect,
119
+ agent_name: Name of agent that produced result (CEO, Explorer, Proposal, Architect,
120
120
  TaskPlanner, Developer, QA, Auditor, or Archivist)
121
121
  llm_response: Raw LLM response (JSON string, can include markdown code blocks)
122
122
 
@@ -136,7 +136,7 @@ def devhive_submit_result(project_name: str, agent_name: str, llm_response: str)
136
136
  if result["status"] == "success":
137
137
  print(result["executive_summary"])
138
138
  next_task = result["next_task"]
139
- # Use next_task with OpenCode Task tool
139
+ # Use next_task with Task tool (general)
140
140
  """
141
141
  try:
142
142
  from devhive.core.task_orchestrator import TaskOrchestrator
@@ -182,7 +182,7 @@ def get_next_step(project_name: str) -> str:
182
182
 
183
183
  Returns:
184
184
  JSON string with:
185
- - agent: The agent role name (Explorer, Proposal, etc.)
185
+ - agent: The agent role name (CEO, Explorer, Proposal, etc.)
186
186
  - reason: Why this agent needs to run
187
187
  - system_prompt: System prompt to send to LLM
188
188
  - user_prompt: User prompt to send to LLM
@@ -211,9 +211,9 @@ def get_next_step(project_name: str) -> str:
211
211
  context = agent.get_context()
212
212
 
213
213
  # Build prompts using PromptBuilder
214
- # For Explorer, we need to check if requirements are in kwargs
215
- if agent_role == "Explorer":
216
- # Requirements should be provided when executing Explorer
214
+ # For Explorer/CEO, we need to check if requirements are in kwargs
215
+ if agent_role in ["Explorer", "CEO"]:
216
+ # Requirements should be provided when executing
217
217
  prompts = PromptBuilder.build_prompts(agent_role, context, requirements="[Requirements will be provided when executing]")
218
218
  else:
219
219
  prompts = PromptBuilder.build_prompts(agent_role, context)
@@ -7,6 +7,28 @@ class ResponseValidator:
7
7
  Ensures responses contain required keys and valid data structures.
8
8
  """
9
9
 
10
+ @staticmethod
11
+ def validate_ceo(response: Dict[str, Any]) -> Tuple[bool, str]:
12
+ """
13
+ Validate CEO agent response.
14
+
15
+ Expected keys: workflow_plan, reasoning
16
+ """
17
+ required_keys = ["workflow_plan", "reasoning"]
18
+ is_valid, error = ResponseValidator._validate_keys(response, required_keys, "CEO")
19
+ if not is_valid:
20
+ return is_valid, error
21
+
22
+ if not isinstance(response.get("workflow_plan"), list):
23
+ return False, "CEO: 'workflow_plan' must be a list of agent names"
24
+
25
+ valid_agents = ["Explorer", "Proposal", "Architect", "TaskPlanner", "Developer", "QA", "Auditor", "Archivist"]
26
+ for agent in response["workflow_plan"]:
27
+ if agent not in valid_agents:
28
+ return False, f"CEO: Invalid agent name '{agent}' in workflow_plan. Valid agents are: {', '.join(valid_agents)}"
29
+
30
+ return True, ""
31
+
10
32
  @staticmethod
11
33
  def validate_explorer(response: Dict[str, Any]) -> Tuple[bool, str]:
12
34
  """
@@ -191,6 +213,7 @@ class ResponseValidator:
191
213
  List of expected key names
192
214
  """
193
215
  key_mapping = {
216
+ "CEO": ["workflow_plan", "reasoning"],
194
217
  "Explorer": ["user_needs", "constraints", "dependencies", "risks", "complexity", "suggested_workflow", "new_guidelines_content", "clarification_question"],
195
218
  "Proposal": ["feature_description", "user_value", "acceptance_criteria", "scope"],
196
219
  "Architect": ["architecture_pattern", "components", "data_models", "apis"],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devhive
3
- Version: 0.1.18
3
+ Version: 0.1.20
4
4
  Summary: DevHive MCP Server
5
5
  Requires-Python: >=3.10
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "devhive"
3
- version = "0.1.18"
3
+ version = "0.1.20"
4
4
  description = "DevHive MCP Server"
5
5
  requires-python = ">=3.10"
6
6
 
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="devhive",
5
- version="0.1.18",
5
+ version="0.1.20",
6
6
  packages=find_packages(),
7
7
  package_data={
8
8
  "devhive": ["skills/*.md", "skills/*/*.md"],
@@ -1,190 +0,0 @@
1
- import json
2
- from typing import Dict, Any
3
- from mcp.server.fastmcp import Context
4
- from devhive.agents.base_agent import BaseAgent
5
- from devhive.core.project_state_manager import ProjectStateManager
6
-
7
- class CEOAgent(BaseAgent):
8
- role = "CEO"
9
-
10
- def get_next_agent_deterministic(self) -> Dict[str, Any]:
11
- """
12
- Determine next agent to run based on current state (no LLM needed).
13
- This is a rule-based decision making process following the strict pipeline sequence.
14
-
15
- Pipeline order:
16
- 1. Explorer
17
- 2. Proposal
18
- 3. Architect
19
- 4. TaskPlanner
20
- 5. Developer (Iterative)
21
- 6. QA
22
- 7. Auditor
23
- 8. Archivist
24
-
25
- Returns:
26
- Dict with 'agent' (role name) and 'reason' (explanation)
27
- """
28
- state = self.state_manager.get_state()
29
- artifacts = state.get("artifacts", {})
30
-
31
- # Check each stage in order
32
- if artifacts.get("exploration") is None:
33
- return {
34
- "agent": "Explorer",
35
- "reason": "Need initial feature analysis and exploration"
36
- }
37
-
38
- # Determine complexity from exploration artifact
39
- complexity = "high" # Default to high safety
40
- try:
41
- expl_id = artifacts.get("exploration")
42
- if expl_id:
43
- expl_data = self.artifact_manager.load_artifact(expl_id)
44
- complexity = expl_data.get("complexity", "high").lower()
45
- except Exception:
46
- pass # Fallback to high complexity on error
47
-
48
- # Dynamic Routing based on Complexity
49
- # Low: Explorer -> Developer -> QA -> Archivist
50
- # Medium: Explorer -> Proposal -> Developer -> QA -> Archivist
51
- # High: Full Suite
52
-
53
- if artifacts.get("proposal") is None:
54
- if complexity == "low":
55
- pass # Skip Proposal
56
- else:
57
- return {
58
- "agent": "Proposal",
59
- "reason": "Exploration complete, need feature proposal"
60
- }
61
-
62
- if artifacts.get("architecture") is None:
63
- if complexity in ["low", "medium"]:
64
- pass # Skip Architecture
65
- else:
66
- return {
67
- "agent": "Architect",
68
- "reason": "Proposal complete, need technical architecture design"
69
- }
70
-
71
- if artifacts.get("tasks") is None:
72
- if complexity in ["low", "medium"]:
73
- pass # Skip Task Planning
74
- else:
75
- return {
76
- "agent": "TaskPlanner",
77
- "reason": "Architecture complete, need task breakdown"
78
- }
79
-
80
- if artifacts.get("implementation") is None:
81
- # Iterative Developer Workflow
82
- dev_progress = state.get("developer_progress", {})
83
- pending_tasks = dev_progress.get("pending_tasks", [])
84
- completed_tasks = dev_progress.get("completed_tasks", [])
85
-
86
- # If we haven't initialized developer progress yet, we need to route to developer
87
- # Or if there are still pending tasks to complete
88
- if not dev_progress or pending_tasks:
89
- task_count = len(pending_tasks) if pending_tasks else "tasks"
90
- return {
91
- "agent": "Developer",
92
- "reason": f"Need to execute {task_count} pending tasks sequentially"
93
- }
94
- elif not pending_tasks and completed_tasks:
95
- # This state shouldn't normally happen (orchestrator should create implementation artifact)
96
- # But just in case, if pending is empty but completed is not, we're done with implementation
97
- pass
98
- else:
99
- # No tasks found at all? Fallback to single run
100
- return {
101
- "agent": "Developer",
102
- "reason": "Ready for implementation"
103
- }
104
-
105
- if artifacts.get("tests") is None:
106
- return {
107
- "agent": "QA",
108
- "reason": "Implementation complete, need tests"
109
- }
110
-
111
- if artifacts.get("verification") is None:
112
- if complexity in ["low", "medium"]:
113
- pass # Skip Auditor
114
- else:
115
- return {
116
- "agent": "Auditor",
117
- "reason": "Tests complete, need final verification"
118
- }
119
-
120
- if artifacts.get("archive") is None:
121
- return {
122
- "agent": "Archivist",
123
- "reason": "All stages complete, ready to archive project"
124
- }
125
-
126
- # All done
127
- return {
128
- "agent": "Complete",
129
- "reason": "All pipeline stages finished, project is complete"
130
- }
131
-
132
- async def execute(self, ctx: Context, **kwargs) -> Dict[str, Any]:
133
- """
134
- Original LLM-based decision making (requires sampling support).
135
- Currently not used in manual workflow.
136
- """
137
- state_manager = ProjectStateManager(self.project_name)
138
- state = state_manager.get_state()
139
-
140
- context = {
141
- "project_status": state.get('status'),
142
- "artifacts_summary": state.get("artifacts", {})
143
- }
144
-
145
- sys_prompt = """
146
- You are the CEO orchestrating an AI software development pipeline.
147
-
148
- The pipeline is strictly sequential:
149
-
150
- 1 Explorer
151
- 2 Proposal
152
- 3 Architect
153
- 4 TaskPlanner
154
- 5 Developer
155
- 6 QA
156
- 7 Auditor
157
- 8 Archivist
158
-
159
- Rules:
160
-
161
- - NEVER return Wait unless the pipeline is finished
162
- - ALWAYS select the next missing role
163
- - Each role produces an artifact
164
-
165
- Explorer → exploration
166
- Proposal → proposal
167
- Architect → architecture
168
- TaskPlanner → tasks
169
- Developer → implementation
170
- QA → tests
171
- Auditor → verification
172
- Archivist → archived
173
-
174
- Return JSON only:
175
- { "decision": "Run <Role>", "reason": "..." }
176
- """
177
- user_prompt = f"""Decide next step.
178
-
179
- Project: {context.get('project_name')}
180
- Status: {context.get('project_status')}
181
- Stage: {context.get('stage')}
182
- Artifacts: {json.dumps(context.get('artifacts_summary', {}), indent=2)}
183
-
184
- Available Roles: Explorer, Proposal, Architect, TaskPlanner, Developer, QA, Auditor, Archivist.
185
- Return JSON: {{ "decision": "Run <Role>", "reason": "..." }}
186
- If finished, "Run Archivist".
187
- If stage is "initialization", "Run Explorer"
188
- """
189
- resp = await self._call_llm(ctx, sys_prompt, user_prompt)
190
- return self._parse_json(resp)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes