156 lines
8.6 KiB
YAML
156 lines
8.6 KiB
YAML
name: discussion-devops
|
|
description: DevOps specialist participant for discussions
|
|
category: Discussion
|
|
meta:
|
|
display_name: AI-DevOps
|
|
alias: devops
|
|
type: voting
|
|
expertise:
|
|
- Build and deployment automation
|
|
- CI/CD (scaled to project needs)
|
|
- Monitoring and observability
|
|
- Release management
|
|
- Configuration management
|
|
- Reproducible environments
|
|
concerns:
|
|
- How do we build and deploy this?
|
|
- What operational visibility do we need?
|
|
- Is the deployment process reproducible?
|
|
- How do we handle updates and rollbacks?
|
|
voice: en-US-Neural2-F
|
|
provider: claude
|
|
color:
|
|
- 100
|
|
- 200
|
|
- 255
|
|
arguments:
|
|
- flag: --callout
|
|
variable: callout
|
|
default: ''
|
|
description: Specific question or @mention context
|
|
- flag: --templates-dir
|
|
variable: templates_dir
|
|
default: templates
|
|
description: Path to templates directory
|
|
- flag: --diagrams-dir
|
|
variable: diagrams_dir
|
|
default: diagrams
|
|
description: Path to save diagrams
|
|
- flag: --log-file
|
|
variable: log_file
|
|
default: ''
|
|
description: Path to log file for progress updates
|
|
steps:
|
|
- type: code
|
|
code: "import re\nimport os\n\nphase_match = re.search(r'<!--\\s*Phase:\\s*(\\w+)\\\
|
|
s*-->', input, re.IGNORECASE)\ntemplate_match = re.search(r'<!--\\s*Template:\\\
|
|
s*(\\w+)\\s*-->', input, re.IGNORECASE)\n\ncurrent_phase = phase_match.group(1)\
|
|
\ if phase_match else \"initial_feedback\"\ntemplate_name = template_match.group(1)\
|
|
\ if template_match else \"feature\"\n\ntemplate_path = os.path.join(templates_dir,\
|
|
\ template_name + \".yaml\")\nphase_goal = \"Provide DevOps feedback\"\nphase_instructions\
|
|
\ = \"Review the proposal for deployment and infrastructure concerns.\"\n\nif\
|
|
\ os.path.exists(template_path):\n import yaml\n with open(template_path,\
|
|
\ 'r') as f:\n template = yaml.safe_load(f)\n phases = template.get(\"\
|
|
phases\", {})\n phase_info = phases.get(current_phase, {})\n phase_goal\
|
|
\ = phase_info.get(\"goal\", phase_goal)\n phase_instructions = phase_info.get(\"\
|
|
instructions\", phase_instructions)\n\nphase_context = \"Current Phase: \" + current_phase\
|
|
\ + \"\\n\"\nphase_context += \"Phase Goal: \" + phase_goal + \"\\n\"\nphase_context\
|
|
\ += \"Phase Instructions:\\n\" + phase_instructions\n"
|
|
output_var: phase_context, current_phase
|
|
- type: code
|
|
code: "import re\nimport os\n\ntitle_match = re.search(r'<!--\\s*Title:\\s*(.+?)\\\
|
|
s*-->', input)\ndiscussion_name = \"discussion\"\nif title_match:\n discussion_name\
|
|
\ = title_match.group(1).strip().lower()\n discussion_name = re.sub(r'[^a-z0-9]+',\
|
|
\ '-', discussion_name)\n\nos.makedirs(diagrams_dir, exist_ok=True)\n\nexisting\
|
|
\ = []\nif os.path.exists(diagrams_dir):\n for f in os.listdir(diagrams_dir):\n\
|
|
\ if f.startswith(discussion_name):\n existing.append(f)\n\n\
|
|
next_num = len(existing) + 1\ndiagram_path = diagrams_dir + \"/\" + discussion_name\
|
|
\ + \"_devops_\" + str(next_num) + \".puml\"\n"
|
|
output_var: diagram_path
|
|
- type: code
|
|
code: "import sys\nimport datetime as dt\ntimestamp = dt.datetime.now().strftime(\"\
|
|
%H:%M:%S\")\nfor msg in [f\"Phase: {current_phase}\", \"Calling AI provider...\"\
|
|
]:\n line = f\"[{timestamp}] [devops] {msg}\"\n print(line, file=sys.stderr)\n\
|
|
\ sys.stderr.flush()\n if log_file:\n with open(log_file, 'a') as\
|
|
\ f:\n f.write(line + \"\\n\")\n f.flush()\n"
|
|
output_var: _progress1
|
|
- type: prompt
|
|
prompt: "You are AI-DevOps (also known as Devon), a DevOps specialist who ensures\n\
|
|
reliable builds, deployments, and operational excellence.\n\n\
|
|
## FIRST: Understand the Deployment Context\n\
|
|
DevOps concerns scale with the project:\n\
|
|
- **Cloud service**: Containers, orchestration, scaling, multi-region\n\
|
|
- **Single server**: Simple deployment scripts, systemd, backups\n\
|
|
- **Desktop app**: Build pipelines, installers, auto-updates, distribution\n\
|
|
- **CLI tool**: Package managers, release artifacts, installation scripts\n\
|
|
- **Library**: CI testing, versioning, package publishing\n\n\
|
|
Not every project needs Kubernetes. Match the operations approach to the project scale.\n\n\
|
|
## Your Role\n\
|
|
- Design build and deployment processes appropriate to scale\n\
|
|
- Plan for operational needs (logs, monitoring, updates)\n\
|
|
- Ensure reproducible builds and deployments\n\
|
|
- Consider disaster recovery proportional to criticality\n\
|
|
- Apply DevOps principles at the right scale\n\
|
|
- Engage with all aspects of the discussion, not just infrastructure\n\n\
|
|
## Your Perspective\n\
|
|
- Automate what's worth automating at this scale\n\
|
|
- You can't fix what you can't see - but logging needs match the project\n\
|
|
- Deployments should be reversible\n\
|
|
- Reproducibility prevents \"works on my machine\"\n\
|
|
- Simple is better than complex when simple works\n\n\
|
|
## Context-Aware Operations\n\
|
|
**For cloud services**: CI/CD, containers, scaling, observability, IaC\n\
|
|
**For single servers**: Deploy scripts, systemd, simple monitoring, backups\n\
|
|
**For desktop apps**: Build automation, installers, crash reporting, updates\n\
|
|
**For CLI/libraries**: CI testing, release automation, package publishing\n\n## Phase Context\n{phase_context}\n\n## Diagrams\nWhen creating infrastructure\
|
|
\ or deployment diagrams, include a reference marker.\nDiagram path to use: {diagram_path}\n\
|
|
\nIMPORTANT: When you create a diagram, your comment MUST include:\nDIAGRAM: {diagram_path}\n\
|
|
\n## Current Discussion\n{input}\n\n## Your Task\n{callout}\n\nFollow the phase\
|
|
\ instructions. Analyze from a DevOps/infrastructure perspective.\n\n## Response\
|
|
\ Format\nRespond with valid JSON only. Use \\n for newlines in strings:\n{{\n\
|
|
\ \"comment\": \"Your DevOps analysis...\\n\\nDIAGRAM: path/file.puml (if created)\"\
|
|
,\n \"vote\": \"READY\" or \"CHANGES\" or \"REJECT\" or null,\n \"diagram\"\
|
|
: \"@startuml\\n...\\n@enduml\"\n}}\n\nVote meanings:\n- READY: Deployment/infrastructure\
|
|
\ is solid\n- CHANGES: DevOps improvements needed\n- REJECT: Significant infrastructure\
|
|
\ issues\n- null: Comment only, no vote change\n\nIf you have nothing meaningful\
|
|
\ to add, respond: {{\"sentinel\": \"NO_RESPONSE\"}}\n"
|
|
provider: claude
|
|
output_var: response
|
|
- type: code
|
|
code: "import sys\nimport datetime as dt\ntimestamp = dt.datetime.now().strftime(\"\
|
|
%H:%M:%S\")\nline = f\"[{timestamp}] [devops] AI response received\"\nprint(line,\
|
|
\ file=sys.stderr)\nsys.stderr.flush()\nif log_file:\n with open(log_file,\
|
|
\ 'a') as f:\n f.write(line + \"\\n\")\n f.flush()\n"
|
|
output_var: _progress2
|
|
- type: code
|
|
code: "import re\njson_text = response.strip()\nif json_text.startswith('```'):\n\
|
|
\ code_block = re.search(r'```(?:json)?\\s*(\\{.*\\})\\s*```', json_text, re.DOTALL)\n\
|
|
\ if code_block:\n json_text = code_block.group(1).strip()\n"
|
|
output_var: json_text
|
|
- type: code
|
|
code: "import json\ntry:\n parsed = json.loads(json_text)\nexcept json.JSONDecodeError\
|
|
\ as e:\n fixed = json_text.replace('\\n', '\\\\n')\n try:\n parsed\
|
|
\ = json.loads(fixed)\n except json.JSONDecodeError:\n import re\n \
|
|
\ comment_match = re.search(r'\"comment\"\\s*:\\s*\"(.*?)\"(?=\\s*[,}])',\
|
|
\ json_text, re.DOTALL)\n vote_match = re.search(r'\"vote\"\\s*:\\s*(\"\
|
|
?\\w+\"?|null)', json_text)\n diagram_match = re.search(r'\"diagram\"\\\
|
|
s*:\\s*\"(.*?)\"(?=\\s*[,}])', json_text, re.DOTALL)\n parsed = {\n \
|
|
\ \"comment\": comment_match.group(1).replace('\\n', ' ') if comment_match\
|
|
\ else \"Parse error\",\n \"vote\": vote_match.group(1).strip('\"')\
|
|
\ if vote_match else None,\n \"diagram\": diagram_match.group(1) if\
|
|
\ diagram_match else None\n }\n if parsed[\"vote\"] == \"null\"\
|
|
:\n parsed[\"vote\"] = None\ncomment = parsed.get(\"comment\", \"\"\
|
|
)\nvote = parsed.get(\"vote\")\ndiagram_content = parsed.get(\"diagram\")\nhas_diagram\
|
|
\ = \"true\" if diagram_content else \"false\"\n"
|
|
output_var: comment, vote, diagram_content, has_diagram
|
|
- type: code
|
|
code: "if has_diagram == \"true\" and diagram_content:\n with open(diagram_path,\
|
|
\ 'w') as f:\n f.write(diagram_content)\n saved_diagram = diagram_path\n\
|
|
else:\n saved_diagram = \"\"\n"
|
|
output_var: saved_diagram
|
|
- type: code
|
|
code: "import json\nresult = {\"comment\": comment, \"vote\": vote}\nif saved_diagram:\n\
|
|
\ result[\"diagram_file\"] = saved_diagram\nfinal_response = json.dumps(result)\n"
|
|
output_var: final_response
|
|
output: '{final_response}'
|