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.
Files changed (166) hide show
  1. {qaas_python-0.2.1 → qaas_python-0.2.2}/.gitignore +3 -0
  2. {qaas_python-0.2.1 → qaas_python-0.2.2}/PKG-INFO +1 -1
  3. {qaas_python-0.2.1 → qaas_python-0.2.2}/pyproject.toml +2 -2
  4. qaas_python-0.2.1/tutorial/01-code-structure.md +0 -251
  5. qaas_python-0.2.1/tutorial/02-how-agents-communicate.md +0 -963
  6. qaas_python-0.2.1/tutorial/03-skills-and-hooks.md +0 -607
  7. qaas_python-0.2.1/tutorial/04-mcp-servers.md +0 -709
  8. qaas_python-0.2.1/tutorial/05-prompt-configuration.md +0 -619
  9. qaas_python-0.2.1/tutorial/06-jira-integration.md +0 -938
  10. qaas_python-0.2.1/tutorial/07-github-actions.md +0 -499
  11. qaas_python-0.2.1/tutorial/08-packaging-and-publishing.md +0 -669
  12. qaas_python-0.2.1/tutorial/09-guardrails-and-safety.md +0 -1078
  13. qaas_python-0.2.1/tutorial/README.md +0 -88
  14. {qaas_python-0.2.1 → qaas_python-0.2.2}/ARCHITECTURE.md +0 -0
  15. {qaas_python-0.2.1 → qaas_python-0.2.2}/BUILD_PLAN.md +0 -0
  16. {qaas_python-0.2.1 → qaas_python-0.2.2}/CLAUDE.md +0 -0
  17. {qaas_python-0.2.1 → qaas_python-0.2.2}/LICENSE +0 -0
  18. {qaas_python-0.2.1 → qaas_python-0.2.2}/README.md +0 -0
  19. {qaas_python-0.2.1 → qaas_python-0.2.2}/config/targets/corvid.yaml +0 -0
  20. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/adapters/__init__.py +0 -0
  21. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/adapters/tracker.py +0 -0
  22. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/adapters/vcs.py +0 -0
  23. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/cli.py +0 -0
  24. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/conductor.py +0 -0
  25. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/config.py +0 -0
  26. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/arbiter.yaml +0 -0
  27. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/cartographer.yaml +0 -0
  28. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/clerk.yaml +0 -0
  29. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/conduit.yaml +0 -0
  30. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/forge.yaml +0 -0
  31. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/mender.yaml +0 -0
  32. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/proof.yaml +0 -0
  33. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/surface.yaml +0 -0
  34. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/vault.yaml +0 -0
  35. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/agents/warden.yaml +0 -0
  36. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/defaults/config/system.yaml +0 -0
  37. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/discover.py +0 -0
  38. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/envelope.py +0 -0
  39. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/guardrails.py +0 -0
  40. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/__init__.py +0 -0
  41. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/context.py +0 -0
  42. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/contract_diff.py +0 -0
  43. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/defect_memory.py +0 -0
  44. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/env_control.py +0 -0
  45. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/envelope_server.py +0 -0
  46. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/test_runner.py +0 -0
  47. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/tracker.py +0 -0
  48. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/mcp/vcs.py +0 -0
  49. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/paths.py +0 -0
  50. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/.claude-plugin/plugin.json +0 -0
  51. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/a11y-audit/SKILL.md +0 -0
  52. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/adversarial-review/SKILL.md +0 -0
  53. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/api-surface-extraction/SKILL.md +0 -0
  54. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/authz-matrix-check/SKILL.md +0 -0
  55. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/console-error-triage/SKILL.md +0 -0
  56. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/contract-test-generation/SKILL.md +0 -0
  57. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/dedupe-strategy/SKILL.md +0 -0
  58. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/environment-pinning/SKILL.md +0 -0
  59. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/error-taxonomy/SKILL.md +0 -0
  60. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/exploratory-ui-walk/SKILL.md +0 -0
  61. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/failing-test-authoring/SKILL.md +0 -0
  62. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/flake-detection/SKILL.md +0 -0
  63. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/form-state-probe/SKILL.md +0 -0
  64. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/minimal-diff-discipline/SKILL.md +0 -0
  65. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/openapi-diff/SKILL.md +0 -0
  66. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/ownership-resolution/SKILL.md +0 -0
  67. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/product-task-graph/SKILL.md +0 -0
  68. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/regression-risk-scoring/SKILL.md +0 -0
  69. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/regression-suite-selection/SKILL.md +0 -0
  70. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/repo-cartography/SKILL.md +0 -0
  71. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/repro-minimisation/SKILL.md +0 -0
  72. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/rollback-plan-authoring/SKILL.md +0 -0
  73. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/root-cause-vs-symptom/SKILL.md +0 -0
  74. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/routing-rules/SKILL.md +0 -0
  75. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/severity-rubric/SKILL.md +0 -0
  76. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/test-first-fix/SKILL.md +0 -0
  77. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/test-quality-audit/SKILL.md +0 -0
  78. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/ticket-writer/SKILL.md +0 -0
  79. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/verdict-reporting/SKILL.md +0 -0
  80. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/plugin/skills/verification-protocol/SKILL.md +0 -0
  81. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/ARBITER.md +0 -0
  82. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/CARTOGRAPHER.md +0 -0
  83. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/CLERK.md +0 -0
  84. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/CONDUIT.md +0 -0
  85. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/FORGE.md +0 -0
  86. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/MENDER.md +0 -0
  87. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/PROOF.md +0 -0
  88. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/SURFACE.md +0 -0
  89. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/VAULT.md +0 -0
  90. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/WARDEN.md +0 -0
  91. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/prompts/_shared.md +0 -0
  92. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/registry.py +0 -0
  93. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/runner.py +0 -0
  94. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/scorecard.py +0 -0
  95. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/sdk_compat.py +0 -0
  96. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/store.py +0 -0
  97. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/target.py +0 -0
  98. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/tasks.py +0 -0
  99. {qaas_python-0.2.1 → qaas_python-0.2.2}/src/qaas/trace.py +0 -0
  100. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/CODEOWNERS +0 -0
  101. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/Dockerfile +0 -0
  102. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/__init__.py +0 -0
  103. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/auth.py +0 -0
  104. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/config.py +0 -0
  105. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/db.py +0 -0
  106. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/errors.py +0 -0
  107. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/main.py +0 -0
  108. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/models.py +0 -0
  109. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/routes/__init__.py +0 -0
  110. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/routes/auth.py +0 -0
  111. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/routes/invoices.py +0 -0
  112. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/routes/orders.py +0 -0
  113. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/routes/stream.py +0 -0
  114. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/app/schemas.py +0 -0
  115. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/migrations/001_init.sql +0 -0
  116. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/pyproject.toml +0 -0
  117. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/api/seed/fixtures.sql +0 -0
  118. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/defects.yaml +0 -0
  119. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/docker-compose.yml +0 -0
  120. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/openapi.yaml +0 -0
  121. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/.gitignore +0 -0
  122. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/Dockerfile +0 -0
  123. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/index.html +0 -0
  124. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/package-lock.json +0 -0
  125. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/package.json +0 -0
  126. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/api.ts +0 -0
  127. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/components/Button.tsx +0 -0
  128. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/components/Layout.tsx +0 -0
  129. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/components/SearchInput.tsx +0 -0
  130. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/main.tsx +0 -0
  131. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/routes/CheckoutReview.tsx +0 -0
  132. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/routes/Login.tsx +0 -0
  133. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/routes/NewOrder.tsx +0 -0
  134. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/routes/OrderDetail.tsx +0 -0
  135. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/routes/OrdersList.tsx +0 -0
  136. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/src/styles.css +0 -0
  137. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/tsconfig.json +0 -0
  138. {qaas_python-0.2.1 → qaas_python-0.2.2}/target-app/web/vite.config.ts +0 -0
  139. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/adapters/test_github_vcs.py +0 -0
  140. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/adapters/test_jira_tracker.py +0 -0
  141. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/conftest.py +0 -0
  142. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/conftest.py +0 -0
  143. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_contract_diff.py +0 -0
  144. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_defect_memory.py +0 -0
  145. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_env_control.py +0 -0
  146. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_test_runner.py +0 -0
  147. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_tracker.py +0 -0
  148. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/mcp/test_vcs.py +0 -0
  149. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/support.py +0 -0
  150. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/target_app/test_seeded_defects.py +0 -0
  151. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_cli.py +0 -0
  152. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_conductor.py +0 -0
  153. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_config.py +0 -0
  154. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_discover.py +0 -0
  155. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_envelope.py +0 -0
  156. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_guardrails.py +0 -0
  157. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_hooks_and_skills.py +0 -0
  158. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_paths.py +0 -0
  159. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_prompt_overrides.py +0 -0
  160. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_registry.py +0 -0
  161. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_scorecard.py +0 -0
  162. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_skills_actually_load.py +0 -0
  163. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_store.py +0 -0
  164. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_target_profile_is_honoured.py +0 -0
  165. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_trace.py +0 -0
  166. {qaas_python-0.2.1 → qaas_python-0.2.2}/tests/test_user_mcp_servers.py +0 -0
@@ -19,3 +19,6 @@ dist/
19
19
 
20
20
  # Agent evidence screenshots land here because put_artifact takes only text.
21
21
  target-app/*.png
22
+
23
+ # Personal notes, not published.
24
+ tutorial/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: qaas-python
3
- Version: 0.2.1
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.1"
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/", "tutorial/",
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)