diff --git a/.github/agents/bmad-agent-bmad-master.md b/.github/agents/bmad-agent-bmad-master.md
new file mode 100644
index 000000000..fcf0a0802
--- /dev/null
+++ b/.github/agents/bmad-agent-bmad-master.md
@@ -0,0 +1,16 @@
+---
+name: 'bmad-master'
+description: 'bmad-master agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/core/agents/bmad-master.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmb-agent-builder.md b/.github/agents/bmad-agent-bmb-agent-builder.md
new file mode 100644
index 000000000..33c52b842
--- /dev/null
+++ b/.github/agents/bmad-agent-bmb-agent-builder.md
@@ -0,0 +1,16 @@
+---
+name: 'agent-builder'
+description: 'agent-builder agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmb/agents/agent-builder.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmb-module-builder.md b/.github/agents/bmad-agent-bmb-module-builder.md
new file mode 100644
index 000000000..2960169bb
--- /dev/null
+++ b/.github/agents/bmad-agent-bmb-module-builder.md
@@ -0,0 +1,16 @@
+---
+name: 'module-builder'
+description: 'module-builder agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmb/agents/module-builder.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmb-workflow-builder.md b/.github/agents/bmad-agent-bmb-workflow-builder.md
new file mode 100644
index 000000000..c0c866d85
--- /dev/null
+++ b/.github/agents/bmad-agent-bmb-workflow-builder.md
@@ -0,0 +1,16 @@
+---
+name: 'workflow-builder'
+description: 'workflow-builder agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmb/agents/workflow-builder.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmm-analyst.md b/.github/agents/bmad-agent-bmm-analyst.md
new file mode 100644
index 000000000..bac849d27
--- /dev/null
+++ b/.github/agents/bmad-agent-bmm-analyst.md
@@ -0,0 +1,16 @@
+---
+name: 'analyst'
+description: 'analyst agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmm/agents/analyst.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmm-architect.md b/.github/agents/bmad-agent-bmm-architect.md
new file mode 100644
index 000000000..fc4ead3aa
--- /dev/null
+++ b/.github/agents/bmad-agent-bmm-architect.md
@@ -0,0 +1,16 @@
+---
+name: 'architect'
+description: 'architect agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmm/agents/architect.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmm-dev.md b/.github/agents/bmad-agent-bmm-dev.md
new file mode 100644
index 000000000..e2d927ef2
--- /dev/null
+++ b/.github/agents/bmad-agent-bmm-dev.md
@@ -0,0 +1,16 @@
+---
+name: 'dev'
+description: 'dev agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmm/agents/dev.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmm-pm.md b/.github/agents/bmad-agent-bmm-pm.md
new file mode 100644
index 000000000..d1b8daa67
--- /dev/null
+++ b/.github/agents/bmad-agent-bmm-pm.md
@@ -0,0 +1,16 @@
+---
+name: 'pm'
+description: 'pm agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmm/agents/pm.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmm-quick-flow-solo-dev.md b/.github/agents/bmad-agent-bmm-quick-flow-solo-dev.md
new file mode 100644
index 000000000..c8e1840ea
--- /dev/null
+++ b/.github/agents/bmad-agent-bmm-quick-flow-solo-dev.md
@@ -0,0 +1,16 @@
+---
+name: 'quick-flow-solo-dev'
+description: 'quick-flow-solo-dev agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmm/agents/quick-flow-solo-dev.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmm-quinn.md b/.github/agents/bmad-agent-bmm-quinn.md
new file mode 100644
index 000000000..c306aae3a
--- /dev/null
+++ b/.github/agents/bmad-agent-bmm-quinn.md
@@ -0,0 +1,16 @@
+---
+name: 'quinn'
+description: 'quinn agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmm/agents/quinn.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmm-sm.md b/.github/agents/bmad-agent-bmm-sm.md
new file mode 100644
index 000000000..c7ee7dbba
--- /dev/null
+++ b/.github/agents/bmad-agent-bmm-sm.md
@@ -0,0 +1,16 @@
+---
+name: 'sm'
+description: 'sm agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmm/agents/sm.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmm-tech-writer.md b/.github/agents/bmad-agent-bmm-tech-writer.md
new file mode 100644
index 000000000..c020ac97f
--- /dev/null
+++ b/.github/agents/bmad-agent-bmm-tech-writer.md
@@ -0,0 +1,16 @@
+---
+name: 'tech-writer'
+description: 'tech-writer agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmm/agents/tech-writer/tech-writer.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-bmm-ux-designer.md b/.github/agents/bmad-agent-bmm-ux-designer.md
new file mode 100644
index 000000000..5dbb42b47
--- /dev/null
+++ b/.github/agents/bmad-agent-bmm-ux-designer.md
@@ -0,0 +1,16 @@
+---
+name: 'ux-designer'
+description: 'ux-designer agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/bmm/agents/ux-designer.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-cis-brainstorming-coach.md b/.github/agents/bmad-agent-cis-brainstorming-coach.md
new file mode 100644
index 000000000..c581ebe3b
--- /dev/null
+++ b/.github/agents/bmad-agent-cis-brainstorming-coach.md
@@ -0,0 +1,16 @@
+---
+name: 'brainstorming-coach'
+description: 'brainstorming-coach agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/cis/agents/brainstorming-coach.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-cis-creative-problem-solver.md b/.github/agents/bmad-agent-cis-creative-problem-solver.md
new file mode 100644
index 000000000..7974ff473
--- /dev/null
+++ b/.github/agents/bmad-agent-cis-creative-problem-solver.md
@@ -0,0 +1,16 @@
+---
+name: 'creative-problem-solver'
+description: 'creative-problem-solver agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/cis/agents/creative-problem-solver.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-cis-design-thinking-coach.md b/.github/agents/bmad-agent-cis-design-thinking-coach.md
new file mode 100644
index 000000000..fc2a5892f
--- /dev/null
+++ b/.github/agents/bmad-agent-cis-design-thinking-coach.md
@@ -0,0 +1,16 @@
+---
+name: 'design-thinking-coach'
+description: 'design-thinking-coach agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/cis/agents/design-thinking-coach.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-cis-innovation-strategist.md b/.github/agents/bmad-agent-cis-innovation-strategist.md
new file mode 100644
index 000000000..df0e4b2e9
--- /dev/null
+++ b/.github/agents/bmad-agent-cis-innovation-strategist.md
@@ -0,0 +1,16 @@
+---
+name: 'innovation-strategist'
+description: 'innovation-strategist agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/cis/agents/innovation-strategist.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-cis-presentation-master.md b/.github/agents/bmad-agent-cis-presentation-master.md
new file mode 100644
index 000000000..830129b08
--- /dev/null
+++ b/.github/agents/bmad-agent-cis-presentation-master.md
@@ -0,0 +1,16 @@
+---
+name: 'presentation-master'
+description: 'presentation-master agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/cis/agents/presentation-master.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-cis-storyteller.md b/.github/agents/bmad-agent-cis-storyteller.md
new file mode 100644
index 000000000..b6b22669e
--- /dev/null
+++ b/.github/agents/bmad-agent-cis-storyteller.md
@@ -0,0 +1,16 @@
+---
+name: 'storyteller'
+description: 'storyteller agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/cis/agents/storyteller/storyteller.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmad-agent-tea-tea.md b/.github/agents/bmad-agent-tea-tea.md
new file mode 100644
index 000000000..1f32afc80
--- /dev/null
+++ b/.github/agents/bmad-agent-tea-tea.md
@@ -0,0 +1,16 @@
+---
+name: 'tea'
+description: 'tea agent'
+disable-model-invocation: true
+---
+
+You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
+
+
+1. LOAD the FULL agent file from {project-root}/_bmad/tea/agents/tea.md
+2. READ its entire contents - this contains the complete agent persona, menu, and instructions
+3. FOLLOW every step in the section precisely
+4. DISPLAY the welcome/greeting as instructed
+5. PRESENT the numbered menu
+6. WAIT for user input before proceeding
+
diff --git a/.github/agents/bmd-custom-bmb-agent-builder.agent.md b/.github/agents/bmd-custom-bmb-agent-builder.agent.md
deleted file mode 100644
index 478f3c1d9..000000000
--- a/.github/agents/bmd-custom-bmb-agent-builder.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Agent Builder agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Agent Builder Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmb/agents/agent-builder.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmb-module-builder.agent.md b/.github/agents/bmd-custom-bmb-module-builder.agent.md
deleted file mode 100644
index 1064ddeca..000000000
--- a/.github/agents/bmd-custom-bmb-module-builder.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Module Builder agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Module Builder Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmb/agents/module-builder.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmb-workflow-builder.agent.md b/.github/agents/bmd-custom-bmb-workflow-builder.agent.md
deleted file mode 100644
index 6c00421b3..000000000
--- a/.github/agents/bmd-custom-bmb-workflow-builder.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Workflow Builder agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Workflow Builder Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmb/agents/workflow-builder.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmgd-game-architect.agent.md b/.github/agents/bmd-custom-bmgd-game-architect.agent.md
deleted file mode 100644
index 49bae6459..000000000
--- a/.github/agents/bmd-custom-bmgd-game-architect.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Game Architect agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Game Architect Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmgd/agents/game-architect.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmgd-game-designer.agent.md b/.github/agents/bmd-custom-bmgd-game-designer.agent.md
deleted file mode 100644
index df2bfc18c..000000000
--- a/.github/agents/bmd-custom-bmgd-game-designer.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Game Designer agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Game Designer Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmgd/agents/game-designer.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmgd-game-dev.agent.md b/.github/agents/bmd-custom-bmgd-game-dev.agent.md
deleted file mode 100644
index 8a14503c5..000000000
--- a/.github/agents/bmd-custom-bmgd-game-dev.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Game Dev agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Game Dev Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmgd/agents/game-dev.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmgd-game-qa.agent.md b/.github/agents/bmd-custom-bmgd-game-qa.agent.md
deleted file mode 100644
index 04063fb8e..000000000
--- a/.github/agents/bmd-custom-bmgd-game-qa.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Game Qa agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Game Qa Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmgd/agents/game-qa.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmgd-game-scrum-master.agent.md b/.github/agents/bmd-custom-bmgd-game-scrum-master.agent.md
deleted file mode 100644
index 337047296..000000000
--- a/.github/agents/bmd-custom-bmgd-game-scrum-master.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Game Scrum Master agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Game Scrum Master Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmgd/agents/game-scrum-master.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmgd-game-solo-dev.agent.md b/.github/agents/bmd-custom-bmgd-game-solo-dev.agent.md
deleted file mode 100644
index 2e722762c..000000000
--- a/.github/agents/bmd-custom-bmgd-game-solo-dev.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Game Solo Dev agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Game Solo Dev Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmgd/agents/game-solo-dev.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmm-analyst.agent.md b/.github/agents/bmd-custom-bmm-analyst.agent.md
deleted file mode 100644
index 06453a791..000000000
--- a/.github/agents/bmd-custom-bmm-analyst.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Analyst agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Analyst Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmm/agents/analyst.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmm-architect.agent.md b/.github/agents/bmd-custom-bmm-architect.agent.md
deleted file mode 100644
index 8f4a8c18b..000000000
--- a/.github/agents/bmd-custom-bmm-architect.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Architect agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Architect Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmm/agents/architect.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmm-dev.agent.md b/.github/agents/bmd-custom-bmm-dev.agent.md
deleted file mode 100644
index ea91fc734..000000000
--- a/.github/agents/bmd-custom-bmm-dev.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Dev agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Dev Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmm/agents/dev.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmm-pm.agent.md b/.github/agents/bmd-custom-bmm-pm.agent.md
deleted file mode 100644
index e2652e1ce..000000000
--- a/.github/agents/bmd-custom-bmm-pm.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Pm agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Pm Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmm/agents/pm.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmm-quick-flow-solo-dev.agent.md b/.github/agents/bmd-custom-bmm-quick-flow-solo-dev.agent.md
deleted file mode 100644
index 82502c5e1..000000000
--- a/.github/agents/bmd-custom-bmm-quick-flow-solo-dev.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Quick Flow Solo Dev agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Quick Flow Solo Dev Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmm/agents/quick-flow-solo-dev.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmm-sm.agent.md b/.github/agents/bmd-custom-bmm-sm.agent.md
deleted file mode 100644
index 49144b38d..000000000
--- a/.github/agents/bmd-custom-bmm-sm.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Sm agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Sm Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmm/agents/sm.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmm-tea.agent.md b/.github/agents/bmd-custom-bmm-tea.agent.md
deleted file mode 100644
index e710b0aac..000000000
--- a/.github/agents/bmd-custom-bmm-tea.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Tea agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Tea Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmm/agents/tea.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmm-tech-writer.agent.md b/.github/agents/bmd-custom-bmm-tech-writer.agent.md
deleted file mode 100644
index 74a593a29..000000000
--- a/.github/agents/bmd-custom-bmm-tech-writer.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Tech Writer agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Tech Writer Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmm/agents/tech-writer.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-bmm-ux-designer.agent.md b/.github/agents/bmd-custom-bmm-ux-designer.agent.md
deleted file mode 100644
index 882f537f5..000000000
--- a/.github/agents/bmd-custom-bmm-ux-designer.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Ux Designer agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Ux Designer Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/bmm/agents/ux-designer.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-cis-brainstorming-coach.agent.md b/.github/agents/bmd-custom-cis-brainstorming-coach.agent.md
deleted file mode 100644
index bcadfb3e9..000000000
--- a/.github/agents/bmd-custom-cis-brainstorming-coach.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Brainstorming Coach agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Brainstorming Coach Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/cis/agents/brainstorming-coach.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-cis-creative-problem-solver.agent.md b/.github/agents/bmd-custom-cis-creative-problem-solver.agent.md
deleted file mode 100644
index 97cceb16e..000000000
--- a/.github/agents/bmd-custom-cis-creative-problem-solver.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Creative Problem Solver agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Creative Problem Solver Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/cis/agents/creative-problem-solver.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-cis-design-thinking-coach.agent.md b/.github/agents/bmd-custom-cis-design-thinking-coach.agent.md
deleted file mode 100644
index b1b86aa63..000000000
--- a/.github/agents/bmd-custom-cis-design-thinking-coach.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Design Thinking Coach agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Design Thinking Coach Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/cis/agents/design-thinking-coach.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-cis-innovation-strategist.agent.md b/.github/agents/bmd-custom-cis-innovation-strategist.agent.md
deleted file mode 100644
index ce77c703b..000000000
--- a/.github/agents/bmd-custom-cis-innovation-strategist.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Innovation Strategist agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Innovation Strategist Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/cis/agents/innovation-strategist.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-cis-presentation-master.agent.md b/.github/agents/bmd-custom-cis-presentation-master.agent.md
deleted file mode 100644
index 6666b0cde..000000000
--- a/.github/agents/bmd-custom-cis-presentation-master.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Presentation Master agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Presentation Master Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/cis/agents/presentation-master.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-cis-storyteller.agent.md b/.github/agents/bmd-custom-cis-storyteller.agent.md
deleted file mode 100644
index 6a6f4fb93..000000000
--- a/.github/agents/bmd-custom-cis-storyteller.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Storyteller agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Storyteller Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/cis/agents/storyteller/storyteller.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/agents/bmd-custom-core-bmad-master.agent.md b/.github/agents/bmd-custom-core-bmad-master.agent.md
deleted file mode 100644
index 12c3fff1b..000000000
--- a/.github/agents/bmd-custom-core-bmad-master.agent.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-description: "Activates the Bmad Master agent persona."
-tools: ["changes","edit","fetch","githubRepo","problems","runCommands","runTasks","runTests","search","runSubagent","testFailure","todos","usages"]
----
-
-# Bmad Master Agent
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-
-1. LOAD the FULL agent file from @_bmad/core/agents/bmad-master.md
-2. READ its entire contents - this contains the complete agent persona, menu, and instructions
-3. Execute ALL activation steps exactly as written in the agent file
-4. Follow the agent's persona and menu system precisely
-5. Stay in character throughout the session
-
-
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index 90f3712d1..21be0f000 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -1,739 +1,55 @@
-# GitHub Copilot Instructions for Websoft9
+# Websoft9 Project - AI Collaboration Guidelines
-## Project Overview
+## Project Context
-Websoft9 is a containerized application management platform consisting of:
-- **Cockpit**: Web-based system management interface
-- **Four Core Containers**:
- - **AppHub**: Custom-built application hub (Python + FastAPI) - our main service
- - **Gitea**: Git repository service
- - **Portainer**: Docker container management UI
- - **Nginx Proxy Manager**: Reverse proxy and SSL management
+**websoft9** is an open-source, GitOps-driven application deployment platform for single-server scenarios, designed for teams without dedicated DevOps capabilities. Combines 300+ app store with Infrastructure as Code.
-## Tech Stack
+**Target Users**: SMBs, indie developers, small teams (novice to intermediate skill level)
-### AppHub Service (Primary Development Focus)
-- **Language**: Python 3.11+
-- **Framework**: FastAPI
-- **Async**: asyncio-based for non-blocking operations
-- **Validation**: Pydantic models
-- **Database**: SQLite (with option for PostgreSQL)
-- **Docker**: Containerized deployment
+**Core Philosophy**: More powerful than basic tools, simpler than enterprise platforms
-### Infrastructure
-- **Orchestration**: Docker Compose
-- **Proxy**: Nginx-based reverse proxy
-- **System Management**: Cockpit
-- **Version Control**: Gitea (self-hosted)
-- **Container Management**: Portainer
-
-## Code Standards
-
-### Python/FastAPI Best Practices
-
-1. **Follow PEP 8** - Use consistent Python style
-2. **Type Hints**: Always use type annotations
-3. **Async First**: Prefer `async/await` for I/O operations
-4. **Pydantic Models**: Use for request/response validation
-5. **Dependency Injection**: Leverage FastAPI's `Depends()`
-
-### Example Code Pattern
-
-```python
-from fastapi import APIRouter, Depends, HTTPException, status
-from pydantic import BaseModel
-from typing import Optional
-import logging
-
-logger = logging.getLogger(__name__)
-
-# Pydantic Schema
-class AppCreate(BaseModel):
- name: str
- description: Optional[str] = None
- image: str
-
-class AppResponse(BaseModel):
- id: str
- name: str
- status: str
-
-# Router
-router = APIRouter(prefix="/api/v1/apps", tags=["applications"])
-
-@router.post("/", response_model=AppResponse, status_code=status.HTTP_201_CREATED)
-async def create_application(
- app: AppCreate,
- current_user: dict = Depends(get_current_user)
-) -> AppResponse:
- """
- Create a new application instance
-
- Args:
- app: Application configuration
- current_user: Authenticated user from dependency
-
- Returns:
- AppResponse with created application details
-
- Raises:
- HTTPException: If creation fails
- """
- try:
- result = await app_service.create(app, current_user)
- logger.info(f"Application created: {result.id}")
- return result
- except ValueError as e:
- logger.error(f"Invalid application config: {e}")
- raise HTTPException(
- status_code=status.HTTP_400_BAD_REQUEST,
- detail=str(e)
- )
- except Exception as e:
- logger.exception(f"Failed to create application: {e}")
- raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail="Internal server error"
- )
-```
-
-## Project Structure
-
-```
-websoft9/
-├── apphub/ # Main FastAPI application
-│ ├── src/
-│ │ ├── api/
-│ │ │ └── v1/ # API version 1 routes
-│ │ │ ├── routers/ # Endpoint definitions
-│ │ │ └── deps.py # Dependencies (auth, db, etc.)
-│ │ ├── core/ # Business logic & services
-│ │ ├── schemas/ # Pydantic models
-│ │ ├── models/ # Database models
-│ │ ├── db/ # Database utilities
-│ │ └── main.py # FastAPI app entry point
-│ ├── tests/ # pytest test suite
-│ ├── requirements.txt
-│ └── Dockerfile
-├── docker/
-│ ├── docker-compose.yml # Service orchestration
-│ ├── .env # Environment variables
-│ └── proxy/
-│ └── config/ # Nginx configurations
-├── cockpit/ # Cockpit configurations
-├── scripts/ # Automation scripts
-└── docs/ # Documentation
-```
-
-## Development Guidelines
-
-### Adding New API Endpoints
-
-1. **Define Schema** in `apphub/src/schemas/`
- ```python
- # apphub/src/schemas/deployment.py
- from pydantic import BaseModel, Field
-
- class DeploymentCreate(BaseModel):
- app_id: str = Field(..., description="Application ID")
- config: dict = Field(default_factory=dict)
- ```
-
-2. **Implement Service Logic** in `apphub/src/core/`
- ```python
- # apphub/src/core/deployment_service.py
- async def deploy_application(app_id: str, config: dict) -> dict:
- # Business logic here
- pass
- ```
-
-3. **Create Router** in `apphub/src/api/v1/routers/`
- ```python
- # apphub/src/api/v1/routers/deployments.py
- from fastapi import APIRouter
-
- router = APIRouter(prefix="/deployments", tags=["deployments"])
-
- @router.post("/")
- async def create_deployment(...):
- pass
- ```
-
-4. **Add Tests** in `tests/`
- ```python
- # tests/test_deployments.py
- import pytest
- from httpx import AsyncClient
-
- @pytest.mark.asyncio
- async def test_create_deployment(client: AsyncClient):
- response = await client.post("/api/v1/deployments", json={...})
- assert response.status_code == 201
- ```
-
-### Docker Container Management
-
-When working with Docker operations in AppHub:
-
-```python
-import docker
-from docker.errors import NotFound, APIError
-
-async def restart_container(container_name: str) -> dict:
- """Restart a Docker container"""
- try:
- client = docker.from_env()
- container = client.containers.get(container_name)
- container.restart()
- return {"status": "success", "container": container_name}
- except NotFound:
- raise HTTPException(
- status_code=404,
- detail=f"Container {container_name} not found"
- )
- except APIError as e:
- raise HTTPException(
- status_code=500,
- detail=f"Docker API error: {str(e)}"
- )
-```
-
-### Error Handling Pattern
-
-Always use structured error handling:
-
-```python
-try:
- result = await service.perform_operation()
- return result
-except ValueError as e:
- # Client error - bad input
- logger.warning(f"Invalid input: {e}")
- raise HTTPException(status_code=400, detail=str(e))
-except PermissionError as e:
- # Authorization error
- logger.warning(f"Permission denied: {e}")
- raise HTTPException(status_code=403, detail="Permission denied")
-except NotFoundError as e:
- # Resource not found
- raise HTTPException(status_code=404, detail=str(e))
-except Exception as e:
- # Unexpected server error
- logger.exception(f"Unexpected error: {e}")
- raise HTTPException(status_code=500, detail="Internal server error")
-```
-
-### Logging Standards
-
-```python
-import logging
-
-logger = logging.getLogger(__name__)
-
-# Info: normal operations
-logger.info(f"Application {app_id} started successfully")
-
-# Warning: recoverable issues
-logger.warning(f"Deprecated API endpoint called: {endpoint}")
-
-# Error: operation failures
-logger.error(f"Failed to connect to database: {error}")
-
-# Exception: with full stack trace
-logger.exception(f"Unexpected error in {function_name}")
-```
-
-## Testing Guidelines
-
-### Test Structure
-
-```python
-import pytest
-from httpx import AsyncClient
-from fastapi.testclient import TestClient
-
-@pytest.fixture
-async def client():
- """Async HTTP client fixture"""
- async with AsyncClient(app=app, base_url="http://test") as ac:
- yield ac
-
-@pytest.mark.asyncio
-async def test_get_application(client: AsyncClient):
- """Test retrieving an application"""
- response = await client.get("/api/v1/apps/test-app")
- assert response.status_code == 200
- assert response.json()["name"] == "test-app"
-
-@pytest.mark.asyncio
-async def test_create_application_invalid(client: AsyncClient):
- """Test creating application with invalid data"""
- response = await client.post("/api/v1/apps", json={"invalid": "data"})
- assert response.status_code == 422
-```
-
-### Running Tests
-
-```bash
-# Run all tests
-pytest
-
-# Run with coverage
-pytest --cov=apphub --cov-report=html
-
-# Run specific test file
-pytest tests/test_apps.py
-
-# Run with verbose output
-pytest -v
-```
-
-## Docker & Container Guidelines
-
-### Dockerfile Best Practices
-
-```dockerfile
-# Use specific Python version
-FROM python:3.11-slim
-
-# Set working directory
-WORKDIR /app
-
-# Install dependencies separately for better caching
-COPY requirements.txt .
-RUN pip install --no-cache-dir -r requirements.txt
-
-# Copy application code
-COPY . .
-
-# Use non-root user
-RUN useradd -m appuser
-USER appuser
-
-# Expose port
-EXPOSE 8000
-
-# Run application
-CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
-```
-
-### Docker Compose Service Definition
-
-```yaml
-services:
- apphub:
- build: ./apphub
- container_name: websoft9-apphub
- restart: unless-stopped
- environment:
- - DATABASE_URL=${DATABASE_URL}
- - API_KEY=${API_KEY}
- volumes:
- - apphub-data:/app/data
- networks:
- - websoft9
- depends_on:
- - proxy
-```
-
-### Container Communication
-
-All Websoft9 services communicate via the `websoft9` Docker network:
-
-```python
-# Accessing other services from AppHub
-GITEA_URL = "http://websoft9-gitea:3000"
-PORTAINER_URL = "http://websoft9-portainer:9000"
-PROXY_URL = "http://websoft9-proxy:80"
-```
-
-## Security Best Practices
-
-### 1. Never Hardcode Secrets
-
-```python
-# ❌ BAD
-API_KEY = "hardcoded-secret-key"
-
-# ✅ GOOD
-import os
-API_KEY = os.getenv("API_KEY")
-if not API_KEY:
- raise ValueError("API_KEY environment variable not set")
-```
-
-### 2. Input Validation
-
-```python
-from pydantic import BaseModel, validator, Field
-
-class AppConfig(BaseModel):
- name: str = Field(..., min_length=3, max_length=50)
- port: int = Field(..., ge=1024, le=65535)
-
- @validator('name')
- def validate_name(cls, v):
- if not v.replace('-', '').replace('_', '').isalnum():
- raise ValueError('Name must be alphanumeric')
- return v
-```
-
-### 3. Authentication & Authorization
-
-```python
-from fastapi import Depends, Header, HTTPException
-
-async def verify_api_key(x_api_key: str = Header(...)) -> str:
- """Verify API key from request header"""
- stored_key = os.getenv("API_KEY")
- if x_api_key != stored_key:
- raise HTTPException(
- status_code=401,
- detail="Invalid API key"
- )
- return x_api_key
-
-@router.get("/protected")
-async def protected_route(api_key: str = Depends(verify_api_key)):
- return {"message": "Access granted"}
-```
-
-### 4. CORS Configuration
-
-```python
-from fastapi.middleware.cors import CORSMiddleware
-
-app.add_middleware(
- CORSMiddleware,
- allow_origins=["https://yourdomain.com"], # Specific origins only
- allow_credentials=True,
- allow_methods=["GET", "POST", "PUT", "DELETE"],
- allow_headers=["*"],
-)
-```
-
-## Working with External Services
-
-### Gitea Integration
-
-```python
-import httpx
-
-class GiteaClient:
- def __init__(self, base_url: str, token: str):
- self.base_url = base_url
- self.headers = {"Authorization": f"token {token}"}
-
- async def create_repository(self, name: str, private: bool = False):
- async with httpx.AsyncClient() as client:
- response = await client.post(
- f"{self.base_url}/api/v1/user/repos",
- headers=self.headers,
- json={"name": name, "private": private}
- )
- response.raise_for_status()
- return response.json()
-```
-
-### Portainer Integration
-
-```python
-class PortainerClient:
- def __init__(self, base_url: str, api_key: str):
- self.base_url = base_url
- self.headers = {"X-API-Key": api_key}
-
- async def list_containers(self, endpoint_id: int = 1):
- async with httpx.AsyncClient() as client:
- response = await client.get(
- f"{self.base_url}/api/endpoints/{endpoint_id}/docker/containers/json",
- headers=self.headers
- )
- return response.json()
-```
-
-## Common Development Tasks
-
-### Starting Development Environment
-
-```bash
-# Clone repository
-git clone https://github.com/websoft9/websoft9.git
-cd websoft9
-
-# Start all services
-docker-compose -f docker/docker-compose.yml up -d
-
-# View logs
-docker-compose -f docker/docker-compose.yml logs -f apphub
-
-# Stop services
-docker-compose -f docker/docker-compose.yml down
-```
-
-### Local AppHub Development
-
-```bash
-# Navigate to apphub
-cd apphub
-
-# Create virtual environment
-python3 -m venv venv
-source venv/bin/activate # On Windows: venv\Scripts\activate
-
-# Install dependencies
-pip install -r requirements.txt
-pip install -r requirements-dev.txt # Development dependencies
-
-# Run locally
-cd src
-uvicorn main:app --reload --host 0.0.0.0 --port 8000
-
-# Access API docs
-# http://localhost:8000/docs (Swagger UI)
-# http://localhost:8000/redoc (ReDoc)
-```
-
-### Debugging
-
-```python
-# Add breakpoint in code
-import pdb; pdb.set_trace()
-
-# Or use ipdb for better experience
-import ipdb; ipdb.set_trace()
-
-# Use logging for production debugging
-logger.debug(f"Variable value: {variable}")
-```
-
-## AI-Assisted Development Tips
-
-### Effective Prompts for GitHub Copilot
-
-1. **Be Specific with Context**
- ```python
- # Create a FastAPI endpoint for Websoft9 AppHub that retrieves application status
- # Should check Docker container status and return JSON response
- # Include error handling for container not found
- ```
-
-2. **Provide Type Hints**
- ```python
- async def get_app_status(app_id: str) -> dict:
- # Copilot will generate better code with type hints
- ```
-
-3. **Use Descriptive Function Names**
- ```python
- # Good: Copilot understands intent
- async def deploy_application_to_docker_container(config: DeploymentConfig):
-
- # Less effective
- async def deploy(c):
- ```
-
-### Code Generation Examples
-
-When asking Copilot to generate code:
-
-```python
-# Prompt: "Create an async function to backup Websoft9 application data"
-# Expected pattern:
-
-async def backup_application_data(
- app_id: str,
- backup_path: str,
- include_logs: bool = True
-) -> dict:
- """
- Backup application data to specified path
-
- Args:
- app_id: Application identifier
- backup_path: Destination path for backup
- include_logs: Whether to include log files
-
- Returns:
- dict: Backup metadata including path, size, timestamp
- """
- # Implementation...
-```
-
-## Performance Optimization
-
-### Async Operations
-
-```python
-import asyncio
-
-# ✅ GOOD: Concurrent operations
-async def fetch_all_data():
- results = await asyncio.gather(
- fetch_apps(),
- fetch_containers(),
- fetch_repositories()
- )
- return results
-
-# ❌ BAD: Sequential operations
-async def fetch_all_data():
- apps = await fetch_apps()
- containers = await fetch_containers()
- repos = await fetch_repositories()
- return [apps, containers, repos]
-```
-
-### Database Queries
-
-```python
-# Use connection pooling
-from databases import Database
-
-database = Database(DATABASE_URL, min_size=5, max_size=20)
-
-# Batch operations when possible
-async def get_multiple_apps(app_ids: list[str]):
- query = "SELECT * FROM apps WHERE id = ANY(:ids)"
- return await database.fetch_all(query=query, values={"ids": app_ids})
-```
-
-### Caching
-
-```python
-from functools import lru_cache
-from datetime import datetime, timedelta
-
-# Simple in-memory cache
-_cache = {}
-
-async def get_system_info(force_refresh: bool = False):
- cache_key = "system_info"
-
- if not force_refresh and cache_key in _cache:
- cached_data, timestamp = _cache[cache_key]
- if datetime.now() - timestamp < timedelta(minutes=5):
- return cached_data
-
- # Fetch fresh data
- data = await fetch_system_info()
- _cache[cache_key] = (data, datetime.now())
- return data
-```
-
-## Commit & PR Guidelines
-
-### Commit Message Format
-
-Follow Conventional Commits:
-
-```
-():
-
-
-
-