# PRD: GitOps Tool with Argo CD Support
**Issue**: [#264](https://github.com/vfarcic/dot-ai/issues/264)
**Status**: Draft
**Priority**: High
**Created**: 2025-12-10
---
## Problem Statement
Users working with GitOps workflows need to generate Argo CD Application CRs for their Kubernetes manifests. Currently:
1. **No Standalone GitOps Tool**: Users must manually create Argo CD Applications for existing packages
2. **No Project Detection**: Tools don't analyze the project to find existing Helm charts, Kustomize overlays, or manifest directories
3. **Manual Process**: Creating Application CRs requires knowing the exact schema and options
4. **Disconnected from AI Assistance**: No AI-powered guidance for GitOps configuration
This PRD introduces a new `gitops` MCP tool that operates in **standalone mode** - working with any existing manifests, not just those generated by the `recommend` tool.
---
## Solution Overview
Create a new `gitops` MCP tool that:
1. **Analyzes the Project**: Scans the working directory to detect package types (Helm, Kustomize, raw manifests)
2. **Confirms with User**: "Is this the package? [detected path]" or asks for path if not detected
3. **Selects GitOps Provider**: Ask which GitOps tool to use (Argo CD now, Flux in #265)
4. **Collects GitOps Configuration**: Repository URL, sync policy, namespaces, etc.
5. **Generates GitOps Resources**: Provider-specific manifests (Argo CD Application, Flux HelmRelease, etc.)
### Key Design Principles
- **Standalone First**: Works independently with any existing packages
- **Smart Detection**: Analyzes project structure to find packages automatically
- **User Confirmation**: Always confirms detected paths before proceeding
- **Pluggable Providers**: Architecture designed for multiple GitOps tools (Argo CD, Flux, future tools)
- **Shared Infrastructure**: Detection, session management, and question framework are reusable across providers
---
## User Journeys
### Journey 1: Auto-Detected Helm Chart
```
User: [invokes gitops tool with intent "deploy my app"]
→ Tool scans project, finds ./charts/my-app/Chart.yaml
→ "I found a Helm chart at ./charts/my-app/. Is this the package you want to deploy?"
→ User confirms: Yes
→ "Which GitOps tool would you like to use?"
- Argo CD (only option in this PRD)
→ Additional questions:
- Git repository URL? (e.g., https://github.com/org/repo.git)
- Path within repository? (default: charts/my-app)
- Target namespace for deployment?
- Argo CD Application namespace? (default: argocd)
- Sync policy? (Manual / Automatic / Automatic with Pruning)
→ Tool generates Argo CD Application CR
→ "Where should I save the Application manifest?" (default: ./argocd-application.yaml)
```
### Journey 2: Auto-Detected Kustomize
```
User: [invokes gitops tool]
→ Tool scans project, finds ./deploy/kustomization.yaml
→ "I found a Kustomize overlay at ./deploy/. Is this the package you want to deploy?"
→ User confirms: Yes
→ Tool collects GitOps configuration
→ Generates Application CR with Kustomize source type
```
### Journey 3: Multiple Packages Detected
```
User: [invokes gitops tool]
→ Tool scans project, finds:
- ./charts/frontend/Chart.yaml
- ./charts/backend/Chart.yaml
- ./deploy/kustomization.yaml
→ "I found multiple packages. Which one would you like to deploy?"
Option 1: ./charts/frontend (Helm)
Option 2: ./charts/backend (Helm)
Option 3: ./deploy (Kustomize)
Option 4: Specify a different path
→ User selects option
→ Continues with GitOps configuration
```
### Journey 4: No Package Detected
```
User: [invokes gitops tool]
→ Tool scans project, finds no recognizable packages
→ "I couldn't detect a Helm chart, Kustomize overlay, or manifest directory.
Where is your package located?"
→ User provides path: ./kubernetes/
→ Tool analyzes the path:
- If contains Chart.yaml → Helm
- If contains kustomization.yaml → Kustomize
- If contains .yaml/.yml files → Raw manifests
→ Continues with GitOps configuration
```
### Journey 5: Raw Manifests Directory
```
User: [invokes gitops tool]
→ Tool detects ./manifests/ directory with .yaml files (no Chart.yaml or kustomization.yaml)
→ "I found raw Kubernetes manifests at ./manifests/. Is this what you want to deploy?"
→ User confirms
→ Tool generates Application CR with directory source type
```
---
## Technical Design
### Tool Interface
```typescript
// New MCP tool: gitops
interface GitOpsToolParams {
// Stage control
stage?: 'detect' | 'selectPackage' | 'selectProvider' | 'configure' | 'generate';
// Session management
sessionId?: string;
// User inputs
packagePath?: string; // Manual path override
selectedPackage?: number; // Index when multiple packages found
provider?: 'argocd' | 'flux'; // GitOps provider selection
answers?: Record<string, any>; // Answers to configuration questions
}
```
### Workflow Stages
```
[detect] → [selectPackage] → [selectProvider] → [configure] → [generate]
↓ ↓ ↓ ↓ ↓
Scan for Confirm/select Argo CD or Provider- Output
packages package path Flux specific manifests
questions
```
### Shared Infrastructure (Reusable by Flux and Future Providers)
The following components are designed to be **provider-agnostic** and reusable:
1. **Package Detection** (`detection.ts`): Scans for Helm, Kustomize, raw manifests
2. **Session Management** (`session.ts`): Tracks workflow state across stages
3. **Question Framework** (`questions.ts`): Handles user prompts, validation, defaults
4. **Output Handling**: File writing, YAML formatting, multi-document output
Only the **generator** and **provider-specific questions** vary by provider.
### Package Detection Logic
```typescript
interface DetectedPackage {
path: string;
type: 'helm' | 'kustomize' | 'raw-manifests';
name: string; // Derived from Chart.yaml name or directory
confidence: 'high' | 'medium' | 'low';
}
async function detectPackages(workingDir: string): Promise<DetectedPackage[]> {
const packages: DetectedPackage[] = [];
// 1. Find Helm charts (Chart.yaml)
const helmCharts = await glob('**/Chart.yaml', { cwd: workingDir });
for (const chartPath of helmCharts) {
const chartDir = path.dirname(chartPath);
const chartYaml = await readYaml(path.join(workingDir, chartPath));
packages.push({
path: chartDir,
type: 'helm',
name: chartYaml.name || path.basename(chartDir),
confidence: 'high'
});
}
// 2. Find Kustomize overlays (kustomization.yaml)
const kustomizations = await glob('**/kustomization.yaml', { cwd: workingDir });
for (const kustomizePath of kustomizations) {
const kustomizeDir = path.dirname(kustomizePath);
packages.push({
path: kustomizeDir,
type: 'kustomize',
name: path.basename(kustomizeDir),
confidence: 'high'
});
}
// 3. Find raw manifest directories (directories with .yaml files)
const manifestDirs = await findManifestDirectories(workingDir);
for (const dir of manifestDirs) {
// Only add if not already detected as Helm or Kustomize
if (!packages.some(p => p.path === dir)) {
packages.push({
path: dir,
type: 'raw-manifests',
name: path.basename(dir),
confidence: 'medium'
});
}
}
return packages;
}
```
### Provider Selection
After package confirmation, the user selects their GitOps provider:
```typescript
const providerQuestion = {
id: 'gitopsProvider',
question: 'Which GitOps tool would you like to use?',
type: 'select',
options: [
{ value: 'argocd', label: 'Argo CD', description: 'Generate Argo CD Application' },
{ value: 'flux', label: 'Flux', description: 'Generate Flux GitRepository + HelmRelease/Kustomization' }
],
default: 'argocd'
};
```
**Note**: Flux option will show "coming soon" until PRD #265 is implemented.
### Configuration Questions
Questions are split into **shared** (common to all providers) and **provider-specific**:
#### Shared Questions (Used by All Providers)
```typescript
const sharedQuestions = [
{
id: 'gitRepoUrl',
question: 'Git repository URL where the package is stored?',
type: 'text',
required: true,
placeholder: 'https://github.com/org/repo.git'
},
{
id: 'gitRepoPath',
question: 'Path within the repository?',
type: 'text',
default: '<detected-package-path>',
required: true
},
{
id: 'targetRevision',
question: 'Git branch or tag to track?',
type: 'text',
default: 'HEAD'
},
{
id: 'destinationNamespace',
question: 'Target namespace for deployment?',
type: 'text',
required: true,
placeholder: 'default'
},
{
id: 'outputPath',
question: 'Where to save the GitOps manifest?',
type: 'text',
default: './<provider>-application.yaml' // e.g., ./argocd-application.yaml
}
];
```
#### Argo CD-Specific Questions
```typescript
const argocdQuestions = [
{
id: 'applicationNamespace',
question: 'Namespace for the Argo CD Application CR?',
type: 'text',
default: 'argocd'
},
{
id: 'project',
question: 'Argo CD project?',
type: 'text',
default: 'default'
},
{
id: 'syncPolicy',
question: 'Sync policy?',
type: 'select',
options: [
{ value: 'manual', label: 'Manual', description: 'Sync only when triggered' },
{ value: 'auto', label: 'Automatic', description: 'Sync automatically on changes' },
{ value: 'auto-prune', label: 'Automatic with Pruning', description: 'Auto-sync and remove orphaned resources' }
],
default: 'manual'
}
];
```
### Application CR Generation
#### Helm Chart Source
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: <package-name>
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
path: charts/my-app
targetRevision: HEAD
helm:
valueFiles:
- values.yaml
destination:
server: https://kubernetes.default.svc
namespace: my-app
syncPolicy:
automated:
prune: true
selfHeal: true
```
#### Kustomize Source
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: <package-name>
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
path: deploy/overlays/production
targetRevision: HEAD
destination:
server: https://kubernetes.default.svc
namespace: my-app
syncPolicy:
automated:
prune: true
selfHeal: true
```
#### Raw Manifests (Directory)
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: <package-name>
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
path: manifests
targetRevision: HEAD
directory:
recurse: true
destination:
server: https://kubernetes.default.svc
namespace: my-app
syncPolicy:
automated:
prune: true
selfHeal: true
```
### Pluggable Generator Interface
The generator interface allows adding new providers without modifying core logic:
```typescript
// src/core/gitops/types.ts
interface DetectedPackage {
path: string;
type: 'helm' | 'kustomize' | 'raw-manifests';
name: string;
confidence: 'high' | 'medium' | 'low';
}
interface GitOpsConfig {
// From detection
package: DetectedPackage;
// From shared questions
gitRepoUrl: string;
gitRepoPath: string;
targetRevision: string;
destinationNamespace: string;
outputPath: string;
// Provider-specific (passed through)
providerConfig: Record<string, any>;
}
interface GitOpsGenerator {
/** Provider identifier */
readonly providerId: string;
/** Human-readable name */
readonly providerName: string;
/** Provider-specific questions (added to shared questions) */
getQuestions(): Question[];
/** Generate GitOps manifests */
generate(config: GitOpsConfig): GeneratedOutput;
}
interface GeneratedOutput {
manifests: string; // YAML content (may be multi-document)
filename: string; // Suggested filename
description: string; // Human-readable summary
}
// Registry for providers
const providers: Map<string, GitOpsGenerator> = new Map();
function registerProvider(generator: GitOpsGenerator) {
providers.set(generator.providerId, generator);
}
// Argo CD provider registered by default
registerProvider(new ArgoCDGenerator());
// Flux provider will be registered by PRD #265
// registerProvider(new FluxGenerator());
```
### File Structure
```
src/
├── tools/
│ └── gitops/
│ ├── index.ts # Tool entry point
│ ├── detection.ts # Package detection logic (SHARED)
│ ├── questions.ts # Question framework (SHARED)
│ ├── session.ts # Session management (SHARED)
│ └── generators/
│ ├── index.ts # Generator registry (SHARED)
│ ├── types.ts # Generator interface (SHARED)
│ ├── argocd.ts # Argo CD generator
│ └── flux.ts # Flux generator (PRD #265)
├── core/
│ └── gitops/
│ └── types.ts # Shared types
prompts/
└── gitops/
├── detect-package.md # Detection prompt (SHARED)
├── shared-questions.md # Common questions (SHARED)
└── argocd-questions.md # Argo CD-specific prompts
```
Files marked **(SHARED)** are provider-agnostic and will be reused by Flux (PRD #265).
---
## Success Criteria
### Shared Infrastructure (Reusable)
1. **Package Detection**: Tool correctly detects Helm charts, Kustomize overlays, and raw manifest directories
2. **User Confirmation**: Always confirms detected package before proceeding
3. **Multiple Package Handling**: Presents clear selection when multiple packages found
4. **Manual Override**: Users can specify custom paths when detection fails or is wrong
5. **Provider Selection**: Users can choose GitOps provider (Argo CD now, Flux shows "coming soon")
6. **Pluggable Architecture**: New providers can be added by implementing `GitOpsGenerator` interface
7. **File Output**: Saves manifest to user-specified path
### Argo CD-Specific
8. **Valid Application CR**: Generated Application CRs pass `kubectl apply --dry-run=client` validation
9. **All Source Types**: Correctly generates Helm, Kustomize, and directory source configurations
10. **Sync Policies**: Supports manual, auto, and auto-prune sync policies
---
## Out of Scope
1. **Flux Support**: Covered by PRD #265
2. **Recommend Integration**: Covered by PRD #266
3. **Git Push**: Actually pushing generated files to Git
4. **Argo CD Detection**: Auto-detecting if Argo CD is installed
5. **ApplicationSet**: Multi-environment patterns
6. **App of Apps**: Nested Application structures
7. **Private Repos**: Credential configuration for private repositories
8. **Third-Party Helm Repos**: External HelmRepository references (future enhancement)
---
## Dependencies
| Dependency | Relationship |
|------------|--------------|
| PRD #248 | Optional - packages generated by recommend can be used, but not required |
---
## Supersedes
This PRD, along with #265 and #266, supersedes:
- **#254** (Argo CD Integration for Third-Party Helm Charts)
- **#255** (Argo CD Integration for Packaged Recommendations)
- **#256** (Flux Integration for GitOps Deployments)
The new architecture separates concerns:
- **#264** (this): Standalone gitops tool + Argo CD
- **#265**: Adds Flux support to gitops tool
- **#266**: Integrates gitops into recommend workflow
---
## Risks and Mitigations
| Risk | Impact | Mitigation |
|------|--------|------------|
| False positive detection | Wrong package selected | Always confirm with user; allow manual override |
| Complex project structures | Detection misses packages | Support manual path input; improve detection heuristics |
| Invalid Application generated | Deployment fails | Validate against Argo CD schema; include dry-run option |
| Path format differences | Git path doesn't match local | Let user specify exact repository path |
---
## Milestones
### Shared Infrastructure
- [ ] **M1**: Package detection logic (Helm, Kustomize, raw manifests)
- [ ] **M2**: User confirmation flow with multiple package handling
- [ ] **M3**: Provider selection and pluggable generator interface
- [ ] **M4**: Shared question framework and session management
- [ ] **M5**: File output with user-specified path
### Argo CD Provider
- [ ] **M6**: Argo CD-specific questions (namespace, project, sync policy)
- [ ] **M7**: Application CR generation for all source types (Helm, Kustomize, directory)
- [ ] **M8**: Integration tests for detection and Argo CD generation
- [ ] **M9**: Documentation with examples
---
## Progress Log
| Date | Update |
|------|--------|
| 2025-12-10 | PRD created as part of GitOps architecture restructuring |
| 2025-12-10 | Supersedes #254, #255, #256 (with #265 and #266) |