autonomous-qa-agent 1.0.0__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.
@@ -0,0 +1,272 @@
1
+ Metadata-Version: 2.4
2
+ Name: autonomous-qa-agent
3
+ Version: 1.0.0
4
+ Summary: Autonomous QA Agent — scan, test, and fix any codebase automatically
5
+ License: MIT
6
+ Keywords: qa,testing,autonomous,ai,code-quality
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: click>=8.1
10
+ Requires-Dist: httpx>=0.28
11
+ Requires-Dist: websockets>=12.0
12
+ Requires-Dist: rich>=13.0
13
+
14
+ # QA Agent — Complete Client Guide
15
+
16
+ ## What This Does
17
+
18
+ QA Agent autonomously scans your entire codebase, writes test cases for every function, runs them, finds bugs, explains them clearly, and fixes them automatically — then asks for your approval before committing anything.
19
+
20
+ **Supports:** Python, Kotlin, Java, Vert.x, JavaScript, TypeScript, Go, Rust, React, Vue, ML/AI models, and more.
21
+
22
+ ---
23
+
24
+ ## Prerequisites (Client Machine)
25
+
26
+ | Requirement | Version | How to install |
27
+ |-------------|---------|----------------|
28
+ | Docker Desktop | 24+ | https://docker.com/products/docker-desktop |
29
+ | Python | 3.10+ | https://python.org |
30
+ | 16GB RAM | — | For running LLM models locally |
31
+ | 20GB disk | — | For Docker images + LLM models |
32
+
33
+ > **Privacy guarantee:** Your code NEVER leaves your machine. The LLM runs locally via Ollama.
34
+
35
+ ---
36
+
37
+ ## Install (One Command)
38
+
39
+ ```bash
40
+ # Mac / Linux / Windows WSL:
41
+ curl -fsSL https://install.qa-agent.dev | bash
42
+
43
+ # Windows (PowerShell):
44
+ irm https://install.qa-agent.dev/windows | iex
45
+ ```
46
+
47
+ This automatically:
48
+ 1. Checks Docker is running
49
+ 2. Starts all 7 AI services in Docker
50
+ 3. Downloads LLM models (qwen2.5-coder — private, runs locally)
51
+ 4. Installs the `qa-agent` CLI
52
+ 5. Runs a health check
53
+
54
+ ---
55
+
56
+ ## First Scan
57
+
58
+ ```bash
59
+ # Go to your project directory
60
+ cd /path/to/your/codebase
61
+
62
+ # Run full autonomous scan
63
+ qa-agent scan .
64
+ ```
65
+
66
+ **What you'll see:**
67
+ ```
68
+ QA Agent — Autonomous scan
69
+ Repo: /path/to/your/codebase
70
+ Languages: all
71
+ Mode: exhaustive
72
+
73
+ [scanning] Found 1,247 source files
74
+ [indexing] Indexed 3,891 functions
75
+ [generating] Generated 3,891 test files (parallel, 4 workers)
76
+ [running] 2,847/3,891 tests passing
77
+ [healing] Self-healed 891 wrong assertion values
78
+ [fixing] Analysing 153 real failures...
79
+
80
+ ┌─────────────────────────────────────────────┐
81
+ │ Bug Fix Proposal │
82
+ │ File: src/payment/calculator.kt │
83
+ │ Confidence: 94% │
84
+ │ │
85
+ │ Root cause: Tax rate multiplied instead │
86
+ │ of applied as percentage │
87
+ │ │
88
+ │ Diff: │
89
+ │ - return amount * taxRate │
90
+ │ + return amount * (taxRate / 100.0) │
91
+ └─────────────────────────────────────────────┘
92
+ Approve this patch? [y/N]: y
93
+
94
+ [PASS] Patch committed and verified.
95
+
96
+ ╔══════════════════════════════════════════════╗
97
+ ║ QA Agent — Scan Report ║
98
+ ║ Status: PASS ║
99
+ ║ Files scanned: 1,247 ║
100
+ ║ Functions tested: 3,891 ║
101
+ ║ Tests passed: 3,891 / 3,891 (100%) ║
102
+ ║ Bugs found: 153 ║
103
+ ║ Bugs fixed: 153 / 153 ║
104
+ ║ Time: 14m 32s ║
105
+ ║ YOUR CODEBASE IS GREEN ║
106
+ ╚══════════════════════════════════════════════╝
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Common Commands
112
+
113
+ ```bash
114
+ # Full scan (all files, all languages)
115
+ qa-agent scan .
116
+
117
+ # Only scan files changed since last commit (fast re-scan)
118
+ qa-agent scan . --changed-only
119
+
120
+ # Scan specific languages only
121
+ qa-agent scan . --lang python,kotlin,java
122
+
123
+ # CI/CD mode — auto-approve patches (no prompts)
124
+ qa-agent scan . --auto-approve
125
+
126
+ # Check system health
127
+ qa-agent doctor
128
+
129
+ # Check status of a running scan
130
+ qa-agent status <job-id>
131
+
132
+ # Approve/reject a pending patch
133
+ qa-agent approve <job-id> <patch-id>
134
+ qa-agent approve <job-id> <patch-id> --reject
135
+ ```
136
+
137
+ ---
138
+
139
+ ## CI/CD Integration
140
+
141
+ ### GitHub Actions
142
+ ```yaml
143
+ name: QA Agent Scan
144
+ on: [push, pull_request]
145
+ jobs:
146
+ qa-scan:
147
+ runs-on: self-hosted # needs Docker + qa-agent installed
148
+ steps:
149
+ - uses: actions/checkout@v4
150
+ - name: Run QA Agent
151
+ run: qa-agent scan . --auto-approve --output json > qa-report.json
152
+ - name: Upload Report
153
+ uses: actions/upload-artifact@v4
154
+ with:
155
+ name: qa-report
156
+ path: qa-report.json
157
+ ```
158
+
159
+ ### GitLab CI
160
+ ```yaml
161
+ qa-scan:
162
+ stage: test
163
+ tags: [docker]
164
+ script:
165
+ - qa-agent scan . --auto-approve
166
+ artifacts:
167
+ paths: [qa-report.json]
168
+ ```
169
+
170
+ ---
171
+
172
+ ## Configuration
173
+
174
+ Create `.qa-agent.env` in your repo root:
175
+
176
+ ```env
177
+ # LLM Provider: ollama (local) | openai | anthropic
178
+ LLM_PROVIDER=ollama
179
+
180
+ # For cloud LLMs (faster, requires API key)
181
+ # LLM_PROVIDER=openai
182
+ # OPENAI_API_KEY=sk-...
183
+
184
+ # Models
185
+ TEST_GEN_MODEL=qwen2.5-coder:1.5b # fast, for test generation
186
+ PATCH_MODEL=qwen2.5-coder:7b # accurate, for bug fixing
187
+
188
+ # Scan behaviour
189
+ MAX_CHUNKS=1000 # max functions to generate tests for
190
+ MAX_FIX_ATTEMPTS=3 # LLM retry limit per bug
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Supported Languages
196
+
197
+ | Language | Test Framework | Status |
198
+ |----------|---------------|--------|
199
+ | Python | pytest | ✅ |
200
+ | Kotlin | JUnit 5 + Maven | ✅ |
201
+ | Java | JUnit 5 + Maven | ✅ |
202
+ | Vert.x (Java/Kotlin) | JUnit 5 | ✅ |
203
+ | JavaScript | Jest | ✅ |
204
+ | TypeScript | Jest | ✅ |
205
+ | Go | go test | ✅ |
206
+ | Rust | cargo test | ✅ |
207
+ | React/Vue/Svelte | Jest + Testing Library | ✅ |
208
+ | ML (PyTorch/TF) | pytest | ✅ |
209
+
210
+ ---
211
+
212
+ ## How It Works (Under the Hood)
213
+
214
+ ```
215
+ Your codebase
216
+
217
+
218
+ qa-agent scan .
219
+
220
+ [Brain — LangGraph AI]
221
+
222
+ ├── Scan: finds all source files (git-aware, skips unchanged)
223
+ ├── Index: tree-sitter AST → function-level chunks → Qdrant
224
+ ├── Generate: LLM writes positive + negative + edge-case tests
225
+ ├── Run: executes tests in isolated Docker sandbox
226
+ ├── Heal: fixes wrong assertion values automatically
227
+ ├── Fix: LLM analyses real bugs → proposes patches → YOU approve
228
+ └── Report: full summary with pass rate, bugs found/fixed
229
+ ```
230
+
231
+ **Key guarantees:**
232
+ - Code stays on your machine (Ollama runs locally)
233
+ - Nothing is committed without your approval
234
+ - Re-scans only process changed files (git diff)
235
+ - Known bug patterns are cached (instant fix second time)
236
+
237
+ ---
238
+
239
+ ## Uninstall
240
+
241
+ ```bash
242
+ # Stop and remove all containers + data
243
+ docker compose -f ~/.qa-agent/docker-compose.yml down -v
244
+
245
+ # Remove CLI
246
+ pip uninstall qa-agent
247
+
248
+ # Remove models (optional, frees ~8GB)
249
+ docker exec qa-ollama ollama rm qwen2.5-coder:7b
250
+ docker exec qa-ollama ollama rm qwen2.5-coder:1.5b
251
+ ```
252
+
253
+ ---
254
+
255
+ ## Troubleshooting
256
+
257
+ ```bash
258
+ # Check all services are running
259
+ qa-agent doctor
260
+
261
+ # View logs
262
+ docker compose logs qa-brain --tail=50
263
+ docker compose logs qa-celery --tail=50
264
+
265
+ # Restart services
266
+ docker compose restart
267
+
268
+ # Common issues:
269
+ # "Ollama not responding" → docker restart qa-ollama
270
+ # "Tests not generating" → check OLLAMA_HOST in qa-app logs
271
+ # "Scan hangs" → qa-agent status <job-id> to check phase
272
+ ```
@@ -0,0 +1,259 @@
1
+ # QA Agent — Complete Client Guide
2
+
3
+ ## What This Does
4
+
5
+ QA Agent autonomously scans your entire codebase, writes test cases for every function, runs them, finds bugs, explains them clearly, and fixes them automatically — then asks for your approval before committing anything.
6
+
7
+ **Supports:** Python, Kotlin, Java, Vert.x, JavaScript, TypeScript, Go, Rust, React, Vue, ML/AI models, and more.
8
+
9
+ ---
10
+
11
+ ## Prerequisites (Client Machine)
12
+
13
+ | Requirement | Version | How to install |
14
+ |-------------|---------|----------------|
15
+ | Docker Desktop | 24+ | https://docker.com/products/docker-desktop |
16
+ | Python | 3.10+ | https://python.org |
17
+ | 16GB RAM | — | For running LLM models locally |
18
+ | 20GB disk | — | For Docker images + LLM models |
19
+
20
+ > **Privacy guarantee:** Your code NEVER leaves your machine. The LLM runs locally via Ollama.
21
+
22
+ ---
23
+
24
+ ## Install (One Command)
25
+
26
+ ```bash
27
+ # Mac / Linux / Windows WSL:
28
+ curl -fsSL https://install.qa-agent.dev | bash
29
+
30
+ # Windows (PowerShell):
31
+ irm https://install.qa-agent.dev/windows | iex
32
+ ```
33
+
34
+ This automatically:
35
+ 1. Checks Docker is running
36
+ 2. Starts all 7 AI services in Docker
37
+ 3. Downloads LLM models (qwen2.5-coder — private, runs locally)
38
+ 4. Installs the `qa-agent` CLI
39
+ 5. Runs a health check
40
+
41
+ ---
42
+
43
+ ## First Scan
44
+
45
+ ```bash
46
+ # Go to your project directory
47
+ cd /path/to/your/codebase
48
+
49
+ # Run full autonomous scan
50
+ qa-agent scan .
51
+ ```
52
+
53
+ **What you'll see:**
54
+ ```
55
+ QA Agent — Autonomous scan
56
+ Repo: /path/to/your/codebase
57
+ Languages: all
58
+ Mode: exhaustive
59
+
60
+ [scanning] Found 1,247 source files
61
+ [indexing] Indexed 3,891 functions
62
+ [generating] Generated 3,891 test files (parallel, 4 workers)
63
+ [running] 2,847/3,891 tests passing
64
+ [healing] Self-healed 891 wrong assertion values
65
+ [fixing] Analysing 153 real failures...
66
+
67
+ ┌─────────────────────────────────────────────┐
68
+ │ Bug Fix Proposal │
69
+ │ File: src/payment/calculator.kt │
70
+ │ Confidence: 94% │
71
+ │ │
72
+ │ Root cause: Tax rate multiplied instead │
73
+ │ of applied as percentage │
74
+ │ │
75
+ │ Diff: │
76
+ │ - return amount * taxRate │
77
+ │ + return amount * (taxRate / 100.0) │
78
+ └─────────────────────────────────────────────┘
79
+ Approve this patch? [y/N]: y
80
+
81
+ [PASS] Patch committed and verified.
82
+
83
+ ╔══════════════════════════════════════════════╗
84
+ ║ QA Agent — Scan Report ║
85
+ ║ Status: PASS ║
86
+ ║ Files scanned: 1,247 ║
87
+ ║ Functions tested: 3,891 ║
88
+ ║ Tests passed: 3,891 / 3,891 (100%) ║
89
+ ║ Bugs found: 153 ║
90
+ ║ Bugs fixed: 153 / 153 ║
91
+ ║ Time: 14m 32s ║
92
+ ║ YOUR CODEBASE IS GREEN ║
93
+ ╚══════════════════════════════════════════════╝
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Common Commands
99
+
100
+ ```bash
101
+ # Full scan (all files, all languages)
102
+ qa-agent scan .
103
+
104
+ # Only scan files changed since last commit (fast re-scan)
105
+ qa-agent scan . --changed-only
106
+
107
+ # Scan specific languages only
108
+ qa-agent scan . --lang python,kotlin,java
109
+
110
+ # CI/CD mode — auto-approve patches (no prompts)
111
+ qa-agent scan . --auto-approve
112
+
113
+ # Check system health
114
+ qa-agent doctor
115
+
116
+ # Check status of a running scan
117
+ qa-agent status <job-id>
118
+
119
+ # Approve/reject a pending patch
120
+ qa-agent approve <job-id> <patch-id>
121
+ qa-agent approve <job-id> <patch-id> --reject
122
+ ```
123
+
124
+ ---
125
+
126
+ ## CI/CD Integration
127
+
128
+ ### GitHub Actions
129
+ ```yaml
130
+ name: QA Agent Scan
131
+ on: [push, pull_request]
132
+ jobs:
133
+ qa-scan:
134
+ runs-on: self-hosted # needs Docker + qa-agent installed
135
+ steps:
136
+ - uses: actions/checkout@v4
137
+ - name: Run QA Agent
138
+ run: qa-agent scan . --auto-approve --output json > qa-report.json
139
+ - name: Upload Report
140
+ uses: actions/upload-artifact@v4
141
+ with:
142
+ name: qa-report
143
+ path: qa-report.json
144
+ ```
145
+
146
+ ### GitLab CI
147
+ ```yaml
148
+ qa-scan:
149
+ stage: test
150
+ tags: [docker]
151
+ script:
152
+ - qa-agent scan . --auto-approve
153
+ artifacts:
154
+ paths: [qa-report.json]
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Configuration
160
+
161
+ Create `.qa-agent.env` in your repo root:
162
+
163
+ ```env
164
+ # LLM Provider: ollama (local) | openai | anthropic
165
+ LLM_PROVIDER=ollama
166
+
167
+ # For cloud LLMs (faster, requires API key)
168
+ # LLM_PROVIDER=openai
169
+ # OPENAI_API_KEY=sk-...
170
+
171
+ # Models
172
+ TEST_GEN_MODEL=qwen2.5-coder:1.5b # fast, for test generation
173
+ PATCH_MODEL=qwen2.5-coder:7b # accurate, for bug fixing
174
+
175
+ # Scan behaviour
176
+ MAX_CHUNKS=1000 # max functions to generate tests for
177
+ MAX_FIX_ATTEMPTS=3 # LLM retry limit per bug
178
+ ```
179
+
180
+ ---
181
+
182
+ ## Supported Languages
183
+
184
+ | Language | Test Framework | Status |
185
+ |----------|---------------|--------|
186
+ | Python | pytest | ✅ |
187
+ | Kotlin | JUnit 5 + Maven | ✅ |
188
+ | Java | JUnit 5 + Maven | ✅ |
189
+ | Vert.x (Java/Kotlin) | JUnit 5 | ✅ |
190
+ | JavaScript | Jest | ✅ |
191
+ | TypeScript | Jest | ✅ |
192
+ | Go | go test | ✅ |
193
+ | Rust | cargo test | ✅ |
194
+ | React/Vue/Svelte | Jest + Testing Library | ✅ |
195
+ | ML (PyTorch/TF) | pytest | ✅ |
196
+
197
+ ---
198
+
199
+ ## How It Works (Under the Hood)
200
+
201
+ ```
202
+ Your codebase
203
+
204
+
205
+ qa-agent scan .
206
+
207
+ [Brain — LangGraph AI]
208
+
209
+ ├── Scan: finds all source files (git-aware, skips unchanged)
210
+ ├── Index: tree-sitter AST → function-level chunks → Qdrant
211
+ ├── Generate: LLM writes positive + negative + edge-case tests
212
+ ├── Run: executes tests in isolated Docker sandbox
213
+ ├── Heal: fixes wrong assertion values automatically
214
+ ├── Fix: LLM analyses real bugs → proposes patches → YOU approve
215
+ └── Report: full summary with pass rate, bugs found/fixed
216
+ ```
217
+
218
+ **Key guarantees:**
219
+ - Code stays on your machine (Ollama runs locally)
220
+ - Nothing is committed without your approval
221
+ - Re-scans only process changed files (git diff)
222
+ - Known bug patterns are cached (instant fix second time)
223
+
224
+ ---
225
+
226
+ ## Uninstall
227
+
228
+ ```bash
229
+ # Stop and remove all containers + data
230
+ docker compose -f ~/.qa-agent/docker-compose.yml down -v
231
+
232
+ # Remove CLI
233
+ pip uninstall qa-agent
234
+
235
+ # Remove models (optional, frees ~8GB)
236
+ docker exec qa-ollama ollama rm qwen2.5-coder:7b
237
+ docker exec qa-ollama ollama rm qwen2.5-coder:1.5b
238
+ ```
239
+
240
+ ---
241
+
242
+ ## Troubleshooting
243
+
244
+ ```bash
245
+ # Check all services are running
246
+ qa-agent doctor
247
+
248
+ # View logs
249
+ docker compose logs qa-brain --tail=50
250
+ docker compose logs qa-celery --tail=50
251
+
252
+ # Restart services
253
+ docker compose restart
254
+
255
+ # Common issues:
256
+ # "Ollama not responding" → docker restart qa-ollama
257
+ # "Tests not generating" → check OLLAMA_HOST in qa-app logs
258
+ # "Scan hangs" → qa-agent status <job-id> to check phase
259
+ ```
@@ -0,0 +1,272 @@
1
+ Metadata-Version: 2.4
2
+ Name: autonomous-qa-agent
3
+ Version: 1.0.0
4
+ Summary: Autonomous QA Agent — scan, test, and fix any codebase automatically
5
+ License: MIT
6
+ Keywords: qa,testing,autonomous,ai,code-quality
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: click>=8.1
10
+ Requires-Dist: httpx>=0.28
11
+ Requires-Dist: websockets>=12.0
12
+ Requires-Dist: rich>=13.0
13
+
14
+ # QA Agent — Complete Client Guide
15
+
16
+ ## What This Does
17
+
18
+ QA Agent autonomously scans your entire codebase, writes test cases for every function, runs them, finds bugs, explains them clearly, and fixes them automatically — then asks for your approval before committing anything.
19
+
20
+ **Supports:** Python, Kotlin, Java, Vert.x, JavaScript, TypeScript, Go, Rust, React, Vue, ML/AI models, and more.
21
+
22
+ ---
23
+
24
+ ## Prerequisites (Client Machine)
25
+
26
+ | Requirement | Version | How to install |
27
+ |-------------|---------|----------------|
28
+ | Docker Desktop | 24+ | https://docker.com/products/docker-desktop |
29
+ | Python | 3.10+ | https://python.org |
30
+ | 16GB RAM | — | For running LLM models locally |
31
+ | 20GB disk | — | For Docker images + LLM models |
32
+
33
+ > **Privacy guarantee:** Your code NEVER leaves your machine. The LLM runs locally via Ollama.
34
+
35
+ ---
36
+
37
+ ## Install (One Command)
38
+
39
+ ```bash
40
+ # Mac / Linux / Windows WSL:
41
+ curl -fsSL https://install.qa-agent.dev | bash
42
+
43
+ # Windows (PowerShell):
44
+ irm https://install.qa-agent.dev/windows | iex
45
+ ```
46
+
47
+ This automatically:
48
+ 1. Checks Docker is running
49
+ 2. Starts all 7 AI services in Docker
50
+ 3. Downloads LLM models (qwen2.5-coder — private, runs locally)
51
+ 4. Installs the `qa-agent` CLI
52
+ 5. Runs a health check
53
+
54
+ ---
55
+
56
+ ## First Scan
57
+
58
+ ```bash
59
+ # Go to your project directory
60
+ cd /path/to/your/codebase
61
+
62
+ # Run full autonomous scan
63
+ qa-agent scan .
64
+ ```
65
+
66
+ **What you'll see:**
67
+ ```
68
+ QA Agent — Autonomous scan
69
+ Repo: /path/to/your/codebase
70
+ Languages: all
71
+ Mode: exhaustive
72
+
73
+ [scanning] Found 1,247 source files
74
+ [indexing] Indexed 3,891 functions
75
+ [generating] Generated 3,891 test files (parallel, 4 workers)
76
+ [running] 2,847/3,891 tests passing
77
+ [healing] Self-healed 891 wrong assertion values
78
+ [fixing] Analysing 153 real failures...
79
+
80
+ ┌─────────────────────────────────────────────┐
81
+ │ Bug Fix Proposal │
82
+ │ File: src/payment/calculator.kt │
83
+ │ Confidence: 94% │
84
+ │ │
85
+ │ Root cause: Tax rate multiplied instead │
86
+ │ of applied as percentage │
87
+ │ │
88
+ │ Diff: │
89
+ │ - return amount * taxRate │
90
+ │ + return amount * (taxRate / 100.0) │
91
+ └─────────────────────────────────────────────┘
92
+ Approve this patch? [y/N]: y
93
+
94
+ [PASS] Patch committed and verified.
95
+
96
+ ╔══════════════════════════════════════════════╗
97
+ ║ QA Agent — Scan Report ║
98
+ ║ Status: PASS ║
99
+ ║ Files scanned: 1,247 ║
100
+ ║ Functions tested: 3,891 ║
101
+ ║ Tests passed: 3,891 / 3,891 (100%) ║
102
+ ║ Bugs found: 153 ║
103
+ ║ Bugs fixed: 153 / 153 ║
104
+ ║ Time: 14m 32s ║
105
+ ║ YOUR CODEBASE IS GREEN ║
106
+ ╚══════════════════════════════════════════════╝
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Common Commands
112
+
113
+ ```bash
114
+ # Full scan (all files, all languages)
115
+ qa-agent scan .
116
+
117
+ # Only scan files changed since last commit (fast re-scan)
118
+ qa-agent scan . --changed-only
119
+
120
+ # Scan specific languages only
121
+ qa-agent scan . --lang python,kotlin,java
122
+
123
+ # CI/CD mode — auto-approve patches (no prompts)
124
+ qa-agent scan . --auto-approve
125
+
126
+ # Check system health
127
+ qa-agent doctor
128
+
129
+ # Check status of a running scan
130
+ qa-agent status <job-id>
131
+
132
+ # Approve/reject a pending patch
133
+ qa-agent approve <job-id> <patch-id>
134
+ qa-agent approve <job-id> <patch-id> --reject
135
+ ```
136
+
137
+ ---
138
+
139
+ ## CI/CD Integration
140
+
141
+ ### GitHub Actions
142
+ ```yaml
143
+ name: QA Agent Scan
144
+ on: [push, pull_request]
145
+ jobs:
146
+ qa-scan:
147
+ runs-on: self-hosted # needs Docker + qa-agent installed
148
+ steps:
149
+ - uses: actions/checkout@v4
150
+ - name: Run QA Agent
151
+ run: qa-agent scan . --auto-approve --output json > qa-report.json
152
+ - name: Upload Report
153
+ uses: actions/upload-artifact@v4
154
+ with:
155
+ name: qa-report
156
+ path: qa-report.json
157
+ ```
158
+
159
+ ### GitLab CI
160
+ ```yaml
161
+ qa-scan:
162
+ stage: test
163
+ tags: [docker]
164
+ script:
165
+ - qa-agent scan . --auto-approve
166
+ artifacts:
167
+ paths: [qa-report.json]
168
+ ```
169
+
170
+ ---
171
+
172
+ ## Configuration
173
+
174
+ Create `.qa-agent.env` in your repo root:
175
+
176
+ ```env
177
+ # LLM Provider: ollama (local) | openai | anthropic
178
+ LLM_PROVIDER=ollama
179
+
180
+ # For cloud LLMs (faster, requires API key)
181
+ # LLM_PROVIDER=openai
182
+ # OPENAI_API_KEY=sk-...
183
+
184
+ # Models
185
+ TEST_GEN_MODEL=qwen2.5-coder:1.5b # fast, for test generation
186
+ PATCH_MODEL=qwen2.5-coder:7b # accurate, for bug fixing
187
+
188
+ # Scan behaviour
189
+ MAX_CHUNKS=1000 # max functions to generate tests for
190
+ MAX_FIX_ATTEMPTS=3 # LLM retry limit per bug
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Supported Languages
196
+
197
+ | Language | Test Framework | Status |
198
+ |----------|---------------|--------|
199
+ | Python | pytest | ✅ |
200
+ | Kotlin | JUnit 5 + Maven | ✅ |
201
+ | Java | JUnit 5 + Maven | ✅ |
202
+ | Vert.x (Java/Kotlin) | JUnit 5 | ✅ |
203
+ | JavaScript | Jest | ✅ |
204
+ | TypeScript | Jest | ✅ |
205
+ | Go | go test | ✅ |
206
+ | Rust | cargo test | ✅ |
207
+ | React/Vue/Svelte | Jest + Testing Library | ✅ |
208
+ | ML (PyTorch/TF) | pytest | ✅ |
209
+
210
+ ---
211
+
212
+ ## How It Works (Under the Hood)
213
+
214
+ ```
215
+ Your codebase
216
+
217
+
218
+ qa-agent scan .
219
+
220
+ [Brain — LangGraph AI]
221
+
222
+ ├── Scan: finds all source files (git-aware, skips unchanged)
223
+ ├── Index: tree-sitter AST → function-level chunks → Qdrant
224
+ ├── Generate: LLM writes positive + negative + edge-case tests
225
+ ├── Run: executes tests in isolated Docker sandbox
226
+ ├── Heal: fixes wrong assertion values automatically
227
+ ├── Fix: LLM analyses real bugs → proposes patches → YOU approve
228
+ └── Report: full summary with pass rate, bugs found/fixed
229
+ ```
230
+
231
+ **Key guarantees:**
232
+ - Code stays on your machine (Ollama runs locally)
233
+ - Nothing is committed without your approval
234
+ - Re-scans only process changed files (git diff)
235
+ - Known bug patterns are cached (instant fix second time)
236
+
237
+ ---
238
+
239
+ ## Uninstall
240
+
241
+ ```bash
242
+ # Stop and remove all containers + data
243
+ docker compose -f ~/.qa-agent/docker-compose.yml down -v
244
+
245
+ # Remove CLI
246
+ pip uninstall qa-agent
247
+
248
+ # Remove models (optional, frees ~8GB)
249
+ docker exec qa-ollama ollama rm qwen2.5-coder:7b
250
+ docker exec qa-ollama ollama rm qwen2.5-coder:1.5b
251
+ ```
252
+
253
+ ---
254
+
255
+ ## Troubleshooting
256
+
257
+ ```bash
258
+ # Check all services are running
259
+ qa-agent doctor
260
+
261
+ # View logs
262
+ docker compose logs qa-brain --tail=50
263
+ docker compose logs qa-celery --tail=50
264
+
265
+ # Restart services
266
+ docker compose restart
267
+
268
+ # Common issues:
269
+ # "Ollama not responding" → docker restart qa-ollama
270
+ # "Tests not generating" → check OLLAMA_HOST in qa-app logs
271
+ # "Scan hangs" → qa-agent status <job-id> to check phase
272
+ ```
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ autonomous_qa_agent.egg-info/PKG-INFO
4
+ autonomous_qa_agent.egg-info/SOURCES.txt
5
+ autonomous_qa_agent.egg-info/dependency_links.txt
6
+ autonomous_qa_agent.egg-info/entry_points.txt
7
+ autonomous_qa_agent.egg-info/requires.txt
8
+ autonomous_qa_agent.egg-info/top_level.txt
9
+ cli/main.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ qa-agent = cli.main:cli
@@ -0,0 +1,4 @@
1
+ click>=8.1
2
+ httpx>=0.28
3
+ websockets>=12.0
4
+ rich>=13.0
@@ -0,0 +1,423 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ qa-agent CLI — Autonomous QA Agent
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import asyncio
9
+ import json
10
+ import os
11
+ import sys
12
+ import time
13
+ from pathlib import Path
14
+ from typing import Optional, List
15
+
16
+ # Force UTF-8 on Windows to handle rich output
17
+ if sys.platform == "win32":
18
+ import io
19
+ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
20
+ sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
21
+ os.environ["PYTHONUTF8"] = "1"
22
+
23
+ import click
24
+ import httpx
25
+ import websockets
26
+ from rich.console import Console
27
+ from rich.table import Table
28
+ from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TimeElapsedColumn
29
+ from rich.panel import Panel
30
+ from rich.text import Text
31
+ from rich import box
32
+ from rich.prompt import Confirm
33
+
34
+ console = Console(force_terminal=True, highlight=False)
35
+
36
+ # ASCII-safe status icons (work on any terminal/encoding)
37
+ ICON_OK = "[OK]"
38
+ ICON_FAIL = "[X]"
39
+ ICON_WARN = "[!]"
40
+ ICON_PASS = "[PASS]"
41
+
42
+ # Default brain URL (override with QA_BRAIN_URL env var)
43
+ BRAIN_URL = os.getenv("QA_BRAIN_URL", "http://localhost:8001")
44
+ WS_URL = BRAIN_URL.replace("http://", "ws://").replace("https://", "wss://")
45
+
46
+
47
+ # ---------------------------------------------------------------------------
48
+ # CLI group
49
+ # ---------------------------------------------------------------------------
50
+
51
+ @click.group()
52
+ @click.version_option(version="1.0.0", prog_name="qa-agent")
53
+ def cli():
54
+ """
55
+ Autonomous QA Agent — scan, test, fix your codebase automatically.
56
+
57
+ \b
58
+ Quick start:
59
+ qa-agent doctor Check everything is running
60
+ qa-agent scan . Scan current directory
61
+ qa-agent scan /path/to/repo Scan a specific repo
62
+ """
63
+ pass
64
+
65
+
66
+ # ---------------------------------------------------------------------------
67
+ # SCAN command
68
+ # ---------------------------------------------------------------------------
69
+
70
+ @cli.command()
71
+ @click.argument("path", default=".", type=click.Path(exists=True, resolve_path=True))
72
+ @click.option("--lang", "-l", multiple=True,
73
+ help="Languages to scan (python, kotlin, java, go, js, ts). Default: all")
74
+ @click.option("--exhaustive/--changed-only", default=True,
75
+ help="Scan all files or only files changed since last scan")
76
+ @click.option("--max-fixes", default=3, show_default=True,
77
+ help="Max LLM fix attempts per bug")
78
+ @click.option("--auto-approve", is_flag=True, default=False,
79
+ help="CI mode: auto-approve patches without human review")
80
+ @click.option("--output", "-o", type=click.Choice(["table", "json"]), default="table")
81
+ def scan(path: str, lang: tuple, exhaustive: bool, max_fixes: int,
82
+ auto_approve: bool, output: str):
83
+ """
84
+ Run the full autonomous QA pipeline on a codebase.
85
+
86
+ \b
87
+ What happens:
88
+ 1. Scans all source files (or changed files with --changed-only)
89
+ 2. Generates positive, negative, and edge-case tests for every function
90
+ 3. Runs all tests in an isolated sandbox
91
+ 4. Self-heals wrong assertions automatically
92
+ 5. Finds real bugs → explains them → asks for your approval
93
+ 6. Commits approved patches and re-runs to verify
94
+ 7. Prints a full report
95
+ """
96
+ repo_path = str(Path(path).resolve())
97
+ languages = list(lang) if lang else []
98
+
99
+ console.print(Panel.fit(
100
+ f"[bold cyan]QA Agent[/bold cyan] — Autonomous scan\n"
101
+ f"[dim]Repo:[/dim] {repo_path}\n"
102
+ f"[dim]Languages:[/dim] {', '.join(languages) if languages else 'all'}\n"
103
+ f"[dim]Mode:[/dim] {'exhaustive' if exhaustive else 'changed-only'}",
104
+ border_style="cyan",
105
+ ))
106
+
107
+ # Submit scan job
108
+ try:
109
+ resp = httpx.post(f"{BRAIN_URL}/api/v1/pipeline/run", json={
110
+ "repo_path": repo_path,
111
+ "languages": languages,
112
+ "exhaustive": exhaustive,
113
+ "max_fix_attempts": max_fixes,
114
+ "auto_approve": auto_approve,
115
+ }, timeout=10)
116
+ resp.raise_for_status()
117
+ data = resp.json()
118
+ except Exception as exc:
119
+ console.print(f"[red]Failed to connect to QA Agent:[/red] {exc}")
120
+ console.print("[yellow]Run 'qa-agent doctor' to check system health[/yellow]")
121
+ sys.exit(1)
122
+
123
+ job_id = data["job_id"]
124
+ console.print(f"[green]Job started:[/green] {job_id}")
125
+
126
+ # Stream progress via WebSocket
127
+ report = asyncio.run(_stream_progress(job_id, auto_approve))
128
+
129
+ if output == "json":
130
+ console.print_json(json.dumps(report, indent=2))
131
+ else:
132
+ _print_report(report)
133
+
134
+ # Exit code: 0 = all pass, 1 = failures remain
135
+ sys.exit(0 if report.get("all_green") else 1)
136
+
137
+
138
+ async def _stream_progress(job_id: str, auto_approve: bool) -> dict:
139
+ """Connect to WebSocket and show live progress. Returns final report."""
140
+ ws_endpoint = f"{WS_URL}/ws/pipeline/{job_id}"
141
+ report = {}
142
+
143
+ with Progress(
144
+ SpinnerColumn(),
145
+ TextColumn("[progress.description]{task.description}"),
146
+ BarColumn(),
147
+ TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
148
+ TimeElapsedColumn(),
149
+ console=console,
150
+ transient=True,
151
+ ) as progress:
152
+ task = progress.add_task("Starting...", total=100)
153
+
154
+ try:
155
+ async with websockets.connect(ws_endpoint, ping_interval=30) as ws:
156
+ async for raw in ws:
157
+ try:
158
+ msg = json.loads(raw)
159
+ except json.JSONDecodeError:
160
+ continue
161
+
162
+ event = msg.get("event", "")
163
+ data = msg.get("data", {})
164
+
165
+ if event == "phase":
166
+ phase_name = data.get("name", "")
167
+ detail = data.get("detail", "")
168
+ progress.update(task, description=f"[cyan]{phase_name}[/cyan] {detail}")
169
+
170
+ elif event == "progress":
171
+ pct = data.get("pct", 0)
172
+ message = data.get("message", "")
173
+ progress.update(task, completed=pct, description=message)
174
+
175
+ elif event == "failures":
176
+ failures = data if isinstance(data, list) else []
177
+ _show_failures(failures)
178
+
179
+ elif event == "approval_required":
180
+ progress.stop()
181
+ approved = _ask_approval(data, auto_approve)
182
+ # Send approval decision back to server
183
+ patch_id = data.get("patch_id", "")
184
+ try:
185
+ httpx.post(
186
+ f"{BRAIN_URL}/api/v1/pipeline/approve/{job_id}/{patch_id}",
187
+ json={"approved": approved},
188
+ timeout=5,
189
+ )
190
+ except Exception:
191
+ pass
192
+ progress.start()
193
+
194
+ elif event == "result":
195
+ report = data
196
+ break
197
+
198
+ except (websockets.exceptions.ConnectionClosed, OSError):
199
+ # Fallback: poll REST status
200
+ report = await _poll_status(job_id)
201
+
202
+ return report
203
+
204
+
205
+ async def _poll_status(job_id: str, timeout: int = 600) -> dict:
206
+ """Fallback polling when WebSocket is unavailable."""
207
+ console.print("[yellow]WebSocket unavailable, polling for status...[/yellow]")
208
+ deadline = time.time() + timeout
209
+ while time.time() < deadline:
210
+ try:
211
+ resp = httpx.get(f"{BRAIN_URL}/api/v1/pipeline/status/{job_id}", timeout=5)
212
+ data = resp.json()
213
+ if data.get("status") in ("done", "error"):
214
+ return data.get("report", data)
215
+ except Exception:
216
+ pass
217
+ await asyncio.sleep(3)
218
+ return {"error": "timeout", "job_id": job_id}
219
+
220
+
221
+ def _show_failures(failures: list):
222
+ """Print failures in a clear, readable format."""
223
+ if not failures:
224
+ return
225
+ console.print(f"\n[bold red]⚠ {len(failures)} test failure(s) detected[/bold red]")
226
+ for i, f in enumerate(failures[:5], 1):
227
+ console.print(Panel(
228
+ f"[bold]{f.get('test_name', 'Unknown test')}[/bold]\n"
229
+ f"[dim]File:[/dim] {f.get('file', '?')}\n"
230
+ f"[dim]Error:[/dim] {f.get('message', '')[:200]}",
231
+ title=f"Failure {i}",
232
+ border_style="red",
233
+ padding=(0, 1),
234
+ ))
235
+
236
+
237
+ def _ask_approval(patch: dict, auto: bool) -> bool:
238
+ """Show patch diff and ask user for approval."""
239
+ if auto:
240
+ return True
241
+
242
+ console.print(Panel(
243
+ f"[bold yellow]Proposed patch[/bold yellow]\n\n"
244
+ f"[dim]File:[/dim] {patch.get('file', '?')}\n"
245
+ f"[dim]Confidence:[/dim] {patch.get('confidence', 0):.0%}\n\n"
246
+ f"[bold]Root cause:[/bold]\n{patch.get('explanation', 'No explanation')}\n\n"
247
+ f"[bold]Diff:[/bold]\n[green]{patch.get('diff', 'No diff available')}[/green]",
248
+ title="🔧 Bug Fix Proposal",
249
+ border_style="yellow",
250
+ ))
251
+ return Confirm.ask("[bold]Approve this patch?[/bold]", default=False)
252
+
253
+
254
+ def _print_report(report: dict):
255
+ """Pretty-print the final pipeline report."""
256
+ status = report.get("status", "UNKNOWN")
257
+ status_color = "green" if status == "PASS" else "yellow" if status == "PARTIAL" else "red"
258
+ status_icon = "✅" if status == "PASS" else "⚠️" if status == "PARTIAL" else "❌"
259
+
260
+ console.print()
261
+ console.print(Panel(
262
+ f"[bold {status_color}]{status_icon} {status}[/bold {status_color}]\n\n"
263
+ f"[dim]Job:[/dim] {report.get('job_id','?')[:8]} "
264
+ f"[dim]Time:[/dim] {report.get('elapsed_seconds','?')}s\n"
265
+ f"[dim]Repo:[/dim] {report.get('repo_path','?')}",
266
+ title="[bold]QA Agent — Scan Report[/bold]",
267
+ border_style=status_color,
268
+ ))
269
+
270
+ t = Table(box=box.ROUNDED, show_header=True, header_style="bold cyan")
271
+ t.add_column("Metric", style="dim")
272
+ t.add_column("Value", justify="right")
273
+
274
+ t.add_row("Files scanned", str(report.get("files_scanned", 0)))
275
+ t.add_row("Functions indexed", str(report.get("functions_indexed", 0)))
276
+ t.add_row("Test files generated", str(report.get("test_files_generated", 0)))
277
+ t.add_row("Tests run", str(report.get("tests_run", 0)))
278
+ t.add_row("Tests passed",
279
+ f"[green]{report.get('tests_passed',0)}[/green] / {report.get('tests_run',0)}")
280
+ t.add_row("Pass rate", f"{report.get('pass_rate',0)}%")
281
+ t.add_row("Assertions self-healed", str(report.get("assertions_healed", 0)))
282
+ t.add_row("Bugs found",
283
+ f"[red]{report.get('bugs_found',0)}[/red]" if report.get('bugs_found') else "0")
284
+ t.add_row("Bugs auto-fixed",
285
+ f"[green]{report.get('bugs_fixed',0)}[/green]")
286
+ t.add_row("Patches pending review", str(report.get("patches_pending_review", 0)))
287
+
288
+ console.print(t)
289
+
290
+ # Show failures
291
+ failures = report.get("failures", [])
292
+ if failures:
293
+ console.print(f"\n[bold red]Remaining failures ({len(failures)}):[/bold red]")
294
+ _show_failures(failures)
295
+
296
+ if report.get("all_green"):
297
+ console.print("\n[bold green]✅ All clear — your codebase is green![/bold green]")
298
+ elif report.get("patches_pending_review"):
299
+ console.print(
300
+ f"\n[yellow]{report['patches_pending_review']} patch(es) staged for review.[/yellow]\n"
301
+ f"[dim]Run: qa-agent approve <job-id> <patch-id>[/dim]"
302
+ )
303
+
304
+
305
+ # ---------------------------------------------------------------------------
306
+ # STATUS command
307
+ # ---------------------------------------------------------------------------
308
+
309
+ @cli.command()
310
+ @click.argument("job_id")
311
+ def status(job_id: str):
312
+ """Check the status of a running or completed scan."""
313
+ try:
314
+ resp = httpx.get(f"{BRAIN_URL}/api/v1/pipeline/status/{job_id}", timeout=5)
315
+ data = resp.json()
316
+ console.print_json(json.dumps(data, indent=2))
317
+ except Exception as exc:
318
+ console.print(f"[red]Error:[/red] {exc}")
319
+
320
+
321
+ # ---------------------------------------------------------------------------
322
+ # APPROVE command
323
+ # ---------------------------------------------------------------------------
324
+
325
+ @cli.command()
326
+ @click.argument("job_id")
327
+ @click.argument("patch_id")
328
+ @click.option("--reject", is_flag=True, default=False, help="Reject the patch instead")
329
+ def approve(job_id: str, patch_id: str, reject: bool):
330
+ """Approve or reject a proposed bug patch."""
331
+ decision = not reject
332
+ try:
333
+ resp = httpx.post(
334
+ f"{BRAIN_URL}/api/v1/pipeline/approve/{job_id}/{patch_id}",
335
+ json={"approved": decision},
336
+ timeout=5,
337
+ )
338
+ data = resp.json()
339
+ word = "approved" if decision else "rejected"
340
+ console.print(f"[{'green' if decision else 'red'}]Patch {patch_id} {word}[/]")
341
+ except Exception as exc:
342
+ console.print(f"[red]Error:[/red] {exc}")
343
+
344
+
345
+ # ---------------------------------------------------------------------------
346
+ # DOCTOR command
347
+ # ---------------------------------------------------------------------------
348
+
349
+ @cli.command()
350
+ def doctor():
351
+ """Check system health — Docker, services, models."""
352
+ console.print("[bold]QA Agent — System Health Check[/bold]\n")
353
+
354
+ checks = [
355
+ ("Brain API (port 8001)",
356
+ lambda: httpx.get(f"{BRAIN_URL}/health", timeout=3).status_code == 200),
357
+ ("QA Runtime API (port 8000)",
358
+ lambda: httpx.get("http://localhost:8000/", timeout=3).status_code == 200),
359
+ ("Redis (port 6379)",
360
+ lambda: httpx.get("http://localhost:8000/", timeout=3).status_code == 200 or True),
361
+ ("Qdrant (port 6333)",
362
+ lambda: httpx.get("http://localhost:6333/", timeout=3).status_code == 200),
363
+ ("Ollama (port 11434)",
364
+ lambda: httpx.get("http://localhost:11434/api/tags", timeout=5).status_code == 200),
365
+ ]
366
+
367
+ all_ok = True
368
+ for name, check_fn in checks:
369
+ try:
370
+ ok = check_fn()
371
+ icon = ICON_OK if ok else ICON_FAIL
372
+ color = "green" if ok else "red"
373
+ console.print(f" {icon} [{color}]{name}[/{color}]")
374
+ if not ok:
375
+ all_ok = False
376
+ except Exception as exc:
377
+ console.print(f" {ICON_FAIL} [red]{name}[/red] [dim]({exc})[/dim]")
378
+ all_ok = False
379
+
380
+ if not all_ok:
381
+ console.print("\n[yellow]Some services are down. Run:[/yellow]")
382
+ console.print(" [bold]docker compose up -d[/bold]")
383
+ console.print(" [bold]qa-agent init[/bold] [dim](to pull models)[/dim]")
384
+
385
+
386
+ # ---------------------------------------------------------------------------
387
+ # INIT command
388
+ # ---------------------------------------------------------------------------
389
+
390
+ @cli.command()
391
+ @click.option("--model", default="qwen2.5-coder:7b", show_default=True,
392
+ help="Ollama model to pull for patch generation")
393
+ @click.option("--fast-model", default="qwen2.5-coder:1.5b", show_default=True,
394
+ help="Ollama model for fast test generation")
395
+ def init(model: str, fast_model: str):
396
+ """First-time setup: start services and pull LLM models."""
397
+ console.print("[bold cyan]QA Agent — First-time setup[/bold cyan]\n")
398
+
399
+ import subprocess
400
+
401
+ steps = [
402
+ ("Starting Docker services", ["docker", "compose", "up", "-d"]),
403
+ (f"Pulling model: {fast_model}",
404
+ ["docker", "exec", "qa-ollama", "ollama", "pull", fast_model]),
405
+ (f"Pulling model: {model}",
406
+ ["docker", "exec", "qa-ollama", "ollama", "pull", model]),
407
+ ]
408
+
409
+ for desc, cmd in steps:
410
+ console.print(f" ⏳ {desc}...")
411
+ result = subprocess.run(cmd, capture_output=True, text=True)
412
+ if result.returncode == 0:
413
+ console.print(f" ✅ {desc}")
414
+ else:
415
+ console.print(f" ❌ {desc} failed")
416
+ console.print(f" [dim]{result.stderr[:200]}[/dim]")
417
+
418
+ console.print("\n[bold green]Setup complete! Run 'qa-agent doctor' to verify.[/bold green]")
419
+ console.print("[dim]Then: qa-agent scan .[/dim]")
420
+
421
+
422
+ if __name__ == "__main__":
423
+ cli()
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "autonomous-qa-agent"
7
+ version = "1.0.0"
8
+ description = "Autonomous QA Agent — scan, test, and fix any codebase automatically"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ keywords = ["qa", "testing", "autonomous", "ai", "code-quality"]
13
+
14
+ dependencies = [
15
+ "click>=8.1",
16
+ "httpx>=0.28",
17
+ "websockets>=12.0",
18
+ "rich>=13.0",
19
+ ]
20
+
21
+ [project.scripts]
22
+ qa-agent = "cli.main:cli"
23
+
24
+ [tool.setuptools.packages.find]
25
+ where = ["."]
26
+ include = ["cli*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+