agentic-harness 0.2.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.
Files changed (214) hide show
  1. agentic_harness-0.2.0/.agent-harness.yml +17 -0
  2. agentic_harness-0.2.0/.github/workflows/ci.yml +59 -0
  3. agentic_harness-0.2.0/.github/workflows/publish.yml +71 -0
  4. agentic_harness-0.2.0/.gitignore +136 -0
  5. agentic_harness-0.2.0/.gitleaks.toml +5 -0
  6. agentic_harness-0.2.0/.pre-commit-config.yaml +16 -0
  7. agentic_harness-0.2.0/.yamllint.yml +11 -0
  8. agentic_harness-0.2.0/CLAUDE.md +118 -0
  9. agentic_harness-0.2.0/CONTRIBUTING.md +181 -0
  10. agentic_harness-0.2.0/LICENSE +21 -0
  11. agentic_harness-0.2.0/Makefile +24 -0
  12. agentic_harness-0.2.0/PKG-INFO +310 -0
  13. agentic_harness-0.2.0/PLANS.md +55 -0
  14. agentic_harness-0.2.0/README.md +285 -0
  15. agentic_harness-0.2.0/TODO.md +32 -0
  16. agentic_harness-0.2.0/docs/plans/2026-03-25-js-stack-and-universal-fixes.md +1804 -0
  17. agentic_harness-0.2.0/docs/plans/2026-03-25-mvp.md +830 -0
  18. agentic_harness-0.2.0/docs/plans/2026-03-25-refactor-stacks.md +128 -0
  19. agentic_harness-0.2.0/docs/plans/2026-03-26-full-restructure.md +358 -0
  20. agentic_harness-0.2.0/docs/plans/2026-03-26-init-as-harness-linter.md +271 -0
  21. agentic_harness-0.2.0/docs/plans/2026-03-26-init-setup-checks.md +1376 -0
  22. agentic_harness-0.2.0/docs/plans/2026-03-26-v02-cli-simplification.md +410 -0
  23. agentic_harness-0.2.0/docs/plans/2026-03-26-v1-vision-declarative-harness.md +85 -0
  24. agentic_harness-0.2.0/docs/superpowers/plans/2026-03-26-gitignore-enforcement.md +848 -0
  25. agentic_harness-0.2.0/docs/superpowers/plans/2026-03-27-claudemd-audit-and-security-audit.md +2015 -0
  26. agentic_harness-0.2.0/docs/superpowers/plans/2026-03-29-i0194-dockerfile-discovery-and-conftest-exceptions.md +1658 -0
  27. agentic_harness-0.2.0/docs/superpowers/plans/2026-03-29-skill-product-experience.md +714 -0
  28. agentic_harness-0.2.0/docs/superpowers/specs/2026-03-26-gitignore-enforcement-design.md +107 -0
  29. agentic_harness-0.2.0/docs/superpowers/specs/2026-03-29-i0194-dockerfile-discovery-and-conftest-exceptions.md +125 -0
  30. agentic_harness-0.2.0/pyproject.toml +48 -0
  31. agentic_harness-0.2.0/scripts/update-gitignore-templates.sh +20 -0
  32. agentic_harness-0.2.0/skills/agent-harness/SKILL.md +358 -0
  33. agentic_harness-0.2.0/skills/agent-harness/docker-guidance.md +171 -0
  34. agentic_harness-0.2.0/skills/agent-harness/monorepo-guidance.md +19 -0
  35. agentic_harness-0.2.0/skills/agent-harness/python-guidance.md +35 -0
  36. agentic_harness-0.2.0/src/agent_harness/__init__.py +6 -0
  37. agentic_harness-0.2.0/src/agent_harness/cli.py +179 -0
  38. agentic_harness-0.2.0/src/agent_harness/config.py +57 -0
  39. agentic_harness-0.2.0/src/agent_harness/conftest.py +51 -0
  40. agentic_harness-0.2.0/src/agent_harness/detect.py +54 -0
  41. agentic_harness-0.2.0/src/agent_harness/exclusions.py +64 -0
  42. agentic_harness-0.2.0/src/agent_harness/fix.py +36 -0
  43. agentic_harness-0.2.0/src/agent_harness/git_files.py +75 -0
  44. agentic_harness-0.2.0/src/agent_harness/init/__init__.py +0 -0
  45. agentic_harness-0.2.0/src/agent_harness/init/diagnostic.py +69 -0
  46. agentic_harness-0.2.0/src/agent_harness/init/scaffold.py +169 -0
  47. agentic_harness-0.2.0/src/agent_harness/init/templates.py +141 -0
  48. agentic_harness-0.2.0/src/agent_harness/lint.py +38 -0
  49. agentic_harness-0.2.0/src/agent_harness/policies/compose/configs.rego +33 -0
  50. agentic_harness-0.2.0/src/agent_harness/policies/compose/configs_test.rego +23 -0
  51. agentic_harness-0.2.0/src/agent_harness/policies/compose/escaping.rego +72 -0
  52. agentic_harness-0.2.0/src/agent_harness/policies/compose/escaping_test.rego +46 -0
  53. agentic_harness-0.2.0/src/agent_harness/policies/compose/hostname.rego +63 -0
  54. agentic_harness-0.2.0/src/agent_harness/policies/compose/hostname_test.rego +69 -0
  55. agentic_harness-0.2.0/src/agent_harness/policies/compose/images.rego +108 -0
  56. agentic_harness-0.2.0/src/agent_harness/policies/compose/images_test.rego +72 -0
  57. agentic_harness-0.2.0/src/agent_harness/policies/compose/services.rego +95 -0
  58. agentic_harness-0.2.0/src/agent_harness/policies/compose/services_test.rego +75 -0
  59. agentic_harness-0.2.0/src/agent_harness/policies/compose/volumes.rego +58 -0
  60. agentic_harness-0.2.0/src/agent_harness/policies/compose/volumes_test.rego +39 -0
  61. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/base_image.rego +45 -0
  62. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/base_image_test.rego +44 -0
  63. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/cache.rego +48 -0
  64. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/cache_test.rego +44 -0
  65. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/healthcheck.rego +38 -0
  66. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/healthcheck_test.rego +33 -0
  67. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/layers.rego +100 -0
  68. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/layers_test.rego +55 -0
  69. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/secrets.rego +88 -0
  70. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/secrets_test.rego +47 -0
  71. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/user.rego +39 -0
  72. agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/user_test.rego +33 -0
  73. agentic_harness-0.2.0/src/agent_harness/policies/dokploy/traefik.rego +72 -0
  74. agentic_harness-0.2.0/src/agent_harness/policies/dokploy/traefik_test.rego +90 -0
  75. agentic_harness-0.2.0/src/agent_harness/policies/gitignore/secrets.rego +64 -0
  76. agentic_harness-0.2.0/src/agent_harness/policies/gitignore/secrets_test.rego +62 -0
  77. agentic_harness-0.2.0/src/agent_harness/policies/javascript/package.rego +61 -0
  78. agentic_harness-0.2.0/src/agent_harness/policies/javascript/package_test.rego +66 -0
  79. agentic_harness-0.2.0/src/agent_harness/policies/python/coverage.rego +43 -0
  80. agentic_harness-0.2.0/src/agent_harness/policies/python/coverage_test.rego +50 -0
  81. agentic_harness-0.2.0/src/agent_harness/policies/python/pytest.rego +56 -0
  82. agentic_harness-0.2.0/src/agent_harness/policies/python/pytest_test.rego +41 -0
  83. agentic_harness-0.2.0/src/agent_harness/policies/python/ruff.rego +69 -0
  84. agentic_harness-0.2.0/src/agent_harness/policies/python/ruff_test.rego +47 -0
  85. agentic_harness-0.2.0/src/agent_harness/policies/python/test_isolation.rego +31 -0
  86. agentic_harness-0.2.0/src/agent_harness/policies/python/test_isolation_test.rego +20 -0
  87. agentic_harness-0.2.0/src/agent_harness/preset.py +47 -0
  88. agentic_harness-0.2.0/src/agent_harness/presets/__init__.py +1 -0
  89. agentic_harness-0.2.0/src/agent_harness/presets/docker/__init__.py +60 -0
  90. agentic_harness-0.2.0/src/agent_harness/presets/docker/conftest_compose_check.py +51 -0
  91. agentic_harness-0.2.0/src/agent_harness/presets/docker/conftest_dockerfile_check.py +76 -0
  92. agentic_harness-0.2.0/src/agent_harness/presets/docker/detect.py +20 -0
  93. agentic_harness-0.2.0/src/agent_harness/presets/docker/hadolint_check.py +51 -0
  94. agentic_harness-0.2.0/src/agent_harness/presets/docker/templates.py +46 -0
  95. agentic_harness-0.2.0/src/agent_harness/presets/dokploy/__init__.py +38 -0
  96. agentic_harness-0.2.0/src/agent_harness/presets/dokploy/conftest_dokploy_check.py +51 -0
  97. agentic_harness-0.2.0/src/agent_harness/presets/dokploy/detect.py +16 -0
  98. agentic_harness-0.2.0/src/agent_harness/presets/javascript/__init__.py +56 -0
  99. agentic_harness-0.2.0/src/agent_harness/presets/javascript/biome_check.py +58 -0
  100. agentic_harness-0.2.0/src/agent_harness/presets/javascript/conftest_package_check.py +34 -0
  101. agentic_harness-0.2.0/src/agent_harness/presets/javascript/detect.py +10 -0
  102. agentic_harness-0.2.0/src/agent_harness/presets/javascript/fix.py +23 -0
  103. agentic_harness-0.2.0/src/agent_harness/presets/javascript/templates.py +39 -0
  104. agentic_harness-0.2.0/src/agent_harness/presets/javascript/type_check.py +75 -0
  105. agentic_harness-0.2.0/src/agent_harness/presets/python/__init__.py +51 -0
  106. agentic_harness-0.2.0/src/agent_harness/presets/python/conftest_check.py +18 -0
  107. agentic_harness-0.2.0/src/agent_harness/presets/python/detect.py +10 -0
  108. agentic_harness-0.2.0/src/agent_harness/presets/python/fix.py +36 -0
  109. agentic_harness-0.2.0/src/agent_harness/presets/python/ruff_check.py +47 -0
  110. agentic_harness-0.2.0/src/agent_harness/presets/python/setup_check.py +168 -0
  111. agentic_harness-0.2.0/src/agent_harness/presets/python/templates.py +225 -0
  112. agentic_harness-0.2.0/src/agent_harness/presets/python/ty_check.py +32 -0
  113. agentic_harness-0.2.0/src/agent_harness/presets/universal/__init__.py +96 -0
  114. agentic_harness-0.2.0/src/agent_harness/presets/universal/claudemd_setup.py +64 -0
  115. agentic_harness-0.2.0/src/agent_harness/presets/universal/conftest_gitignore_check.py +40 -0
  116. agentic_harness-0.2.0/src/agent_harness/presets/universal/conftest_json_check.py +91 -0
  117. agentic_harness-0.2.0/src/agent_harness/presets/universal/file_length_check.py +85 -0
  118. agentic_harness-0.2.0/src/agent_harness/presets/universal/gitignore_setup.py +167 -0
  119. agentic_harness-0.2.0/src/agent_harness/presets/universal/gitignore_tracked_check.py +59 -0
  120. agentic_harness-0.2.0/src/agent_harness/presets/universal/gitignore_tracked_fix.py +37 -0
  121. agentic_harness-0.2.0/src/agent_harness/presets/universal/precommit_check.py +82 -0
  122. agentic_harness-0.2.0/src/agent_harness/presets/universal/templates.py +49 -0
  123. agentic_harness-0.2.0/src/agent_harness/presets/universal/yamllint_check.py +95 -0
  124. agentic_harness-0.2.0/src/agent_harness/registry.py +10 -0
  125. agentic_harness-0.2.0/src/agent_harness/runner.py +73 -0
  126. agentic_harness-0.2.0/src/agent_harness/security/__init__.py +0 -0
  127. agentic_harness-0.2.0/src/agent_harness/security/audit.py +36 -0
  128. agentic_harness-0.2.0/src/agent_harness/security/config.py +48 -0
  129. agentic_harness-0.2.0/src/agent_harness/security/display.py +60 -0
  130. agentic_harness-0.2.0/src/agent_harness/security/gitleaks_scanner.py +100 -0
  131. agentic_harness-0.2.0/src/agent_harness/security/models.py +76 -0
  132. agentic_harness-0.2.0/src/agent_harness/security/osv_scanner.py +150 -0
  133. agentic_harness-0.2.0/src/agent_harness/setup_check.py +21 -0
  134. agentic_harness-0.2.0/src/agent_harness/templates/gitignore/Linux.gitignore +16 -0
  135. agentic_harness-0.2.0/src/agent_harness/templates/gitignore/Node.gitignore +144 -0
  136. agentic_harness-0.2.0/src/agent_harness/templates/gitignore/Python.gitignore +216 -0
  137. agentic_harness-0.2.0/src/agent_harness/templates/gitignore/SOURCE.md +6 -0
  138. agentic_harness-0.2.0/src/agent_harness/templates/gitignore/Windows.gitignore +24 -0
  139. agentic_harness-0.2.0/src/agent_harness/templates/gitignore/macOS.gitignore +25 -0
  140. agentic_harness-0.2.0/src/agent_harness/workspace.py +13 -0
  141. agentic_harness-0.2.0/tests/__init__.py +0 -0
  142. agentic_harness-0.2.0/tests/fixtures/compose/bad_bare_dollar.yml +13 -0
  143. agentic_harness-0.2.0/tests/fixtures/compose/bad_build_directive.yml +6 -0
  144. agentic_harness-0.2.0/tests/fixtures/compose/bad_mutable_tag_no_pull.yml +11 -0
  145. agentic_harness-0.2.0/tests/fixtures/compose/bad_no_healthcheck.yml +6 -0
  146. agentic_harness-0.2.0/tests/fixtures/compose/bad_no_hostname.yml +14 -0
  147. agentic_harness-0.2.0/tests/fixtures/compose/bad_no_restart.yml +10 -0
  148. agentic_harness-0.2.0/tests/fixtures/compose/bad_port_binding.yml +13 -0
  149. agentic_harness-0.2.0/tests/fixtures/compose/good_escaped_dollar.yml +14 -0
  150. agentic_harness-0.2.0/tests/fixtures/compose/good_full.yml +41 -0
  151. agentic_harness-0.2.0/tests/fixtures/compose/good_hostname.yml +15 -0
  152. agentic_harness-0.2.0/tests/fixtures/compose/good_one_shot_exempt.yml +18 -0
  153. agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_alpine_node.Dockerfile +9 -0
  154. agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_alpine_python.Dockerfile +9 -0
  155. agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_copy_before_deps.Dockerfile +8 -0
  156. agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_no_cache_mount.Dockerfile +9 -0
  157. agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_no_healthcheck.Dockerfile +8 -0
  158. agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_no_user.Dockerfile +8 -0
  159. agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_secret_in_arg.Dockerfile +10 -0
  160. agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_secret_in_env.Dockerfile +10 -0
  161. agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_src_before_deps.Dockerfile +9 -0
  162. agentic_harness-0.2.0/tests/fixtures/dockerfile/good_alpine_go.Dockerfile +10 -0
  163. agentic_harness-0.2.0/tests/fixtures/dockerfile/good_cache_mount.Dockerfile +9 -0
  164. agentic_harness-0.2.0/tests/fixtures/dockerfile/good_complete.Dockerfile +14 -0
  165. agentic_harness-0.2.0/tests/fixtures/dockerfile/good_layer_order.Dockerfile +10 -0
  166. agentic_harness-0.2.0/tests/fixtures/dockerfile/good_multistage_copy.Dockerfile +14 -0
  167. agentic_harness-0.2.0/tests/presets/__init__.py +0 -0
  168. agentic_harness-0.2.0/tests/presets/docker/__init__.py +0 -0
  169. agentic_harness-0.2.0/tests/presets/docker/test_conftest_compose_check.py +7 -0
  170. agentic_harness-0.2.0/tests/presets/docker/test_conftest_dockerfile_check.py +89 -0
  171. agentic_harness-0.2.0/tests/presets/docker/test_find_dockerfiles.py +51 -0
  172. agentic_harness-0.2.0/tests/presets/docker/test_hadolint_check.py +8 -0
  173. agentic_harness-0.2.0/tests/presets/dokploy/__init__.py +0 -0
  174. agentic_harness-0.2.0/tests/presets/dokploy/test_conftest_dokploy_check.py +7 -0
  175. agentic_harness-0.2.0/tests/presets/dokploy/test_detect.py +41 -0
  176. agentic_harness-0.2.0/tests/presets/javascript/__init__.py +0 -0
  177. agentic_harness-0.2.0/tests/presets/javascript/test_biome_check.py +46 -0
  178. agentic_harness-0.2.0/tests/presets/javascript/test_conftest_package_check.py +7 -0
  179. agentic_harness-0.2.0/tests/presets/javascript/test_detect.py +20 -0
  180. agentic_harness-0.2.0/tests/presets/javascript/test_type_check.py +49 -0
  181. agentic_harness-0.2.0/tests/presets/python/__init__.py +0 -0
  182. agentic_harness-0.2.0/tests/presets/python/test_detect.py +15 -0
  183. agentic_harness-0.2.0/tests/presets/python/test_ruff_check.py +8 -0
  184. agentic_harness-0.2.0/tests/presets/python/test_setup.py +163 -0
  185. agentic_harness-0.2.0/tests/presets/universal/__init__.py +0 -0
  186. agentic_harness-0.2.0/tests/presets/universal/conftest.py +20 -0
  187. agentic_harness-0.2.0/tests/presets/universal/test_claudemd_setup.py +52 -0
  188. agentic_harness-0.2.0/tests/presets/universal/test_conftest_gitignore_check.py +32 -0
  189. agentic_harness-0.2.0/tests/presets/universal/test_conftest_json_check.py +51 -0
  190. agentic_harness-0.2.0/tests/presets/universal/test_file_length_check.py +50 -0
  191. agentic_harness-0.2.0/tests/presets/universal/test_gitignore_setup.py +119 -0
  192. agentic_harness-0.2.0/tests/presets/universal/test_gitignore_tracked_check.py +103 -0
  193. agentic_harness-0.2.0/tests/presets/universal/test_gitignore_tracked_fix.py +52 -0
  194. agentic_harness-0.2.0/tests/presets/universal/test_precommit_check.py +101 -0
  195. agentic_harness-0.2.0/tests/presets/universal/test_yamllint_check.py +51 -0
  196. agentic_harness-0.2.0/tests/security/__init__.py +0 -0
  197. agentic_harness-0.2.0/tests/security/test_audit.py +119 -0
  198. agentic_harness-0.2.0/tests/security/test_display.py +52 -0
  199. agentic_harness-0.2.0/tests/security/test_gitleaks_scanner.py +90 -0
  200. agentic_harness-0.2.0/tests/security/test_models.py +126 -0
  201. agentic_harness-0.2.0/tests/security/test_osv_scanner.py +170 -0
  202. agentic_harness-0.2.0/tests/security/test_security_config.py +71 -0
  203. agentic_harness-0.2.0/tests/test_cli.py +40 -0
  204. agentic_harness-0.2.0/tests/test_config.py +92 -0
  205. agentic_harness-0.2.0/tests/test_detect.py +142 -0
  206. agentic_harness-0.2.0/tests/test_diagnostic.py +108 -0
  207. agentic_harness-0.2.0/tests/test_exclusions.py +33 -0
  208. agentic_harness-0.2.0/tests/test_git_files.py +95 -0
  209. agentic_harness-0.2.0/tests/test_init.py +97 -0
  210. agentic_harness-0.2.0/tests/test_lint_all.py +35 -0
  211. agentic_harness-0.2.0/tests/test_runner.py +18 -0
  212. agentic_harness-0.2.0/tests/test_setup.py +39 -0
  213. agentic_harness-0.2.0/tests/test_workspace.py +48 -0
  214. agentic_harness-0.2.0/uv.lock +211 -0
@@ -0,0 +1,17 @@
1
+ # AI Harness configuration
2
+ # Detected stacks: python
3
+ stacks: [python]
4
+
5
+ # exclude:
6
+ # - _archive/
7
+ # - vendor/
8
+
9
+ # python:
10
+ # coverage_threshold: 95
11
+ # line_length: 140
12
+
13
+ # javascript:
14
+ # coverage_threshold: 80
15
+
16
+ # docker:
17
+ # own_image_prefix: "ghcr.io/myorg/"
@@ -0,0 +1,59 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [master]
7
+
8
+ jobs:
9
+ check:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - uses: astral-sh/setup-uv@v4
15
+ with:
16
+ version: "latest"
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+
22
+ - name: Install tools
23
+ run: |
24
+ uv sync
25
+ uv tool install -e .
26
+
27
+ # Install external tools
28
+ # conftest
29
+ CONFTEST_VERSION=0.56.0
30
+ curl -sL "https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz" | tar xz -C /usr/local/bin conftest
31
+
32
+ # hadolint
33
+ HADOLINT_VERSION=2.12.0
34
+ curl -sL "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-x86_64" -o /usr/local/bin/hadolint
35
+ chmod +x /usr/local/bin/hadolint
36
+
37
+ # yamllint
38
+ uv tool install yamllint
39
+
40
+ # gitleaks
41
+ GITLEAKS_VERSION=8.21.2
42
+ curl -sL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | tar xz -C /usr/local/bin gitleaks
43
+
44
+ # osv-scanner
45
+ OSV_VERSION=1.9.1
46
+ curl -sL "https://github.com/google/osv-scanner/releases/download/v${OSV_VERSION}/osv-scanner_linux_amd64" -o /usr/local/bin/osv-scanner
47
+ chmod +x /usr/local/bin/osv-scanner
48
+
49
+ - name: Lint
50
+ run: agent-harness lint
51
+
52
+ - name: Test
53
+ run: uv run pytest tests/ -v
54
+
55
+ - name: Rego tests
56
+ run: conftest verify -p src/agent_harness/policies/ --no-color
57
+
58
+ - name: Security audit
59
+ run: agent-harness security-audit
@@ -0,0 +1,71 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ check:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - uses: astral-sh/setup-uv@v4
15
+ with:
16
+ version: "latest"
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+
22
+ - name: Install tools
23
+ run: |
24
+ uv sync
25
+ uv tool install -e .
26
+
27
+ CONFTEST_VERSION=0.56.0
28
+ curl -sL "https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz" | tar xz -C /usr/local/bin conftest
29
+
30
+ HADOLINT_VERSION=2.12.0
31
+ curl -sL "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-x86_64" -o /usr/local/bin/hadolint
32
+ chmod +x /usr/local/bin/hadolint
33
+
34
+ uv tool install yamllint
35
+
36
+ GITLEAKS_VERSION=8.21.2
37
+ curl -sL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | tar xz -C /usr/local/bin gitleaks
38
+
39
+ OSV_VERSION=1.9.1
40
+ curl -sL "https://github.com/google/osv-scanner/releases/download/v${OSV_VERSION}/osv-scanner_linux_amd64" -o /usr/local/bin/osv-scanner
41
+ chmod +x /usr/local/bin/osv-scanner
42
+
43
+ - name: Full quality gate
44
+ run: |
45
+ agent-harness lint
46
+ uv run pytest tests/ -v
47
+ conftest verify -p src/agent_harness/policies/ --no-color
48
+ agent-harness security-audit
49
+
50
+ publish:
51
+ needs: check
52
+ runs-on: ubuntu-latest
53
+ environment: pypi
54
+ permissions:
55
+ id-token: write
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+
59
+ - uses: astral-sh/setup-uv@v4
60
+ with:
61
+ version: "latest"
62
+
63
+ - uses: actions/setup-python@v5
64
+ with:
65
+ python-version: "3.12"
66
+
67
+ - name: Build
68
+ run: uv build
69
+
70
+ - name: Publish to PyPI
71
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,136 @@
1
+ .env
2
+ __pycache__/
3
+ *.pyc
4
+ .venv/
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ .coverage
9
+ coverage.xml
10
+ .worktrees/
11
+ .DS_Store
12
+
13
+ # Added by agent-harness
14
+ $RECYCLE.BIN/
15
+ *$py.class
16
+ *.aof
17
+ *.cab
18
+ *.cover
19
+ *.egg
20
+ *.lnk
21
+ *.log
22
+ *.manifest
23
+ *.mo
24
+ *.msi
25
+ *.msix
26
+ *.msm
27
+ *.msp
28
+ *.pid
29
+ *.pot
30
+ *.py.cover
31
+ *.py[codz]
32
+ *.rdb
33
+ *.sage.py
34
+ *.so
35
+ *.spec
36
+ *.stackdump
37
+ *~
38
+ .AppleDB
39
+ .AppleDesktop
40
+ .AppleDouble
41
+ .DocumentRevisions-V100
42
+ .LSOverride
43
+ .Python
44
+ .Spotlight-V100
45
+ .TemporaryItems
46
+ .Trash-*
47
+ .Trashes
48
+ .VolumeIcon.icns
49
+ ._*
50
+ .abstra/
51
+ .apdisk
52
+ .cache
53
+ .com.apple.timemachine.donotpresent
54
+ .coverage.*
55
+ .directory
56
+ .dmypy.json
57
+ .eggs/
58
+ .envrc
59
+ .fseventsd
60
+ .fuse_hidden*
61
+ .hypothesis/
62
+ .installed.cfg
63
+ .ipynb_checkpoints
64
+ .mypy_cache/
65
+ .nfs*
66
+ .nox/
67
+ .pdm-build/
68
+ .pdm-python
69
+ .pixi
70
+ .pybuilder/
71
+ .pypirc
72
+ .pyre/
73
+ .pytest_cache/
74
+ .pytype/
75
+ .ropeproject
76
+ .ruff_cache/
77
+ .scrapy
78
+ .spyderproject
79
+ .spyproject
80
+ .streamlit/secrets.toml
81
+ .tox/
82
+ .venv
83
+ .webassets-cache
84
+ /site
85
+ ENV/
86
+ Icon[
87
+ MANIFEST
88
+ Network Trash Folder
89
+ Temporary Items
90
+ Thumbs.db
91
+ Thumbs.db:encryptable
92
+ [Dd]esktop.ini
93
+ ]
94
+ __MACOSX/
95
+ __marimo__/
96
+ __pypackages__/
97
+ activemq-data/
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+ cover/
101
+ cython_debug/
102
+ db.sqlite3
103
+ db.sqlite3-journal
104
+ develop-eggs/
105
+ dmypy.json
106
+ docs/_build/
107
+ downloads/
108
+ eggs/
109
+ ehthumbs.db
110
+ ehthumbs_vista.db
111
+ env.bak/
112
+ env/
113
+ htmlcov/
114
+ instance/
115
+ ipython_config.py
116
+ lib/
117
+ lib64/
118
+ local_settings.py
119
+ marimo/_lsp/
120
+ marimo/_static/
121
+ mnesia/
122
+ nohup.out
123
+ nosetests.xml
124
+ parts/
125
+ pip-delete-this-directory.txt
126
+ pip-log.txt
127
+ profile_default/
128
+ rabbitmq-data/
129
+ rabbitmq/
130
+ sdist/
131
+ share/python-wheels/
132
+ target/
133
+ var/
134
+ venv.bak/
135
+ venv/
136
+ wheels/
@@ -0,0 +1,5 @@
1
+ [allowlist]
2
+ description = "Allow test fixtures with intentional fake secrets"
3
+ paths = [
4
+ '''tests/fixtures/.*''',
5
+ ]
@@ -0,0 +1,16 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: harness-fix
5
+ name: auto-fix
6
+ entry: agent-harness fix
7
+ language: system
8
+ pass_filenames: false
9
+ always_run: true
10
+
11
+ - id: harness-lint
12
+ name: agent-harness lint
13
+ entry: agent-harness lint
14
+ language: system
15
+ pass_filenames: false
16
+ always_run: true
@@ -0,0 +1,11 @@
1
+ extends: default
2
+ ignore: |
3
+ .venv/
4
+ node_modules/
5
+ rules:
6
+ line-length:
7
+ max: 200
8
+ truthy:
9
+ check-keys: false
10
+ document-start: disable
11
+ indentation: disable
@@ -0,0 +1,118 @@
1
+ # agent-harness
2
+
3
+ Deterministic quality gates for AI-assisted development. This project IS a harness — it enforces its own rules.
4
+
5
+ ## Dev Commands
6
+
7
+ ```bash
8
+ make lint # agent-harness lint (runs all checks)
9
+ make fix # agent-harness fix (auto-fix, then lint)
10
+ make test # pytest + conftest verify (all tests)
11
+ make security-audit # check deps + secrets in working dir (fast)
12
+ make check # full gate: lint + test + security-audit
13
+ agent-harness security-audit-history # deep scan git history for leaked secrets (run once)
14
+ ```
15
+
16
+ Install dev deps: `uv sync`
17
+
18
+ ## Workflow
19
+
20
+ Pre-commit hooks run `agent-harness fix` and `agent-harness lint` automatically on every commit.
21
+ Before declaring work done, always run `make check` — it's the full quality gate.
22
+
23
+
24
+ ## Setup
25
+
26
+ ```bash
27
+ uv tool install -e . # install CLI globally from source
28
+ uv sync # install dev deps (ruff, ty, pytest)
29
+ agent-harness lint # verify everything passes
30
+ ```
31
+
32
+ ## Architecture
33
+
34
+ ```
35
+ src/agent_harness/
36
+ cli.py — Click CLI: detect, init, lint, fix, security-audit (thin — delegates)
37
+ config.py — Dict-based config from .agent-harness.yml
38
+ runner.py — run_check(), CheckResult, tool_available()
39
+ conftest.py — Shared conftest runner (used by all Rego checks)
40
+ exclusions.py — File exclusion patterns
41
+ workspace.py — Discover subproject roots
42
+ preset.py — Preset base class + ToolInfo/PresetInfo
43
+ registry.py — Explicit preset registration (PRESETS + UNIVERSAL)
44
+ detect.py — Thin orchestrator: for preset in PRESETS: preset.detect()
45
+ lint.py — Thin orchestrator: for preset in PRESETS: preset.run_checks()
46
+ fix.py — Thin orchestrator: for preset in PRESETS: preset.run_fix()
47
+ init/ — Scaffolding (reads preset.get_info())
48
+ presets/
49
+ universal/ — Always runs: yamllint, gitignore, JSON, file length
50
+ python/ — ruff, ty, conftest on pyproject.toml
51
+ javascript/ — Biome, framework type checker, conftest on package.json
52
+ docker/ — hadolint, conftest on Dockerfile + compose
53
+ dokploy/ — conftest for Traefik/Dokploy conventions
54
+ security/ — osv-scanner + gitleaks runners, policy engine, CVE ignore
55
+ policies/ — Rego policies (bundled). Each has WHAT/WHY/FIX.
56
+
57
+ skills/agent-harness/ — Claude Code plugin (SKILL.md + guidance docs)
58
+ ```
59
+
60
+ ## Adding a new preset
61
+
62
+ 1. Create `presets/<name>/` with `__init__.py` implementing `Preset`
63
+ 2. Add individual check files (one per tool)
64
+ 3. Add `<Name>Preset()` to `registry.py`
65
+ 4. Add Rego policies to `policies/<name>/` if needed
66
+
67
+ ## Conventions
68
+
69
+ - Each preset implements: `detect()`, `run_checks()`, `run_fix()`, `run_setup()`, `get_info()`
70
+ - One check per file, with WHAT/WHY/WITHOUT IT/FIX/REQUIRES docstring
71
+ - One Rego policy per file, with `_test.rego` sibling
72
+ - All conftest checks use shared `conftest.py` (never local `_run_conftest`)
73
+ - Tool fallback: `shutil.which()` → `uv run` (Python) or `npx` (JS)
74
+
75
+ ## Policy Design Strategy
76
+
77
+ Every check belongs in exactly one place. The boundary:
78
+
79
+ **"Would any reasonable person agree this is broken?"**
80
+ - YES → lint (Rego `deny` rule in `policies/`)
81
+ - Debatable → init (Python setup check in `presets/*/setup.py`)
82
+
83
+ ### Lint (Rego, every commit)
84
+ - Only `deny` rules. No `warn`.
85
+ - Checks that gates EXIST and aren't objectively broken.
86
+ - Examples: `--strict-markers` missing, `--cov-fail-under` missing, threshold < 30%
87
+
88
+ ### Init (Python, on-demand)
89
+ - `SetupIssue` with severity `critical` (fixable) or `recommendation`.
90
+ - Checks configuration QUALITY. Can auto-fix.
91
+ - Examples: threshold = 50% (recommend 90-95%), missing `-v` flag
92
+
93
+ ### Skill (agent guidance, context-dependent)
94
+ - Actions that require judgment, context, or reading intent.
95
+ - The skill tells the agent WHAT to evaluate and WHY, but the agent decides HOW.
96
+ - Examples: reorganize .gitignore (needs to know which patterns are stale),
97
+ audit CLAUDE.md (needs project context), replace redundant Makefile targets
98
+ (needs to understand what the target was for)
99
+
100
+ ### The boundary: init does, skill guides
101
+ Init must be safe to run blindly (`--apply` never breaks a project).
102
+ If an action could destroy user intent (rewriting .gitignore, editing CLAUDE.md),
103
+ init does the safe subset (deduplicated append) and the skill guides the agent
104
+ to do the rest (full cleanup, reorganization).
105
+
106
+ ### Same topic, all three places
107
+ A single topic (e.g., .gitignore completeness) can have:
108
+ - Lint Rego: "are generated files tracked?" (objectively broken)
109
+ - Init Python: "append missing patterns grouped by category" (safe, mechanical)
110
+ - Skill: "review and clean up the full .gitignore — remove stale patterns, reorganize" (judgment)
111
+
112
+ ## Never
113
+
114
+ - Never embed tool binaries — require them installed externally
115
+ - Never run checks in Docker — must be <500ms local
116
+ - Never duplicate `_run_conftest` — use `agent_harness.conftest.run_conftest()`
117
+ - Never truncate lint/test output with `| tail` or `| head` — output is already optimized
118
+ - Never skip `make check` before declaring a task complete
@@ -0,0 +1,181 @@
1
+ # Contributing to Agent Harness
2
+
3
+ Agent Harness enforces its own rules. We use agent-harness to develop agent-harness.
4
+
5
+ ## Development setup
6
+
7
+ ```bash
8
+ git clone https://github.com/agentic-eng/agent-harness
9
+ cd agent-harness
10
+ uv sync # install dev deps
11
+ uv tool install -e . # install CLI globally from source
12
+ agent-harness lint # verify everything passes
13
+ ```
14
+
15
+ ## Quality gate
16
+
17
+ Before every commit (enforced by pre-commit hooks):
18
+
19
+ ```bash
20
+ make check # lint + test + security-audit
21
+ ```
22
+
23
+ This runs:
24
+ - `agent-harness lint` — 10 checks (ruff, ty, conftest, yamllint, etc.)
25
+ - `uv run pytest tests/ -v` — 201 Python tests
26
+ - `conftest verify` — 109 Rego policy tests
27
+ - `agent-harness security-audit` — dependency + secret scanning
28
+
29
+ ## Adding a new Rego policy
30
+
31
+ One file per concern, one concern per file.
32
+
33
+ ### 1. Decide: is it deterministic?
34
+
35
+ The harness only contains deterministic controls — tools that produce a pass/fail verdict without human judgment. If a rule requires interpretation, it's guidance (document it in the skill), not a policy.
36
+
37
+ ### 2. Choose the right directory
38
+
39
+ - `src/agent_harness/policies/dockerfile/` — Dockerfile rules
40
+ - `src/agent_harness/policies/compose/` — Docker Compose rules
41
+ - `src/agent_harness/policies/dokploy/` — Dokploy/Traefik rules
42
+ - `src/agent_harness/policies/python/` — pyproject.toml / Python config rules
43
+ - `src/agent_harness/policies/gitignore/` — .gitignore rules
44
+
45
+ ### 3. Write the .rego file
46
+
47
+ ```rego
48
+ package dockerfile.my_concern
49
+
50
+ # One-line description.
51
+ # Why this matters for AI agents.
52
+ #
53
+ # Input: <describe the parsed data structure>
54
+
55
+ import rego.v1
56
+
57
+ default _exceptions := []
58
+
59
+ _exceptions := data.exceptions if {
60
+ data.exceptions
61
+ }
62
+
63
+ deny contains msg if {
64
+ not "dockerfile.my_concern" in _exceptions
65
+ # your logic here
66
+ msg := "Actionable error message — what's wrong and how to fix it"
67
+ }
68
+ ```
69
+
70
+ **Conventions:**
71
+ - One file per concern (e.g., `layers.rego`, `cache.rego`)
72
+ - Package name matches directory + filename: `policies/dockerfile/layers.rego` → `package dockerfile.layers`
73
+ - Only `deny` rules. No `warn`.
74
+ - Error messages must be actionable — tell the agent what to do
75
+ - WHAT/WHY/WITHOUT IT/FIX comment block at top
76
+ - Always include `_exceptions` guard so policies can be skipped via `conftest_skip`
77
+
78
+ ### 4. Write the test file
79
+
80
+ Every policy needs a `_test.rego` sibling with at least:
81
+
82
+ ```rego
83
+ package dockerfile.my_concern_test
84
+
85
+ import rego.v1
86
+ import data.dockerfile.my_concern
87
+
88
+ test_bad_input_fires if {
89
+ my_concern.deny with input as [...]
90
+ }
91
+
92
+ test_good_input_passes if {
93
+ count(my_concern.deny) == 0 with input as [...]
94
+ }
95
+
96
+ test_exception_skips if {
97
+ count(my_concern.deny) == 0 with input as [...]
98
+ with data.exceptions as ["dockerfile.my_concern"]
99
+ }
100
+ ```
101
+
102
+ ### 5. Write fixture files
103
+
104
+ Place in `tests/fixtures/<directory>/`:
105
+ - `bad_*.Dockerfile` — triggers the deny
106
+ - `good_*.Dockerfile` — passes clean
107
+
108
+ Bad fixtures should ONLY fail on the rule being tested. Include USER, HEALTHCHECK, cache mount, etc. so they don't trigger unrelated rules.
109
+
110
+ ### 6. Verify
111
+
112
+ ```bash
113
+ # Rego unit tests
114
+ conftest verify --policy src/agent_harness/policies/dockerfile/
115
+
116
+ # Fixture tests
117
+ conftest test tests/fixtures/dockerfile/*.Dockerfile \
118
+ --parser dockerfile \
119
+ -p src/agent_harness/policies/dockerfile/ \
120
+ --all-namespaces
121
+
122
+ # Full quality gate
123
+ make check
124
+ ```
125
+
126
+ ### 7. Update exception ID table
127
+
128
+ Add the new exception ID to `skills/agent-harness/SKILL.md` in the Conftest Exceptions table.
129
+
130
+ ## Adding a new preset
131
+
132
+ 1. Create `presets/<name>/` with `__init__.py` implementing `Preset`
133
+ 2. Add individual check files (one per tool, with WHAT/WHY/WITHOUT IT/FIX docstring)
134
+ 3. Add `<Name>Preset()` to `registry.py`
135
+ 4. Add Rego policies to `policies/<name>/` if needed
136
+ 5. Run `make check`
137
+
138
+ ## Adding a new check module
139
+
140
+ Create a new file in `src/agent_harness/presets/<stack>/`. Follow the existing pattern:
141
+
142
+ - Function takes `project_dir: Path` and returns `CheckResult` (or `list[CheckResult]`)
143
+ - Use `run_check()` from `agent_harness.runner` for subprocess execution
144
+ - Wire the call into the preset's `run_checks()` method
145
+
146
+ ## Evaluating community rules
147
+
148
+ Before writing a custom Rego rule, check if an existing tool covers it:
149
+
150
+ 1. **Does hadolint cover it?** (Dockerfile shell practices) → Don't duplicate
151
+ 2. **Does ruff cover it?** (Python code patterns) → Don't duplicate
152
+ 3. **Does yamllint cover it?** (YAML syntax) → Don't duplicate
153
+ 4. **Does a conftest community policy exist?** → Evaluate for adoption
154
+ 5. **Does Trivy's built-in check cover it?** → Note the DS-* ID, write our own (Trivy is too slow)
155
+
156
+ If an existing tool covers it, don't duplicate in Rego.
157
+
158
+ ### When NOT to write a rule
159
+
160
+ - **It requires file existence checks** — conftest parses content, not filesystem
161
+ - **It requires cross-file analysis** — conftest checks one file at a time
162
+ - **It's a judgment call** — document as guidance in the skill, not as a Rego policy
163
+ - **An existing tool does it better** — hadolint, ruff, yamllint have years of battle-tested rules
164
+
165
+ ## Tool stack
166
+
167
+ | Tool | Purpose | Why this one |
168
+ |------|---------|-------------|
169
+ | conftest | Rego policies for any config file | Only tool that parses TOML + Dockerfile + YAML + JSON + .gitignore |
170
+ | hadolint | Dockerfile shell best practices | 12K stars, maintained, comprehensive |
171
+ | yamllint | YAML syntax + duplicate key detection | Catches duplicate keys conftest's parser silently merges |
172
+ | ruff | Python lint + format | 46K stars, fastest Python linter |
173
+ | ty | Python type checking | Astral's type checker, fast |
174
+
175
+ ## Code style
176
+
177
+ ```bash
178
+ make fix # auto-format + lint
179
+ ```
180
+
181
+ Follow existing patterns. Ruff handles formatting automatically.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Denis Iorlas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,24 @@
1
+ .PHONY: lint fix test check security-audit bootstrap
2
+
3
+ lint:
4
+ agent-harness lint
5
+
6
+ fix:
7
+ agent-harness fix
8
+
9
+ test:
10
+ uv run pytest tests/ -v
11
+ conftest verify -p src/agent_harness/policies/ --no-color
12
+
13
+ security-audit:
14
+ agent-harness security-audit
15
+
16
+ check: lint test security-audit
17
+
18
+ bootstrap: ## First-time setup after clone
19
+ uv sync
20
+ agent-harness init --apply
21
+ @if command -v prek >/dev/null; then prek install; \
22
+ elif command -v pre-commit >/dev/null; then pre-commit install; \
23
+ else echo "Install prek (brew install prek) or pre-commit for git hooks"; fi
24
+ @echo "Done. Run 'make check' to verify."