nasde-toolkit 0.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,303 @@
1
+ ---
2
+ name: nasde-benchmark-from-public-repos
3
+ description: |
4
+ Build diverse benchmark task suites from public GitHub repositories for testing universal skills. Use this skill when the user wants to:
5
+ - Create a benchmark that spans multiple public repositories and languages
6
+ - Test a universal skill (refactoring, test writing, code review, etc.) across diverse codebases
7
+ - Curate a representative set of repos and tasks for cross-codebase validation
8
+ - Build an evaluation suite for a skill that should work in any repository
9
+ Even if the user doesn't say "benchmark" — if they're building a skill meant to work everywhere and want to validate it across many different projects, this skill applies.
10
+ ---
11
+
12
+ # NASDE Benchmark from Public Repos
13
+
14
+ Build a diverse NASDE benchmark by curating tasks from multiple public GitHub repositories. Designed for validating universal skills — skills that should work across different languages, frameworks, project sizes, and architectural styles.
15
+
16
+ ## Prerequisites
17
+
18
+ - An existing NASDE benchmark project (run `nasde init` first, or use the `nasde-benchmark-creator` skill)
19
+ - A clear description of the skill being evaluated (what it does, what kinds of tasks it helps with)
20
+ - Internet access (to browse and clone public repositories)
21
+
22
+ ## Step 1: Understand the skill under test
23
+
24
+ Ask the user:
25
+
26
+ - **What does the skill do?** (e.g., "helps agents refactor code", "guides test writing", "enforces DDD patterns")
27
+ - **What languages/frameworks should it support?** (e.g., "Python, TypeScript, and Go" or "any language")
28
+ - **What task types exercise the skill?** (e.g., "extract method, rename module, split class" for a refactoring skill)
29
+ - **Are there known weak spots?** (e.g., "seems to struggle with large files" or "not sure about Rust")
30
+
31
+ ## Step 2: Design the diversity matrix
32
+
33
+ Based on the skill description, define axes of variation that the benchmark should cover. Present these to the user as a table:
34
+
35
+ ### Example for a refactoring skill
36
+
37
+ | Axis | Values to cover | Why it matters |
38
+ |------|----------------|---------------|
39
+ | **Language** | Python, TypeScript, Go, Rust, C# | Refactoring idioms differ per language |
40
+ | **Project size** | Small (<5K LOC), Medium (5-50K), Large (>50K) | Large codebases stress navigation and context |
41
+ | **Test coverage** | Extensive tests, Minimal tests, No tests | Refactoring with no safety net is harder |
42
+ | **Architecture** | Monolith, Microservice, Library | Different refactoring patterns apply |
43
+ | **Difficulty** | Extract function, Split module, Restructure package | Increasing complexity |
44
+
45
+ Not every cell in the matrix needs a task. Aim for **8–15 tasks** that provide meaningful coverage across the axes. Ask the user which axes matter most — they may want to emphasize language diversity over project size, or vice versa.
46
+
47
+ ## Step 3: Find candidate repositories
48
+
49
+ For each cell in the matrix that needs coverage, search for public repositories that fit.
50
+
51
+ **Good source repositories have:**
52
+ - A clear, active codebase (not abandoned, not a tutorial/toy project)
53
+ - A working build system and some test infrastructure
54
+ - A well-understood structure (README, organized directories)
55
+ - A permissive license (MIT, Apache 2.0, BSD — avoid GPL if the benchmark may be shared)
56
+ - Enough complexity to be a meaningful test (not a single-file script)
57
+
58
+ **Search strategies:**
59
+ 1. **GitHub search** — search by language, stars, topic tags
60
+ 2. **Known ecosystem repos** — well-known open source projects in each language (e.g., FastAPI for Python, Express for Node, Gin for Go)
61
+ 3. **GitHub Trending** — find actively maintained repos with good structure
62
+ 4. **User suggestions** — the user may know repos that represent their target audience
63
+
64
+ For each candidate repo, present:
65
+
66
+ ```
67
+ [1] github.com/user/repo — "Description from GitHub"
68
+ Language: Python | Size: ~15K LOC | Stars: 2.3K | License: MIT
69
+ Tests: pytest suite, good coverage
70
+ Why: Medium Python project, clean architecture, good refactoring target
71
+ Proposed task: "Extract the database access layer into a repository pattern"
72
+
73
+ [2] github.com/user/repo2 — "Description from GitHub"
74
+ Language: TypeScript | Size: ~40K LOC | Stars: 890 | License: Apache 2.0
75
+ Tests: Jest, moderate coverage
76
+ Why: Large TS project, component-heavy, tests UI refactoring
77
+ Proposed task: "Split the UserDashboard component into focused sub-components"
78
+ ```
79
+
80
+ Ask the user to select which repos and tasks to include.
81
+
82
+ ## Step 4: Create tasks for each selected repo
83
+
84
+ For each approved repo+task pair, generate the full task directory. Work through each file with the user.
85
+
86
+ ### 4a: Determine the "before" state
87
+
88
+ Unlike `nasde-benchmark-from-history` (which uses a specific commit), here you choose a state of the repo that presents the problem to solve:
89
+
90
+ - **Option A: Current main branch** — the repo as-is has the problem (e.g., a God class that should be split). Set `source.ref` to a specific commit hash on main for reproducibility.
91
+ - **Option B: A tagged release** — use a specific version. More stable for long-lived benchmarks.
92
+ - **Option C: Create a setup branch** — if the task requires introducing a specific problem into a clean codebase, create a branch that sets up the scenario. Push it to a fork or document the setup in the Dockerfile.
93
+
94
+ Always pin to a specific commit hash, not a branch name — branches move, hashes don't.
95
+
96
+ ### 4b: task.toml (single task config, shared with Harbor)
97
+
98
+ ```toml
99
+ version = "1.0"
100
+
101
+ [task]
102
+ name = "<benchmark-name>/<language>-<repo-slug>-<task-slug>" # Harbor requires org/name format
103
+ description = "<What the agent must do>"
104
+
105
+ [metadata]
106
+ difficulty = "<easy|intermediate|hard>"
107
+ language = "<language>"
108
+ framework = "<framework>"
109
+ source_repo = "https://github.com/<owner>/<repo>"
110
+ diversity_axes = ["<axis:value>", "<axis:value>"]
111
+
112
+ [agent]
113
+ timeout_sec = 1800 # Rule of thumb: estimated_time_minutes × 60
114
+
115
+ [environment]
116
+ memory_mb = 4096 # Claude Code needs 4096+, default 2048 is too low.
117
+
118
+ [verifier]
119
+ timeout_sec = 300
120
+
121
+ [nasde.source] # Only needed when task has no environment/Dockerfile (auto-generation).
122
+ git = "https://github.com/<owner>/<repo>.git"
123
+ ref = "<pinned-commit-hash>"
124
+ ```
125
+
126
+ The `[metadata] diversity_axes` helps track coverage across the matrix. Always pin `[nasde.source] ref` to a specific commit hash, not a branch name.
127
+
128
+ ### 4c: instruction.md
129
+
130
+ Write a task instruction that:
131
+ - Describes the codebase context (what the project does, relevant directory structure)
132
+ - States the problem clearly (what needs to change and why)
133
+ - Defines success criteria the agent can verify
134
+ - Does NOT prescribe the implementation approach
135
+
136
+ ```markdown
137
+ # Task: <Descriptive name>
138
+
139
+ ## Context
140
+ You are working in `/app`, a <language> <framework> project that <brief description>.
141
+ The project structure relevant to this task:
142
+ <tree of relevant directories/files>
143
+
144
+ ## Requirement
145
+ <What needs to change. Describe the problem, not the solution.
146
+ Example: "The UserService class handles authentication, authorization, profile management,
147
+ and notification dispatch. It's 800 lines and growing. Separate these concerns into
148
+ focused services.">
149
+
150
+ ## Scope
151
+ - Focus on: <specific files/directories>
152
+ - Do NOT modify: <test files, configuration, unrelated modules>
153
+ - Preserve: <all existing public APIs, test behavior>
154
+
155
+ ## Quality Expectations
156
+ - Follow <language> idioms and the project's existing style
157
+ - Maintain or improve test coverage
158
+ - Keep changes minimal — change what needs changing, nothing more
159
+
160
+ ## Success Criteria
161
+ 1. <Specific, testable criterion>
162
+ 2. <Specific, testable criterion>
163
+ 3. All existing tests continue to pass
164
+ ```
165
+
166
+ **Important for universal skill benchmarks:** Write the instruction as if the agent has no special skill. The skill configuration is injected via the variant's `CLAUDE.md` — the instruction describes the raw problem.
167
+
168
+ ### 4d: environment/Dockerfile
169
+
170
+ Each repo needs its own Dockerfile. Detect the stack and generate:
171
+
172
+ ```dockerfile
173
+ FROM <base-image>
174
+
175
+ RUN apt-get update && apt-get install -y git curl wget ca-certificates && rm -rf /var/lib/apt/lists/*
176
+
177
+ WORKDIR /app
178
+ RUN git clone https://github.com/<owner>/<repo>.git . && git checkout <pinned-hash>
179
+
180
+ # Install dependencies
181
+ RUN <dependency-install-command>
182
+
183
+ # Verify build works at the "before" state
184
+ RUN <build-or-compile-command>
185
+
186
+ CMD ["/bin/bash"]
187
+ ```
188
+
189
+ **Test the Dockerfile** before moving on:
190
+ ```bash
191
+ docker build -t benchmark-test-<task-name> -f tasks/<task-name>/environment/Dockerfile .
192
+ ```
193
+
194
+ ### 4e: tests/test.sh
195
+
196
+ For public repos, the verifier typically:
197
+ 1. Verifies the project still builds
198
+ 2. Runs the existing test suite (all tests must still pass)
199
+ 3. Checks for task-specific outcomes (new files exist, specific patterns in code, etc.)
200
+
201
+ ```bash
202
+ #!/bin/bash
203
+ cd /app
204
+
205
+ echo "Step 1: Verifying build..."
206
+ if <build-command>; then
207
+ echo "✓ Build succeeded"
208
+ else
209
+ echo "✗ Build failed"
210
+ echo 0 > /logs/verifier/reward.txt
211
+ exit 1
212
+ fi
213
+
214
+ echo "Step 2: Running existing tests..."
215
+ if <test-command>; then
216
+ echo "✓ Existing tests pass"
217
+ else
218
+ echo "✗ Existing tests failed — regression detected"
219
+ echo 0 > /logs/verifier/reward.txt
220
+ exit 1
221
+ fi
222
+
223
+ echo "Step 3: Checking task-specific criteria..."
224
+ # Example: verify a specific file was created or a class was split
225
+ if <task-specific-check>; then
226
+ echo "✓ Task criteria met"
227
+ else
228
+ echo "✗ Task criteria not met"
229
+ echo 0 > /logs/verifier/reward.txt
230
+ exit 1
231
+ fi
232
+
233
+ echo "EVALUATION PASSED ✓"
234
+ echo 1 > /logs/verifier/reward.txt
235
+ exit 0
236
+ ```
237
+
238
+ Task-specific checks depend on the task type:
239
+ - **Refactoring:** check that target files exist, original God class is smaller or removed
240
+ - **Test writing:** check that new test files exist and pass
241
+ - **Bug fix:** check that a specific test case now passes
242
+
243
+ ### 4f: assessment_criteria.md
244
+
245
+ Use the benchmark project's `assessment_dimensions.json` and adapt each dimension to this specific task and language:
246
+
247
+ ```markdown
248
+ # Assessment Criteria: <Task Name>
249
+
250
+ Evaluate the agent's solution across the following dimensions.
251
+ This task is in <language> using <framework> — apply language-specific standards.
252
+
253
+ ## 1. <Dimension> (0–<max_score>)
254
+
255
+ | Score | Criteria |
256
+ |-------|----------|
257
+ | 0 | <worst — specific to this language and task> |
258
+ | ... | ... |
259
+ | <max> | <best — specific to this language and task> |
260
+
261
+ **Key checks:**
262
+ - <Language-specific things to look for>
263
+ ```
264
+
265
+ **Important:** Assessment criteria should reflect language idioms. "Good refactoring" looks different in Rust (ownership, lifetimes) vs Python (duck typing, protocols) vs Go (interfaces, embedding).
266
+
267
+ ## Step 5: Review coverage
268
+
269
+ After all tasks are created, present the filled diversity matrix to the user:
270
+
271
+ ```
272
+ Coverage matrix for "refactoring" skill benchmark:
273
+
274
+ | Language | Small | Medium | Large |
275
+ |------------|-------|--------|-------|
276
+ | Python | | ✓ fastapi-extract | |
277
+ | TypeScript | | | ✓ dashboard-split |
278
+ | Go | ✓ cli-service-layer | | |
279
+ | Rust | ✓ error-handling | | |
280
+ | C# | | ✓ ddd-aggregate | |
281
+
282
+ Gaps: No large Python project, no small TypeScript project.
283
+ ```
284
+
285
+ Ask the user if they want to fill gaps or if current coverage is sufficient.
286
+
287
+ ## Step 6: Verify the benchmark
288
+
289
+ 1. **Build all Docker images** — every task must build successfully
290
+ 2. **Run existing test suites** in each container — they must pass at the "before" state
291
+ 3. **Dry run** on one or two tasks:
292
+ ```bash
293
+ nasde run --variant <skill-variant> --tasks <task-name> --without-eval -C <benchmark-dir>
294
+ ```
295
+
296
+ ## Tips
297
+
298
+ - **Pin commit hashes, not branches.** Branches move. A benchmark task that worked yesterday might break tomorrow if main advanced. Always use the full 40-char hash.
299
+ - **Diverse doesn't mean random.** Each task should test a different aspect of the skill. If three tasks all test "extract method in Python," replace two with different languages or problem types.
300
+ - **Test the Dockerfiles early.** The most common failure is a Dockerfile that doesn't build because a dependency changed or a repo restructured. Build images as you create tasks, not all at the end.
301
+ - **Keep instructions skill-agnostic.** The task instruction describes the problem. The skill is injected via the variant's `CLAUDE.md`. This separation lets you test the same tasks with and without the skill.
302
+ - **Start with 5–8 tasks.** You can always add more. A smaller, well-curated benchmark is better than a large, noisy one.
303
+ - **Combine with nasde-benchmark-creator.** This skill generates tasks from public repos; `nasde-benchmark-creator` handles project scaffold, dimensions, and variants. Use them together.
@@ -0,0 +1,388 @@
1
+ ---
2
+ name: nasde-benchmark-runner
3
+ description: |
4
+ Run coding agent benchmarks and verify results with nasde. Use this skill when the user wants to:
5
+ - Run a benchmark (all tasks, single task, specific variant)
6
+ - Re-run assessment evaluation on existing trial results
7
+ - Check or verify results in Opik (traces, feedback scores, experiments)
8
+ - Troubleshoot a failed benchmark run
9
+ - View or compare trial results
10
+ Even if the user doesn't say "benchmark" — if they're talking about running evaluations, checking scores, or analyzing agent performance, this skill applies.
11
+ After every run that uses --with-opik, ALWAYS verify results via Opik REST API — don't wait for the user to ask.
12
+ ---
13
+
14
+ # NASDE Benchmark Runner
15
+
16
+ Run coding agent benchmarks with `nasde` and verify results. The two-stage pipeline: Harbor runs agents in Docker containers (functional test → reward 0/1), then an LLM-as-a-Judge scores architecture quality across multiple dimensions.
17
+
18
+ ## Authentication setup
19
+
20
+ Before running any benchmark, set up authentication tokens. Both are needed for cross-agent benchmarks.
21
+
22
+ ### Claude Code (OAuth token from subscription)
23
+
24
+ ```bash
25
+ source scripts/export_oauth_token.sh
26
+ ```
27
+
28
+ This extracts `CLAUDE_CODE_OAUTH_TOKEN` from macOS Keychain (written by `claude` CLI login). Required for both Claude agent runs AND assessment evaluation (which spawns the `claude` CLI as a subprocess when `[evaluation] backend = "claude"`).
29
+
30
+ Alternatively, set `ANTHROPIC_API_KEY` for API billing.
31
+
32
+ ### Codex (ChatGPT subscription or API key)
33
+
34
+ **Option 1: ChatGPT subscription (OAuth)** — uses ChatGPT Plus/Pro/Business plan credits, no per-token API cost:
35
+
36
+ ```bash
37
+ codex login # one-time: authenticate via ChatGPT
38
+ source scripts/export_codex_oauth_token.sh # validate tokens are present
39
+ ```
40
+
41
+ NASDE auto-detects `~/.codex/auth.json` with `auth_mode: "chatgpt"` and injects OAuth tokens into the sandbox. No env vars needed.
42
+
43
+ **Option 2: API key** — billed per-token through OpenAI Platform:
44
+
45
+ ```bash
46
+ export $(grep CODEX_API_KEY .env)
47
+ ```
48
+
49
+ Or set directly: `export CODEX_API_KEY=sk-proj-...`
50
+
51
+ API key always takes priority over OAuth when both are present.
52
+
53
+ ### Gemini CLI (Google account or API key)
54
+
55
+ **Option 1: Google account OAuth** — uses Google account credits, no per-token API cost:
56
+
57
+ ```bash
58
+ gemini login # one-time: authenticate via Google account
59
+ source scripts/export_gemini_oauth_token.sh # validate tokens are present
60
+ ```
61
+
62
+ NASDE auto-detects `~/.gemini/oauth_creds.json` and injects OAuth credentials into the sandbox. No env vars needed.
63
+
64
+ **Option 2: API key** — billed through Google AI Studio or Vertex AI:
65
+
66
+ ```bash
67
+ export GEMINI_API_KEY=your-key
68
+ ```
69
+
70
+ Or for Vertex AI: `export GOOGLE_API_KEY=your-key` + `export GOOGLE_CLOUD_PROJECT=your-project`
71
+
72
+ API key always takes priority over OAuth when both are present.
73
+
74
+ ### Combined setup for cross-agent runs
75
+
76
+ ```bash
77
+ source scripts/export_oauth_token.sh # Claude (subscription)
78
+ # Codex: either codex login (subscription) or:
79
+ export $(grep CODEX_API_KEY .env) # Codex (API key)
80
+ source scripts/export_gemini_oauth_token.sh # Gemini (Google account)
81
+ ```
82
+
83
+ ## Running benchmarks
84
+
85
+ All commands assume `-C` points to the benchmark project directory.
86
+
87
+ ### Basic run (all tasks, default variant)
88
+
89
+ ```bash
90
+ nasde run -C path/to/benchmark
91
+ ```
92
+
93
+ Assessment evaluation runs by default. This is the standard workflow.
94
+
95
+ ### Specific variant and tasks
96
+
97
+ ```bash
98
+ # Single task, specific variant
99
+ nasde run --variant guided --tasks my-task -C path/to/benchmark
100
+
101
+ # Multiple tasks
102
+ nasde run --variant baseline --tasks task-a,task-b -C path/to/benchmark
103
+ ```
104
+
105
+ ### With Opik tracing
106
+
107
+ ```bash
108
+ nasde run --variant baseline --tasks my-task -C path/to/benchmark --with-opik
109
+ ```
110
+
111
+ After this completes, ALWAYS verify Opik results (see Opik verification below).
112
+
113
+ ### Harbor only (skip assessment)
114
+
115
+ ```bash
116
+ nasde run --variant baseline -C path/to/benchmark --without-eval
117
+ ```
118
+
119
+ ### Parallel runs (multiple variants)
120
+
121
+ Running multiple variants simultaneously is safe — each job directory includes a unique random suffix to prevent collisions:
122
+
123
+ ```bash
124
+ nasde run --variant vanilla --tasks my-task -C path/to/benchmark &
125
+ nasde run --variant guided --tasks my-task -C path/to/benchmark &
126
+ wait
127
+ ```
128
+
129
+ For deterministic job names, use `--job-suffix`:
130
+
131
+ ```bash
132
+ nasde run --variant vanilla --job-suffix run1 -C path/to/benchmark
133
+ ```
134
+
135
+ ### Running Codex variants
136
+
137
+ Codex variants use `AGENTS.md` (instead of `CLAUDE.md`) and require either `codex login` (ChatGPT subscription) or `CODEX_API_KEY`/`OPENAI_API_KEY` (API billing).
138
+
139
+ **CRITICAL: Codex model must be set explicitly.** The `nasde.toml` default model (e.g. `claude-sonnet-4-6`) is designed for Claude and will be passed to Codex if not overridden. Codex CLI will silently accept invalid model names but produce garbage results (0% pass rate). Always set the model via `--model` flag or in `variant.toml`.
140
+
141
+ ```bash
142
+ # Option A: ChatGPT subscription (no env vars needed after codex login)
143
+ nasde run --variant codex-vanilla --model gpt-5.3-codex -C path/to/benchmark
144
+
145
+ # Option B: API key
146
+ export $(grep CODEX_API_KEY .env)
147
+ nasde run --variant codex-vanilla --model gpt-5.3-codex -C path/to/benchmark
148
+ ```
149
+
150
+ **Codex models** (recommended first, as of 2026-03):
151
+ - `gpt-5.4` — flagship frontier model, best overall for professional work
152
+ - `gpt-5.4-mini` — fast, efficient mini model for responsive coding and subagents
153
+ - `gpt-5.3-codex` — industry-leading coding model for complex software engineering
154
+ - `gpt-5.3-codex-spark` — near-instant real-time coding iteration (ChatGPT Pro only)
155
+
156
+ Older alternatives: `gpt-5.2-codex`, `gpt-5.1-codex`, `gpt-5-codex`, `gpt-5-codex-mini`
157
+
158
+ Codex supports any model compatible with the Responses API. Chat Completions API support is deprecated.
159
+
160
+ **Setting model in variant.toml** (preferred over --model flag):
161
+ ```toml
162
+ agent = "codex"
163
+ model = "gpt-5.4"
164
+ ```
165
+ This avoids accidentally inheriting the Claude model from `nasde.toml`.
166
+
167
+ ### Running Gemini CLI variants
168
+
169
+ Gemini variants use `GEMINI.md` (instead of `CLAUDE.md`) and require either `gemini login` (Google account) or `GEMINI_API_KEY`/`GOOGLE_API_KEY` (API billing).
170
+
171
+ **CRITICAL: Gemini model must use `google/` prefix.** Harbor requires model names in `provider/model_name` format. Always set via `--model` flag or in `variant.toml`.
172
+
173
+ ```bash
174
+ # Option A: Google account OAuth (no env vars needed after gemini login)
175
+ nasde run --variant gemini-vanilla --model google/gemini-3-flash-preview -C path/to/benchmark
176
+
177
+ # Option B: API key
178
+ export GEMINI_API_KEY=your-key
179
+ nasde run --variant gemini-vanilla --model google/gemini-3-flash-preview -C path/to/benchmark
180
+ ```
181
+
182
+ **Gemini models** (recommended first, as of 2026-03):
183
+ - `google/gemini-3.1-pro-preview` — advanced thinking model, deep reasoning
184
+ - `google/gemini-3-flash-preview` — best quality/speed ratio, daily coding
185
+ - `google/gemini-3.1-flash-lite-preview` — fastest, simple tasks
186
+
187
+ **Setting model in variant.toml** (preferred over --model flag):
188
+ ```toml
189
+ agent = "gemini"
190
+ model = "google/gemini-3-flash-preview"
191
+ ```
192
+
193
+ ### Cross-agent comparison (Claude vs Codex vs Gemini)
194
+
195
+ Set up all auth tokens first (see Authentication setup above), then run:
196
+
197
+ ```bash
198
+ source scripts/export_oauth_token.sh && export $(grep CODEX_API_KEY .env) && source scripts/export_gemini_oauth_token.sh
199
+
200
+ # Run Claude, Codex, and Gemini variants — non-Claude MUST have --model override
201
+ nasde run --variant claude-vanilla -C path/to/benchmark --with-opik &
202
+ nasde run --variant codex-vanilla --model gpt-5.3-codex -C path/to/benchmark --with-opik &
203
+ nasde run --variant gemini-vanilla --model google/gemini-3-flash-preview -C path/to/benchmark --with-opik &
204
+ wait
205
+ ```
206
+
207
+ **WARNING**: Running Claude variants in parallel can cause OOM (exit code 137) in Docker. Claude Code containers are memory-heavy (~2-4 GB each). Run Claude variants sequentially, or increase Docker Desktop memory to 16+ GB.
208
+
209
+ ### Custom model and timeout
210
+
211
+ ```bash
212
+ nasde run --variant baseline --model claude-opus-4-7 --timeout 1200 -C path/to/benchmark
213
+ ```
214
+
215
+ **Timeout priority**: `--timeout` flag overrides everything. Without it, Harbor uses `task.toml [agent] timeout_sec` per task. Timeouts are per-task only — there is no project-wide default in nasde.toml.
216
+
217
+ ### Re-evaluate existing results
218
+
219
+ ```bash
220
+ nasde eval path/to/benchmark/jobs/2026-03-16__14-05-58 --with-opik -C path/to/benchmark
221
+ ```
222
+
223
+ ## Token cost heuristic
224
+
225
+ **Claude Code variants:**
226
+ When using `CLAUDE_CODE_OAUTH_TOKEN` (Claude subscription — no per-token cost):
227
+ - **Run freely**: total estimated time under 30 minutes (sum of tasks × variants)
228
+ - **Ask first**: over 30 minutes, OR when using `ANTHROPIC_API_KEY` (API billing)
229
+
230
+ **Codex variants:**
231
+ - **ChatGPT OAuth** (`codex login`): uses subscription credits, no per-token cost. Same heuristic as Claude subscription — run freely under 30 minutes.
232
+ - **API key** (`CODEX_API_KEY`): billed per-token. Always ask before running. Codex uses significantly more input tokens than Claude Code (~1M vs ~250K per task).
233
+
234
+ **Gemini CLI variants:**
235
+ - **Google account OAuth** (`gemini login`): free tier via Gemini Code Assist license (1M token context). Run freely.
236
+ - **API key** (`GEMINI_API_KEY`): billed per-token through Google AI Studio. Ask before running.
237
+ - **Vertex AI** (`GOOGLE_API_KEY`): billed through Google Cloud. Ask before running.
238
+
239
+ Task estimated times are derived from `task.toml [agent] timeout_sec` (timeout_sec / 60 is a rough upper bound; agents typically finish faster). When `--tasks` filters are used, count only selected tasks.
240
+
241
+ ## Viewing results
242
+
243
+ After a run, results are in `jobs/<timestamp>/`:
244
+
245
+ ```bash
246
+ # Job summary
247
+ cat jobs/<timestamp>/result.json | python3 -m json.tool
248
+
249
+ # Per-trial results
250
+ cat jobs/<timestamp>/<trial-id>/result.json | python3 -m json.tool
251
+
252
+ # Verifier output (what test.sh printed)
253
+ cat jobs/<timestamp>/<trial-id>/verifier/test-stdout.txt
254
+
255
+ # Assessment scores
256
+ cat jobs/<timestamp>/<trial-id>/assessment_eval.json | python3 -m json.tool
257
+ ```
258
+
259
+ ### Using Harbor CLI for viewing
260
+
261
+ ```bash
262
+ nasde harbor view path/to/benchmark/jobs/<timestamp>
263
+ ```
264
+
265
+ ## Opik verification
266
+
267
+ After every run with `--with-opik`, verify results via REST API. This is mandatory — Opik has known issues with long-running trials where data may not arrive completely.
268
+
269
+ ### Verification script
270
+
271
+ Use Python `urllib.request` (never curl — it drops the `Comet-Workspace` header):
272
+
273
+ ```python
274
+ python3 -c "
275
+ import urllib.request, json
276
+
277
+ req = urllib.request.Request(
278
+ 'https://www.comet.com/opik/api/v1/private/traces?project_name=<PROJECT_NAME>&limit=1',
279
+ headers={
280
+ 'authorization': '<OPIK_API_KEY>',
281
+ 'Comet-Workspace': '<OPIK_WORKSPACE>',
282
+ },
283
+ )
284
+ resp = json.loads(urllib.request.urlopen(req).read())
285
+ trace = resp['content'][0]
286
+ print(f'Trace: {trace[\"name\"]}')
287
+ print(f'ID: {trace[\"id\"]}')
288
+ print()
289
+ for s in sorted(trace.get('feedback_scores', []), key=lambda x: x['name']):
290
+ print(f' {s[\"name\"]}: {s[\"value\"]}')
291
+ "
292
+ ```
293
+
294
+ Credentials are in the benchmark's `.env` file (or parent directory).
295
+
296
+ ### What to check
297
+
298
+ For each trace, verify:
299
+
300
+ 1. **Feedback scores present** — should include:
301
+ - `reward` (from Harbor verifier: 0.0 or 1.0)
302
+ - `duration_sec` (trial execution time)
303
+ - `arch_<dimension>` for each assessment dimension (normalized 0.0-1.0)
304
+ - `arch_total` (overall normalized score)
305
+ 2. **Trace name format**: `<agent-name>/<trial-name>` (e.g. `baseline/ddd-threshold-discount__4tTaKwg`)
306
+ 3. **Tags**: should include `harbor` and the variant name
307
+
308
+ ### Finding trace IDs
309
+
310
+ The trace ID is printed during the run:
311
+ ```
312
+ OPIK: Started logging traces to ... ?trace_id=<TRACE_ID>&...
313
+ ```
314
+
315
+ Or search by project:
316
+ ```python
317
+ import opik
318
+ client = opik.Opik()
319
+ traces = client.search_traces(
320
+ project_name='<benchmark-name>',
321
+ filter_string='name = "<agent-name>/<trial-name>"',
322
+ max_results=1,
323
+ wait_for_at_least=1,
324
+ wait_for_timeout=10,
325
+ )
326
+ ```
327
+
328
+ ## Troubleshooting
329
+
330
+ ### "No module named 'evals'" or import errors
331
+
332
+ Harbor resolves `import_path` from `harbor_config.json` via `importlib`. If using the built-in agent (`nasde_toolkit.agents.configurable_claude:ConfigurableClaude`), this works when nasde-toolkit is installed. For custom agents, ensure the module is on `sys.path`.
333
+
334
+ ### Docker build fails
335
+
336
+ Test the Dockerfile independently:
337
+ ```bash
338
+ docker build -t test-env -f tasks/<task>/environment/Dockerfile .
339
+ docker run --rm -it test-env bash
340
+ ```
341
+
342
+ ### Assessment eval fails with "No artifacts/workspace/"
343
+
344
+ Harbor didn't copy artifacts. Check:
345
+ - The `artifacts` config in the merged Harbor config (source path must match container layout)
346
+ - The trial log: `jobs/<ts>/<trial>/trial.log`
347
+
348
+ ### Opik scores missing after --with-opik
349
+
350
+ 1. Check trace exists: use the REST API verification script above
351
+ 2. If trace exists but no `arch_*` scores: assessment eval didn't run or failed. Check the CLI output for errors.
352
+ 3. If no trace at all: Opik tracking wasn't enabled. Verify `.env` has `OPIK_API_KEY` and `OPIK_WORKSPACE`.
353
+
354
+ ### Codex trial fails immediately (reward 0, 0/100)
355
+
356
+ Check the agent log for errors:
357
+ ```bash
358
+ head -20 jobs/<ts>/<trial>/agent/codex.txt
359
+ ```
360
+
361
+ Common causes:
362
+ - **`Incorrect API key provided: ''`** — no auth configured. Either run `codex login` (ChatGPT subscription) or set `CODEX_API_KEY`: `export $(grep CODEX_API_KEY .env)`
363
+ - **`model 'X' does not exist`** — wrong model name. Use `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.3-codex`, or `gpt-5.3-codex-spark`
364
+ - **0% pass rate, low scores, but trials completed** — likely inherited Claude model name (e.g. `claude-sonnet-4-6`) instead of OpenAI model. Check `config.json` in the job dir for `model_name`. Fix by adding `model = "gpt-5.3-codex"` to `variant.toml` or using `--model gpt-5.3-codex`
365
+ - **`Tool 'web_search_preview' is not supported`** — model doesn't support Codex tools
366
+ - **`Model metadata for 'X' not found`** — warning only, usually followed by the real error
367
+
368
+ ### Gemini trial fails immediately (reward 0, 0/100)
369
+
370
+ Check the agent log for errors:
371
+ ```bash
372
+ head -20 jobs/<ts>/<trial>/agent/gemini-cli.txt
373
+ ```
374
+
375
+ Common causes:
376
+ - **`GEMINI_API_KEY is not set`** — no auth configured. Either run `gemini login` or set `GEMINI_API_KEY`
377
+ - **`Model name must be in the format provider/model_name`** — model must include `google/` prefix (e.g. `google/gemini-3-flash-preview`)
378
+ - **Node.js errors** — Gemini CLI requires Node.js 22+. Check the Docker image includes nvm setup
379
+ - **DNS resolution failures** — cloud sandboxes may not resolve `generativelanguage.googleapis.com`. ConfigurableGemini auto-fixes this, but custom configs may not
380
+
381
+ ### Trial reward is 0 but code looks correct
382
+
383
+ Read the verifier output:
384
+ ```bash
385
+ cat jobs/<ts>/<trial>/verifier/test-stdout.txt
386
+ ```
387
+
388
+ This shows exactly which step in `test.sh` failed.