qaas-python 0.2.1__tar.gz → 0.2.2__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.
- {qaas_python-0.2.1 → qaas_python-0.2.2}/.gitignore +3 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/PKG-INFO +1 -1
- {qaas_python-0.2.1 → qaas_python-0.2.2}/pyproject.toml +2 -2
- qaas_python-0.2.1/tutorial/01-code-structure.md +0 -251
- qaas_python-0.2.1/tutorial/02-how-agents-communicate.md +0 -963
- qaas_python-0.2.1/tutorial/03-skills-and-hooks.md +0 -607
- qaas_python-0.2.1/tutorial/04-mcp-servers.md +0 -709
- qaas_python-0.2.1/tutorial/05-prompt-configuration.md +0 -619
- qaas_python-0.2.1/tutorial/06-jira-integration.md +0 -938
- qaas_python-0.2.1/tutorial/07-github-actions.md +0 -499
- qaas_python-0.2.1/tutorial/08-packaging-and-publishing.md +0 -669
- qaas_python-0.2.1/tutorial/09-guardrails-and-safety.md +0 -1078
- qaas_python-0.2.1/tutorial/README.md +0 -88
- {qaas_python-0.2.1 → qaas_python-0.2.2}/ARCHITECTURE.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/BUILD_PLAN.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/CLAUDE.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/LICENSE +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/README.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/config/targets/corvid.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/adapters/__init__.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/adapters/tracker.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/adapters/vcs.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/cli.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/conductor.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/config.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/arbiter.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/cartographer.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/clerk.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/conduit.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/forge.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/mender.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/proof.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/surface.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/vault.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/warden.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/system.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/discover.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/envelope.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/guardrails.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/__init__.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/context.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/contract_diff.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/defect_memory.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/env_control.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/envelope_server.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/test_runner.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/tracker.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/vcs.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/paths.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/.claude-plugin/plugin.json +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/a11y-audit/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/adversarial-review/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/api-surface-extraction/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/authz-matrix-check/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/console-error-triage/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/contract-test-generation/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/dedupe-strategy/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/environment-pinning/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/error-taxonomy/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/exploratory-ui-walk/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/failing-test-authoring/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/flake-detection/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/form-state-probe/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/minimal-diff-discipline/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/openapi-diff/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/ownership-resolution/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/product-task-graph/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/regression-risk-scoring/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/regression-suite-selection/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/repo-cartography/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/repro-minimisation/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/rollback-plan-authoring/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/root-cause-vs-symptom/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/routing-rules/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/severity-rubric/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/test-first-fix/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/test-quality-audit/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/ticket-writer/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/verdict-reporting/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/verification-protocol/SKILL.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/ARBITER.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/CARTOGRAPHER.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/CLERK.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/CONDUIT.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/FORGE.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/MENDER.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/PROOF.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/SURFACE.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/VAULT.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/WARDEN.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/_shared.md +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/registry.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/runner.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/scorecard.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/sdk_compat.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/store.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/target.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/tasks.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/trace.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/CODEOWNERS +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/Dockerfile +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/__init__.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/auth.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/config.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/db.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/errors.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/main.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/models.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/routes/__init__.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/routes/auth.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/routes/invoices.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/routes/orders.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/routes/stream.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/schemas.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/migrations/001_init.sql +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/pyproject.toml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/seed/fixtures.sql +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/defects.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/docker-compose.yml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/openapi.yaml +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/.gitignore +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/Dockerfile +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/index.html +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/package-lock.json +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/package.json +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/api.ts +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/components/Button.tsx +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/components/Layout.tsx +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/components/SearchInput.tsx +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/main.tsx +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/routes/CheckoutReview.tsx +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/routes/Login.tsx +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/routes/NewOrder.tsx +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/routes/OrderDetail.tsx +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/routes/OrdersList.tsx +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/styles.css +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/tsconfig.json +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/vite.config.ts +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/adapters/test_github_vcs.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/adapters/test_jira_tracker.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/conftest.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/conftest.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_contract_diff.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_defect_memory.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_env_control.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_test_runner.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_tracker.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_vcs.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/support.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/target_app/test_seeded_defects.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_cli.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_conductor.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_config.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_discover.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_envelope.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_guardrails.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_hooks_and_skills.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_paths.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_prompt_overrides.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_registry.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_scorecard.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_skills_actually_load.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_store.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_target_profile_is_honoured.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_trace.py +0 -0
- {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_user_mcp_servers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: qaas-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A multi-agent QA system: finds real defects, reproduces them, files tickets, fixes them, and proves the fix
|
|
5
5
|
Project-URL: Homepage, https://github.com/allaabdella2-us/qa-multi-agent-system
|
|
6
6
|
Project-URL: Repository, https://github.com/allaabdella2-us/qa-multi-agent-system
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Distribution name is `qaas-python` (`qaas` was taken); the import package and
|
|
3
3
|
# the CLI are both `qaas`.
|
|
4
4
|
name = "qaas-python"
|
|
5
|
-
version = "0.2.
|
|
5
|
+
version = "0.2.2"
|
|
6
6
|
description = "A multi-agent QA system: finds real defects, reproduces them, files tickets, fixes them, and proves the fix"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
license = "MIT"
|
|
@@ -63,7 +63,7 @@ include = [
|
|
|
63
63
|
# (src/qaas/plugin/skills), so "src/" already carries them. The old
|
|
64
64
|
# ".claude/skills/" entry outlived the directory it named -- hatchling
|
|
65
65
|
# ignores a missing path, so it broke nothing and simply misled.
|
|
66
|
-
"src/", "config/", "target-app/", "tests/",
|
|
66
|
+
"src/", "config/", "target-app/", "tests/",
|
|
67
67
|
"README.md", "LICENSE", "ARCHITECTURE.md", "CLAUDE.md", "BUILD_PLAN.md",
|
|
68
68
|
"pyproject.toml",
|
|
69
69
|
]
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
# 01 — Code structure and how the pieces relate
|
|
2
|
-
|
|
3
|
-
Where every module lives, what it owns, and which module is allowed to know about
|
|
4
|
-
which. Read this first; the other files assume it.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## The one-line version
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
qaas <command> → cli.py → conductor.py → runner.py → claude_agent_sdk.query()
|
|
12
|
-
↑ ↑
|
|
13
|
-
a state machine one agent, one call
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Everything else exists to serve those four files.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## The whole package
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
src/qaas/
|
|
24
|
-
├── cli.py 1564 entry point — 13 commands
|
|
25
|
-
├── conductor.py 527 THE STATE MACHINE: phases, budget, concurrency, loops
|
|
26
|
-
├── runner.py 192 invokes ONE agent, records what it cost
|
|
27
|
-
├── registry.py 465 turns an agent's YAML into SDK options
|
|
28
|
-
├── guardrails.py 421 the permission matrix, enforced in code
|
|
29
|
-
├── config.py 407 loads and validates config/
|
|
30
|
-
├── tasks.py 361 builds the per-run task string for each agent
|
|
31
|
-
├── paths.py 317 where config, prompts and skills are found
|
|
32
|
-
├── store.py 290 run ledger, artifacts, versioned system map
|
|
33
|
-
├── envelope.py 290 DefectEnvelope — the only inter-agent type
|
|
34
|
-
├── trace.py 270 the read side of the ledger
|
|
35
|
-
├── target.py 261 target profiles — what makes it portable
|
|
36
|
-
├── scorecard.py 425 recall/precision against the golden ledger
|
|
37
|
-
├── discover.py 227 guesses a target profile for `qaas init`
|
|
38
|
-
├── sdk_compat.py 52 fails loudly when the SDK renames a hook event
|
|
39
|
-
│
|
|
40
|
-
├── prompts/ one .md per agent + _shared.md appended to all
|
|
41
|
-
├── plugin/ the skills, shipped as a Claude Code plugin
|
|
42
|
-
│ ├── .claude-plugin/plugin.json
|
|
43
|
-
│ └── skills/<30 dirs>/SKILL.md
|
|
44
|
-
├── defaults/config/ system.yaml + agents/*.yaml that ship in the wheel
|
|
45
|
-
├── mcp/ seven in-process tool servers
|
|
46
|
-
└── adapters/ tracker (local | jira), vcs (local | github)
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Line counts are real, from `wc -l`. They are a rough guide to where the weight
|
|
50
|
-
sits: `cli.py` and `adapters/tracker.py` are the two biggest files and are mostly
|
|
51
|
-
surface area, not logic.
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## The dependency graph
|
|
56
|
-
|
|
57
|
-
This is the actual import graph, extracted from the source. **Arrows point at what
|
|
58
|
-
a module is allowed to know about.** Nothing points back up.
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
cli.py
|
|
62
|
-
│ (config, paths, store, trace)
|
|
63
|
-
▼
|
|
64
|
-
conductor.py ────────────┐
|
|
65
|
-
│ │
|
|
66
|
-
(config, envelope, │ store, │
|
|
67
|
-
mcp.context) ▼ │
|
|
68
|
-
runner.py │
|
|
69
|
-
│ (registry) │
|
|
70
|
-
▼ │
|
|
71
|
-
registry.py │
|
|
72
|
-
│ (config, │
|
|
73
|
-
│ guardrails, │
|
|
74
|
-
│ sdk_compat) │
|
|
75
|
-
▼ │
|
|
76
|
-
guardrails.py │
|
|
77
|
-
│ (mcp.context) │
|
|
78
|
-
▼ ▼
|
|
79
|
-
config.py ────────► store.py
|
|
80
|
-
│ (target) │ (envelope)
|
|
81
|
-
▼ ▼
|
|
82
|
-
target.py ─────────► envelope.py
|
|
83
|
-
│ (paths) (imports nothing)
|
|
84
|
-
▼
|
|
85
|
-
paths.py
|
|
86
|
-
(imports nothing)
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Two facts fall out of this and are worth internalising:
|
|
90
|
-
|
|
91
|
-
**`envelope.py` and `paths.py` import nothing from the package.** They are the
|
|
92
|
-
foundation. `envelope.py` is the contract every agent speaks; `paths.py` is how
|
|
93
|
-
the package finds its own resources. Both must be understandable on their own,
|
|
94
|
-
and both are heavily tested in isolation.
|
|
95
|
-
|
|
96
|
-
**`registry.py` imports `config.py`, so `config.py` cannot import `registry.py`.**
|
|
97
|
-
There is a real consequence: the validator in `config.py` that checks every MCP
|
|
98
|
-
server an agent names actually exists has to import `registry` *inside the
|
|
99
|
-
function*. The comment there says so.
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## What each module owns
|
|
104
|
-
|
|
105
|
-
| module | owns | does **not** own |
|
|
106
|
-
|---|---|---|
|
|
107
|
-
| `cli.py` | argument parsing, printing, exit codes | any decision about a run |
|
|
108
|
-
| `conductor.py` | phase order, budget, concurrency, escalation, loop bounds | how one agent runs |
|
|
109
|
-
| `runner.py` | one `query()`, one `AgentResult` | whether that agent should run |
|
|
110
|
-
| `registry.py` | assembling `ClaudeAgentOptions` | what the agent then does |
|
|
111
|
-
| `guardrails.py` | allow/deny for every tool call | logging policy (it delegates to the store) |
|
|
112
|
-
| `envelope.py` | the shape of a finding, and its two gates | where findings are stored |
|
|
113
|
-
| `store.py` | the ledger, artifacts, the system map | what any entry means |
|
|
114
|
-
| `config.py` | loading and validating YAML | where the YAML lives (that is `paths.py`) |
|
|
115
|
-
| `paths.py` | config/prompt/skill/state resolution | reading any of them |
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## The two decisions that explain the shape
|
|
120
|
-
|
|
121
|
-
### 1. CONDUCTOR is Python, not a prompt
|
|
122
|
-
|
|
123
|
-
The design document describes an orchestrator agent. It is implemented as an
|
|
124
|
-
ordinary state machine because **a model cannot enforce a budget it is itself
|
|
125
|
-
spending.**
|
|
126
|
-
|
|
127
|
-
Everything that must be true regardless of what a model decides lives in
|
|
128
|
-
`conductor.py`: phase ordering, the concurrency cap, retries, escalation, and the
|
|
129
|
-
loop bounds. That is also why 649 tests run offline with no API key — the
|
|
130
|
-
interesting logic is not behind a model call.
|
|
131
|
-
|
|
132
|
-
```python
|
|
133
|
-
# src/qaas/conductor.py — the five phases, in order
|
|
134
|
-
map_version = await self._phase_map(specs, store, budget, report)
|
|
135
|
-
await self._phase_discover(specs, store, budget, report, mode, map_version)
|
|
136
|
-
await self._phase_reproduce(specs, store, budget, report, map_version)
|
|
137
|
-
if run_mode.files_tickets:
|
|
138
|
-
await self._phase_file(...)
|
|
139
|
-
await self._phase_verify(...)
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### 2. Every agent is its own top-level `query()`
|
|
143
|
-
|
|
144
|
-
Not SDK subagents under a shared parent. Nesting would pool cost into one number
|
|
145
|
-
and blur the per-agent tool allowlist that the whole permission model depends on.
|
|
146
|
-
|
|
147
|
-
One `query()` per agent gives three things that matter:
|
|
148
|
-
|
|
149
|
-
- a real context boundary — CONDUIT cannot see what SURFACE read
|
|
150
|
-
- an enforceable allowlist — the tools are set per call, not per session
|
|
151
|
-
- a per-agent `total_cost_usd`, straight off the `ResultMessage`
|
|
152
|
-
|
|
153
|
-
`AgentDefinition` / `agents=` remains available for *intra-agent* fan-out.
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## Agents are data, not code
|
|
158
|
-
|
|
159
|
-
An agent is **a prompt plus a YAML file**. That is the whole definition.
|
|
160
|
-
|
|
161
|
-
```
|
|
162
|
-
src/qaas/prompts/CONDUIT.md role and standards
|
|
163
|
-
src/qaas/defaults/config/agents/conduit.yaml model, budget, tools, skills, policy
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Adding an agent should require **no change** to `conductor.py`, `runner.py`,
|
|
167
|
-
`registry.py` or `guardrails.py`. A change to one of those while adding an agent
|
|
168
|
-
is a sign something is wrong.
|
|
169
|
-
|
|
170
|
-
Where each kind of instruction belongs — this split is easy to get wrong and the
|
|
171
|
-
codebase is strict about it:
|
|
172
|
-
|
|
173
|
-
| what | where | why |
|
|
174
|
-
|---|---|---|
|
|
175
|
-
| role, standards | `prompts/<AGENT>.md` | stable across every run |
|
|
176
|
-
| house rules for all agents | `prompts/_shared.md` | appended to every prompt, not copy-pasted into eight |
|
|
177
|
-
| **procedure** | `plugin/skills/<name>/SKILL.md` | loaded on demand, shared between agents |
|
|
178
|
-
| the per-run **task** | `tasks.py` | which app, which environment, which finding |
|
|
179
|
-
| **enforcement** | `guardrails.py` | a prompt is a request; code is a rule |
|
|
180
|
-
|
|
181
|
-
> **Nothing in `tasks.py` or a prompt may name a specific application.** A prompt
|
|
182
|
-
> that mentions one repo's layout works exactly once. This rule has been broken
|
|
183
|
-
> and fixed: two `contract_diff` tool descriptions once said
|
|
184
|
-
> `target-app/openapi.yaml` directly to the model.
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
## The eight agents
|
|
189
|
-
|
|
190
|
-
| agent | layer | does |
|
|
191
|
-
|---|---|---|
|
|
192
|
-
| CARTOGRAPHER | map | services, routes, schema, ownership → `system-map.json` |
|
|
193
|
-
| CONDUIT | discovery | API contract drift; ships a failing contract test |
|
|
194
|
-
| SURFACE | discovery | drives the UI through real journeys |
|
|
195
|
-
| VAULT | discovery | schema constraints the code assumes and the database does not enforce |
|
|
196
|
-
| WARDEN | discovery | missing authorization, secrets, vulnerable dependencies, leaked internals |
|
|
197
|
-
| FORGE | triage | reproduces, minimises, measures flake, commits a failing test |
|
|
198
|
-
| CLERK | triage | dedupes, scores severity, routes, files — the only tracker writer |
|
|
199
|
-
| MENDER | remediation | the minimal fix, on a `fix/*` branch |
|
|
200
|
-
| ARBITER | remediation | adversarial review: APPROVE / REQUEST_CHANGES / ESCALATE |
|
|
201
|
-
| PROOF | verify | re-runs the original test → VERIFIED / NOT_FIXED / REGRESSED |
|
|
202
|
-
|
|
203
|
-
The design names 16. Ten are built; CONDUCTOR is the state machine rather than an
|
|
204
|
-
agent; five further discovery specialists are designed and not written.
|
|
205
|
-
|
|
206
|
-
VAULT and WARDEN are worth noting for *how* they were added: a prompt file and a
|
|
207
|
-
YAML file each, with no Python. That is the architecture's central claim, and it
|
|
208
|
-
was not quite true until they tested it -- `_phase_discover` dispatched from a
|
|
209
|
-
closed dict of task builders, so a new discovery agent validated, assembled,
|
|
210
|
-
appeared in `--dry-run`, and was then silently skipped with `no task builder`.
|
|
211
|
-
There is a generic discovery task now, and a test that asserts a config-only
|
|
212
|
-
agent actually *runs*.
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## Runtime state
|
|
217
|
-
|
|
218
|
-
```
|
|
219
|
-
.qaas/ (gitignored)
|
|
220
|
-
├── config/ your config, if you ran `qaas init`
|
|
221
|
-
├── runs/<run-id>/
|
|
222
|
-
│ ├── ledger.jsonl append-only: every tool call, denial, escalation
|
|
223
|
-
│ ├── envelopes/*.json the findings
|
|
224
|
-
│ ├── artifacts/ screenshots, logs, traces
|
|
225
|
-
│ └── results/*.json per-agent cost, turns, duration
|
|
226
|
-
├── system-map/ versioned, shared across runs, pinned per run
|
|
227
|
-
├── memory.db SQLite: defect fingerprints, for dedupe
|
|
228
|
-
└── tickets/*.json the local tracker
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
The ledger is not only an audit trail — the conductor **reads it back** for
|
|
232
|
-
control flow. `_latest_verdict`, `_latest_review` and `_branch_written_since` all
|
|
233
|
-
query it. That is unusual and it is deliberate: a verdict is a typed ledger entry,
|
|
234
|
-
never parsed out of an agent's prose. See [02 — how agents
|
|
235
|
-
communicate](02-how-agents-communicate.md).
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## Reading order for a newcomer
|
|
240
|
-
|
|
241
|
-
1. `qaas validate` then `qaas run --mode pr-check --dry-run` — watch the machine
|
|
242
|
-
describe itself, for free
|
|
243
|
-
2. `envelope.py` — the contract everything moves
|
|
244
|
-
3. `conductor.py::run` — the five phases
|
|
245
|
-
4. `defaults/config/agents/conduit.yaml` + `prompts/CONDUIT.md` — what an agent *is*
|
|
246
|
-
5. `guardrails.py::check` — the one function both enforcement points call
|
|
247
|
-
6. `.qaas/runs/<id>/ledger.jsonl` from a real run, or `qaas trace <id>`
|
|
248
|
-
|
|
249
|
-
---
|
|
250
|
-
|
|
251
|
-
**Next:** [02 — How agents communicate](02-how-agents-communicate.md)
|