@hallucination-studio/harness-engine 1.0.0-beta.14.a797755 → 1.0.0-beta.16.565063c
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.
- package/LICENSE +21 -0
- package/README.md +7 -0
- package/package.json +3 -3
- package/skills/harness-engine/evals/harness_engine_evals/__init__.py +1 -0
- package/skills/harness-engine/evals/harness_engine_evals/cases_frontend.py +212 -0
- package/skills/harness-engine/evals/harness_engine_evals/cases_lifecycle.py +1610 -0
- package/skills/harness-engine/evals/harness_engine_evals/helpers.py +155 -0
- package/skills/harness-engine/evals/harness_engine_evals/registry.py +55 -0
- package/skills/harness-engine/evals/harness_engine_evals/report.py +36 -0
- package/skills/harness-engine/evals/harness_engine_evals/runner.py +53 -0
- package/skills/harness-engine/evals/run_evals.py +5 -2052
- package/skills/harness-engine/scripts/harness_engine/__init__.py +1 -0
- package/skills/harness-engine/scripts/harness_engine/analysis.py +240 -0
- package/skills/harness-engine/scripts/harness_engine/checks.py +287 -0
- package/skills/harness-engine/scripts/harness_engine/cli.py +656 -0
- package/skills/harness-engine/scripts/harness_engine/common.py +977 -0
- package/skills/harness-engine/scripts/harness_engine/continuation.py +520 -0
- package/skills/harness-engine/scripts/harness_engine/git_ops.py +88 -0
- package/skills/harness-engine/scripts/harness_engine/knowledge.py +329 -0
- package/skills/harness-engine/scripts/harness_engine/plans.py +628 -0
- package/skills/harness-engine/scripts/harness_engine/templates.py +124 -0
- package/skills/harness-engine/scripts/manage_harness.py +5 -3801
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hallucination Studio
|
|
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.
|
package/README.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Harness Engine
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@hallucination-studio/harness-engine)
|
|
4
|
+
[](https://www.npmjs.com/package/@hallucination-studio/harness-engine)
|
|
5
|
+
[](https://github.com/hallucination-studio/harness-engine/actions/workflows/ci.yml)
|
|
6
|
+
[](https://github.com/hallucination-studio/harness-engine/actions/workflows/publish-release.yml)
|
|
7
|
+
[](https://github.com/hallucination-studio/harness-engine/actions/workflows/publish-nightly.yml)
|
|
8
|
+
[](https://github.com/hallucination-studio/harness-engine/blob/main/LICENSE)
|
|
9
|
+
|
|
3
10
|
Harness Engine packages a Codex skill that bootstraps an agent-first repository harness.
|
|
4
11
|
It turns the repository-shaping ideas from OpenAI's
|
|
5
12
|
["Harness engineering: leveraging Codex in an agent-first world"](https://openai.com/index/harness-engineering/)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hallucination-studio/harness-engine",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.16.565063c",
|
|
4
4
|
"description": "Install the harness-engine Codex skill for initializing and reconciling advanced repository harness docs.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"skills/**/agents/**",
|
|
25
25
|
"skills/**/assets/**",
|
|
26
26
|
"skills/**/evals/*.json",
|
|
27
|
-
"skills/**/evals
|
|
27
|
+
"skills/**/evals/**/*.py",
|
|
28
28
|
"skills/**/references/**",
|
|
29
|
-
"skills/**/scripts
|
|
29
|
+
"skills/**/scripts/**/*.py"
|
|
30
30
|
],
|
|
31
31
|
"license": "MIT"
|
|
32
32
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Harness Engine eval package."""
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
import tempfile
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from .helpers import *
|
|
9
|
+
|
|
10
|
+
def test_frontend_analysis(tmp_root):
|
|
11
|
+
repo = tmp_root / "frontend-repo"
|
|
12
|
+
repo.mkdir()
|
|
13
|
+
(repo / "package.json").write_text(
|
|
14
|
+
json.dumps(
|
|
15
|
+
{
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"react": "^19.0.0",
|
|
18
|
+
"vite": "^6.0.0",
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
indent=2,
|
|
22
|
+
)
|
|
23
|
+
+ "\n"
|
|
24
|
+
)
|
|
25
|
+
(repo / "src").mkdir()
|
|
26
|
+
(repo / "src" / "App.tsx").write_text("export default function App() { return null; }\n")
|
|
27
|
+
|
|
28
|
+
analysis = run_manager("analyze", "--repo", str(repo))
|
|
29
|
+
question_ids = {item["id"] for item in analysis["human_confirmations"]}
|
|
30
|
+
if not analysis["has_frontend"]:
|
|
31
|
+
raise AssertionError("Frontend repo should be detected")
|
|
32
|
+
if "frontend_stack_notes" not in question_ids:
|
|
33
|
+
raise AssertionError("Frontend repo should ask frontend confirmation questions")
|
|
34
|
+
if "design_style_direction" not in question_ids:
|
|
35
|
+
raise AssertionError("Frontend repo should ask for the desired visual style direction")
|
|
36
|
+
if "React" not in analysis["frameworks"]:
|
|
37
|
+
raise AssertionError("React should be detected")
|
|
38
|
+
if "src/App.tsx" not in analysis["frontend_style_files"]:
|
|
39
|
+
raise AssertionError("Frontend analysis should expose existing frontend code signals")
|
|
40
|
+
if "docs/sops/evidence-first-eval-loop.md" not in analysis["missing_sops"]:
|
|
41
|
+
raise AssertionError("Analysis should include the evidence-first eval SOP")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_backend_init_skips_frontend_design_docs(tmp_root):
|
|
45
|
+
repo = tmp_root / "backend-only-repo"
|
|
46
|
+
repo.mkdir()
|
|
47
|
+
(repo / "pyproject.toml").write_text('[project]\nname = "backend-only"\n')
|
|
48
|
+
answers = tmp_root / "backend-only-answers.json"
|
|
49
|
+
write_answers(answers, project_name="backend-only-demo")
|
|
50
|
+
run_manager("init", "--repo", str(repo), "--answers", str(answers))
|
|
51
|
+
for relative_path in [
|
|
52
|
+
"docs/FRONTEND.md",
|
|
53
|
+
"docs/DESIGN.md",
|
|
54
|
+
"docs/design-docs/index.md",
|
|
55
|
+
"docs/design-docs/style-options.md",
|
|
56
|
+
"docs/design-docs/core-beliefs.md",
|
|
57
|
+
]:
|
|
58
|
+
if (repo / relative_path).exists():
|
|
59
|
+
raise AssertionError(f"Backend-only init should not create {relative_path}")
|
|
60
|
+
assert_exists(repo, "AGENTS.md")
|
|
61
|
+
assert_exists(repo, "ARCHITECTURE.md")
|
|
62
|
+
assert_exists(repo, "docs/QUALITY_SCORE.md")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_frontend_design_control_plane(tmp_root):
|
|
66
|
+
repo = tmp_root / "frontend-design-control-repo"
|
|
67
|
+
repo.mkdir()
|
|
68
|
+
(repo / "package.json").write_text(json.dumps({"dependencies": {"react": "^19.0.0", "vite": "^6.0.0"}}))
|
|
69
|
+
(repo / "src" / "styles").mkdir(parents=True)
|
|
70
|
+
(repo / "src" / "styles" / "theme.css").write_text(":root { --color-primary: #1A1C1E; }\n")
|
|
71
|
+
answers = tmp_root / "frontend-design-control-answers.json"
|
|
72
|
+
write_answers(answers, project_name="frontend-design-control-demo")
|
|
73
|
+
run_manager("init", "--repo", str(repo), "--answers", str(answers))
|
|
74
|
+
frontend_text = (repo / "docs" / "FRONTEND.md").read_text()
|
|
75
|
+
design_text = (repo / "docs" / "DESIGN.md").read_text()
|
|
76
|
+
options_text = (repo / "docs" / "design-docs" / "style-options.md").read_text()
|
|
77
|
+
if not design_text.startswith("---\n"):
|
|
78
|
+
raise AssertionError("DESIGN.md should start with YAML frontmatter, not the harness marker")
|
|
79
|
+
for needle in [
|
|
80
|
+
"## Project Positioning",
|
|
81
|
+
"Requested style direction:",
|
|
82
|
+
"Existing frontend code signals:",
|
|
83
|
+
"src/styles/theme.css",
|
|
84
|
+
"Read `docs/DESIGN.md` before implementing frontend",
|
|
85
|
+
"project-owned unified visual specification",
|
|
86
|
+
"Files controlled by `docs/DESIGN.md` include token notes",
|
|
87
|
+
"Tailwind theme files",
|
|
88
|
+
"global CSS variables",
|
|
89
|
+
"component theme modules",
|
|
90
|
+
"Storybook/theme previews",
|
|
91
|
+
"Agents must read in this order for UI work",
|
|
92
|
+
"map `docs/DESIGN.md` tokens into the project's shared style layer first",
|
|
93
|
+
"Do not add new fonts, font sizes, semantic colors, shadows, radii, or spacing scales directly in component files",
|
|
94
|
+
"Do not call external design-generation skills or package CLIs as part of harness init",
|
|
95
|
+
]:
|
|
96
|
+
if needle not in frontend_text:
|
|
97
|
+
raise AssertionError(f"FRONTEND.md should define design control plane: {needle}")
|
|
98
|
+
for needle in [
|
|
99
|
+
"version: alpha",
|
|
100
|
+
"source: harness-engine-template",
|
|
101
|
+
"colors:",
|
|
102
|
+
"on-primary:",
|
|
103
|
+
"surface-muted:",
|
|
104
|
+
"focus:",
|
|
105
|
+
"success:",
|
|
106
|
+
"warning:",
|
|
107
|
+
"danger:",
|
|
108
|
+
"typography:",
|
|
109
|
+
"display-xl:",
|
|
110
|
+
"display-md:",
|
|
111
|
+
"headline-lg:",
|
|
112
|
+
"headline-md:",
|
|
113
|
+
"title-lg:",
|
|
114
|
+
"title-md:",
|
|
115
|
+
"body-lg:",
|
|
116
|
+
"body-md:",
|
|
117
|
+
"body-sm:",
|
|
118
|
+
"label-md:",
|
|
119
|
+
"label-sm:",
|
|
120
|
+
"rounded:",
|
|
121
|
+
"full: 9999px",
|
|
122
|
+
"spacing:",
|
|
123
|
+
"gutter:",
|
|
124
|
+
"page:",
|
|
125
|
+
"components:",
|
|
126
|
+
"button-primary-hover:",
|
|
127
|
+
"button-secondary:",
|
|
128
|
+
"badge:",
|
|
129
|
+
"table-row:",
|
|
130
|
+
"## Overview",
|
|
131
|
+
"Requested style direction:",
|
|
132
|
+
"Existing frontend code signals:",
|
|
133
|
+
"src/styles/theme.css",
|
|
134
|
+
"## Colors",
|
|
135
|
+
"## Typography",
|
|
136
|
+
"## Layout",
|
|
137
|
+
"## Elevation & Depth",
|
|
138
|
+
"## Shapes",
|
|
139
|
+
"## Components",
|
|
140
|
+
"## Do's and Don'ts",
|
|
141
|
+
"Do not depend on external design-generation skills or packages during init",
|
|
142
|
+
"A restrained developer-tool interface",
|
|
143
|
+
"Use one primary UI font family across the product",
|
|
144
|
+
"All shared UI components must consume tokens from this document through the project's existing style layer",
|
|
145
|
+
"Don't add untracked font families, font sizes, shadows, radii, or semantic colors directly in component files",
|
|
146
|
+
]:
|
|
147
|
+
if needle not in design_text:
|
|
148
|
+
raise AssertionError(f"DESIGN.md should contain project-owned design spec structure: {needle}")
|
|
149
|
+
if "/Users/murphy/code/github/design.md" not in options_text:
|
|
150
|
+
raise AssertionError("style-options.md should document the local design.md reference path")
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_no_external_design_dependency(tmp_root):
|
|
154
|
+
readme_text = (REPO_ROOT / "README.md").read_text()
|
|
155
|
+
skill_text = (SKILL_DIR / "SKILL.md").read_text()
|
|
156
|
+
runtime_text = "\n".join(
|
|
157
|
+
path.read_text()
|
|
158
|
+
for path in sorted((SKILL_DIR / "scripts").rglob("*.py"))
|
|
159
|
+
)
|
|
160
|
+
combined = "\n".join([readme_text, skill_text, runtime_text])
|
|
161
|
+
forbidden = [
|
|
162
|
+
"@google/design.md",
|
|
163
|
+
"prompt in Stitch",
|
|
164
|
+
"brand URL/image import",
|
|
165
|
+
"$google-design-style",
|
|
166
|
+
"google-design-style",
|
|
167
|
+
"third_party/google-design-md",
|
|
168
|
+
"design-source-required",
|
|
169
|
+
]
|
|
170
|
+
for needle in forbidden:
|
|
171
|
+
if needle in combined:
|
|
172
|
+
raise AssertionError(f"Harness Engine should not depend on external design integration text: {needle}")
|
|
173
|
+
for needle in [
|
|
174
|
+
"has no external design runtime dependency",
|
|
175
|
+
"never calls an external design skill",
|
|
176
|
+
"/Users/murphy/code/github/design.md",
|
|
177
|
+
]:
|
|
178
|
+
if needle not in readme_text and needle not in skill_text:
|
|
179
|
+
raise AssertionError(f"Docs should state the dependency-free design boundary: {needle}")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def test_pack_excludes_external_design_dependency(tmp_root):
|
|
183
|
+
result = subprocess.run(
|
|
184
|
+
["npm", "pack", "--dry-run", "--json"],
|
|
185
|
+
cwd=REPO_ROOT,
|
|
186
|
+
text=True,
|
|
187
|
+
capture_output=True,
|
|
188
|
+
check=False,
|
|
189
|
+
)
|
|
190
|
+
if result.returncode != 0:
|
|
191
|
+
raise AssertionError(result.stderr or result.stdout)
|
|
192
|
+
json_start = result.stdout.rfind("\n[")
|
|
193
|
+
if json_start == -1:
|
|
194
|
+
json_start = result.stdout.find("[")
|
|
195
|
+
if json_start == -1:
|
|
196
|
+
raise AssertionError(f"npm pack did not emit JSON file data: {result.stdout}")
|
|
197
|
+
pack_data = json.loads(result.stdout[json_start:].strip())
|
|
198
|
+
files = {item["path"] for item in pack_data[0]["files"]}
|
|
199
|
+
for required_path in [
|
|
200
|
+
".codex-plugin/plugin.json",
|
|
201
|
+
"skills/harness-engine/SKILL.md",
|
|
202
|
+
]:
|
|
203
|
+
if required_path not in files:
|
|
204
|
+
raise AssertionError(f"npm pack should include {required_path}")
|
|
205
|
+
forbidden_prefixes = [
|
|
206
|
+
"skills/google-design-style/",
|
|
207
|
+
"third_party/",
|
|
208
|
+
]
|
|
209
|
+
for file_path in files:
|
|
210
|
+
if any(file_path.startswith(prefix) for prefix in forbidden_prefixes):
|
|
211
|
+
raise AssertionError(f"npm pack should not include external design source or adapter: {file_path}")
|
|
212
|
+
|