Pointing Dokimi At An External Content Repository¶
This repository is the measuring instrument. The things it measures —
skills, question sets, executable tasks, exploration tasks, agent profiles —
live in a separate content repository (for example uxlfoundation/skills).
Nothing here clones anything: you check the content repo out yourself and name
the directory on the command line.
Every content location is an explicit flag. There is no search path and no implicit default that points at a sibling checkout:
| Flag | What it names | Commands |
|---|---|---|
--root |
a whole content checkout to scan | catalog scan |
--questions-root |
directory holding <product_key>_golden.json |
benchmark preflight/run/batch, evaluate, coverage, config_check |
--tasks-root |
directory of executable task dirs (each with task.toml or a BenchFlow task.md), or of exploration task YAML files |
tasks list/run, explore list/run, coverage, config_check |
--repo-root |
the source tree an exploration task is scored against | explore run |
--registry |
a products.yaml describing products this repo has never heard of |
benchmark preflight/run |
--questions |
one question-set file | arms run, answers generate |
Skills, profiles and subjects are named by path inside the arm spec itself
(skill:<path>, profile:<path>, subjects show <descriptor>), so they need
no root flag.
The transcripts below are real runs against a small demo checkout laid out the way the readers expect. Substitute your own checkout path.
The layout the readers expect¶
<checkout>/
skills.yaml # optional manifest: name, status, catalog_path
skills/<skill-name>/SKILL.md
evaluation/harbor/suites.json # optional manifest: suites -> tasks (status, track)
evaluation/harbor/tasks/<task>/ # task.toml + instruction.md + tests/ + solution/
questions/<product_key>_golden.json
explore_tasks/<task>.yaml
agent_profiles/<persona>.md
products.yaml # optional: products this repo's registry lacks
Both manifests are optional — with no manifest, the readers fall back to a
plain filesystem scan of the same directories. skills.yaml comes in two
shapes, and both hold a list of entries:
# skills.yaml, uxlfoundation/skills: entries under `skills:`, catalog_path required
skills:
- name: demo-skill
status: published
catalog_path: skills/demo-skill
# skills.yaml, intel/skills: the file is the list, the skill is at skills/<name>
- name: demo-skill
maintainer: "github-handle"
In the second shape name must be a single directory name. An entry without
status scans with status -; intel/skills reads that as published.
// evaluation/harbor/suites.json
{"suites": [{"name": "demo", "tasks": [{"name": "demo-widget", "status": "published", "track": "executable"}]}]}
A checkout that puts tasks somewhere other than
evaluation/harbor/tasks can be scanned with catalog scan --tasks-subdir
<relative-path>; the run commands take the full path as --tasks-root
regardless of layout.
1. Scan the checkout before you spend anything¶
catalog scan is a pre-flight: it reads the manifests, resolves each declared
entry on disk, and reports one line per entry. It never calls a model, so it
costs nothing and is the cheapest way to find out that a suite you were about
to pay to run is half-declared.
$ python cli.py catalog scan --root C:/Users/Public/content-repo
# skills (2 declared under C:\Users\Public\content-repo)
demo-skill published C:\Users\Public\content-repo\skills\demo-skill ok
not-written-yet planned C:\Users\Public\content-repo\skills\not-written-yet ERROR: Skill path does not exist: C:\Users\Public\content-repo\skills\not-written-yet
# tasks (3 declared under C:\Users\Public\content-repo)
demo-widget published executable ok
demo-quiz published answer-quality skipped: no task.toml or task.md under C:\Users\Public\content-repo\evaluation\harbor\tasks\demo-quiz (manifest status='published')
demo-later planned executable skipped: no task.toml or task.md under C:\Users\Public\content-repo\evaluation\harbor\tasks\demo-later (manifest status='planned')
$ echo $?
1
Read that output as three outcomes, not two:
ok— the entry loaded and can be run.skipped— a declared entry the scan is expected to pass over: aplannedtask with no directory yet, or atrackthattasks rundoes not drive (answer-qualityentries are question-set material, not Docker tasks).ERROR— an entry that should have worked and did not.
Only errors change the exit code, so catalog scan exiting 0 means "everything
declared as runnable is runnable". Note the asymmetry above: a planned task
with no directory is skipped, while a planned skill with no directory is an
error — the skill reader has no notion of a not-yet-written entry. Either drop
such a skill from skills.yaml or expect the non-zero exit.
Restrict the scan with --kind:
$ python cli.py catalog scan --root C:/Users/Public/content-repo --kind tasks
# tasks (3 declared under C:\Users\Public\content-repo)
demo-widget published executable ok
demo-quiz published answer-quality skipped: no task.toml or task.md under C:\Users\Public\content-repo\evaluation\harbor\tasks\demo-quiz (manifest status='published')
demo-later planned executable skipped: no task.toml or task.md under C:\Users\Public\content-repo\evaluation\harbor\tasks\demo-later (manifest status='planned')
$ echo $?
0
2. The awareness half: question sets¶
A question set is <questions-root>/<product_key>_golden.json, in the format
described in methodology.md: new sets
put each question's text under question (questions.v2); existing sets that
use text (questions.v1) are still read, as are older hand-written shapes
(no id, question_id/question_text, a list metadata), with a one-line
notice. The golden set is only ever read; the run writes its own v2 copy. Point
--questions-root at the checkout's questions/ directory and the pipeline
picks up the golden set for the product it is running:
$ python -m dokimi.coverage \
--tasks-root C:/Users/Public/content-repo/evaluation/harbor/tasks \
--questions-root C:/Users/Public/content-repo/questions
| Product | Awareness (questions) | Work (tasks) | Status |
| --- | --- | --- | --- |
...
| `onetbb` | yes | 1 | covered |
(One row per registered product — 24 of them; only the row this checkout
covers is shown.) onetbb is covered because the checkout has both
questions/onetbb_golden.json and one task tagged onetbb.
Resolution is logged, including the miss:
INFO Using golden questions: C:\Users\Public\content-repo\questions\onetbb_golden.json
WARNING questions root C:\Users\Public\content-repo\questions has no golden set for onemkl; running without a golden question set
benchmark run logs a warning and continues with generated questions only.
benchmark preflight treats a missing golden set as an error and exits 1.
If you are comparing arms, that is usually not what you want; check the coverage matrix first.
benchmark preflight resolves the whole plan without calling a model, and
echoes the root it will read:
$ python cli.py benchmark preflight --library demo \
--registry C:/Users/Public/content-repo/products.yaml \
--questions-root C:/Users/Public/content-repo/questions
Resolved benchmark plan
target: demo
name: demo
description: Worked example product for the external-content walkthrough.
doc_source: context7
output_dir: results/demo_final
answer: openai/gpt-6.1-sol
judge: anthropic/claude-sonnet-5-5
questions_root: C:/Users/Public/content-repo/questions
retrieval: semantic-only, top_k=3
arms: without_docs vs with_docs
max_tokens_per_question: 4000
concurrency: 5
context7_id: demo-org/demo
golden questions: C:\Users\Public\content-repo\questions\demo_golden.json (2 items)
(It exited 1 here because no API keys were set: ✗ missing OPENAI_API_KEY for
provider openai. Key checks are part of the pre-flight.)
For a direct N-arm comparison, hand arms run the question file itself:
python cli.py arms run --product demo \
--questions C:/Users/Public/content-repo/questions/demo_golden.json \
--arms baseline,skill:C:/Users/Public/content-repo/skills/demo-skill \
--judge --judge-model <a-different-model>
This is the one command on this page that bills a provider, so no transcript is shown; evaluating-treatments.md covers reading its report. Section 5 shows how to check the arm specs resolve first.
3. The work half: executable tasks¶
--tasks-root is the directory that contains task directories:
$ python cli.py tasks list --tasks-root C:/Users/Public/content-repo/evaluation/harbor/tasks
demo-widget easy demo,widget
onetbb-parallel-reduce medium onetbb
The third column is [metadata] tags; those tags are what tie a task to a
product in the coverage matrix (a tag matches a product's key in
products.yaml, or one of that product's tag_aliases:).
A with-skill treatment arm over an external skill is two harnesses over one
task set — --dry-run validates the wiring without Docker or a model:
$ python cli.py tasks run --tasks demo-widget \
--tasks-root C:/Users/Public/content-repo/evaluation/harbor/tasks \
--harnesses docker-oracle,docker-claude-skill:C:/Users/Public/content-repo/skills/demo-skill \
--baseline-harness docker-oracle \
--model us.anthropic.claude-haiku-4-5-20251001-v1:0 \
--dry-run --out-json results/demo-widget.json
Saved task run artifact: results\demo-widget.json
Saved task run report: results\demo-widget.md
docker-oracle: 0/1 pass (0.00%), ops=1, elapsed=0.00s
docker-claude-skill:C:/Users/Public/content-repo/skills/demo-skill: 0/1 pass (0.00%), ops=1, elapsed=0.00s
docker-claude-skill:C:/Users/Public/content-repo/skills/demo-skill vs docker-oracle: pass-rate delta +0.00%
A dry run reports every cell as not passed; only the matrix shape and the artifact are being checked. See coding-harnesses.md for the harness list, the real Docker flow, and the paired statistics on this track.
4. Exploration tasks: --tasks-root plus --repo-root¶
Exploration tasks are YAML files that ask where something is, and are scored
against a source tree. The two roots are separate because the question and the
code being searched normally live in different checkouts — --tasks-root is
the YAML directory, --repo-root the tree a task is scored against when its
own YAML omits repo_root:.
$ python cli.py explore list --tasks-root C:/Users/Public/content-repo/explore_tasks
demo-locate-widget demo 1 ref(s) Where is the widget width clamped?
$ python cli.py explore run --all \
--tasks-root C:/Users/Public/content-repo/explore_tasks \
--repo-root C:/Users/Public/content-repo/product-checkout \
--arms oracle,empty --baseline-arm empty --out-json results/explore.json
Saved explore run artifact: results\explore.json
oracle: n=1 file_f1=1.000 line_f1=n/a validity=1.000
empty: n=1 file_f1=0.000 line_f1=n/a validity=1.000
oracle vs empty: file_f1 Δ +1.000
The oracle and empty arms are the ceiling and floor: oracle cites the
task's own references (F1 1.000), empty cites nothing (0.000). Getting those
two numbers is how you confirm --repo-root points at the right tree before
running a model arm — an oracle F1 below 1.000 means the references do not
resolve inside the tree you named.
5. Skills and profiles as arms¶
Arms name paths directly, so an external skill or persona needs no root flag. Arm names are derived from the file or directory name, not the full path:
$ python -c "from dokimi.treatments import create_treatments; [print(a.name) for a in create_treatments(['baseline','skill:C:/Users/Public/content-repo/skills/demo-skill','profile:C:/Users/Public/content-repo/agent_profiles/demo-expert.md'])]"
baseline
skill:demo-skill
profile:demo-expert
A path that does not exist fails immediately, before any model call:
FileNotFoundError: Skill path does not exist: C:\Users\Public\no-such-checkout\skills\demo-skill
A subject descriptor bundles the artifact with the suite it should be measured
on, and may point at the external checkout throughout. subjects show
resolves it — including the arm specs it will run — without executing
anything:
$ python cli.py subjects show C:/Users/Public/content-repo/demo-subject.toml
{
"id": "demo-skill",
"subject": {
"kind": "skill",
"ref": "C:/Users/Public/content-repo/skills/demo-skill",
"members": []
},
"suite": {
"products": ["demo"],
"questions": ["C:/Users/Public/content-repo/questions/demo_golden.json"],
"tasks": ["demo-widget"]
},
"baseline": "baseline",
"awareness_arm_specs": [
"baseline",
"skill:C:/Users/Public/content-repo/skills/demo-skill"
],
"work_arm_specs": [
"baseline",
"skill-agent:C:/Users/Public/content-repo/skills/demo-skill"
],
...
}
(Reformatted here for width; the command prints one JSON key per line.)
suite.tasks entries are resolved the way tasks run --tasks resolves them: a
bare name such as demo-widget needs a root, so subjects run takes the same
--tasks-root <checkout>/evaluation/harbor/tasks. A full path to a task
directory works without it.
6. Products this repository has never heard of¶
The committed registry is the bundled dokimi/products.yaml. A product outside it
is unknown, and benchmark says so rather than inventing one:
$ python cli.py benchmark preflight --library demo
Error: "Product 'demo' not found in registry. Available: advisor, dpctl, dpnp, ..."
Supply the product with --registry <checkout>/products.yaml (as in section 2).
An entry there can declare context7_id:, which is what documentation and MCP
arms resolve against.
There is no name-to-library-id guessing. If a documentation arm cannot find an id, it stops and tells you both ways to give it one:
$ python cli.py answers generate --product widgetlib \
--questions C:/Users/Public/content-repo/questions/demo_golden.json
Loaded 2 questions from C:/Users/Public/content-repo/questions/demo_golden.json
Documentation source: context7
Error: 'widgetlib' is not a Context7 library ID. Context7 IDs look like 'uxlfoundation/oneTBB' (GitHub repo) or 'intelpython_github_io_dpnp' (docs website), and cannot be derived from a product name. Either declare 'context7_id:' for the product in products.yaml, or pass --context7-id on the command line.
Resolution order for documentation and MCP arms is: explicit
--context7-id, then the product's context7_id: in the registry, then the
error above.
A registered product that declares no context7_id: is the same error, named
per product. That case needs its own check because a Context7 website id looks
like host_path — a registry key with an underscore in it (mkl_extensions)
would satisfy that shape and be sent as an id, retrieving nothing while the run
still reports a documentation arm.
7. What happens when a root is missing¶
Worth knowing before you read a suspiciously clean result:
| Command | Root missing | Exit |
|---|---|---|
catalog scan --root <missing> |
--root is not a directory: <path> |
1 |
tasks run --tasks-root <missing> |
FileNotFoundError: Task directory not found: demo-widget |
1 |
tasks list --tasks-root <missing> |
prints nothing | 0 |
explore list --tasks-root <missing> |
prints nothing | 0 |
coverage with no roots |
every product reads no/0, plus an explicit note |
0 |
evaluate/benchmark run with a root lacking the golden set |
WARNING ... has no golden set for <product> and continues |
— |
The two list commands are the trap: an empty listing and a correct listing
both exit 0, so a typo in a path looks like an empty checkout. The coverage
matrix is explicit about it instead:
$ python -m dokimi.coverage
...
Note: no --tasks-root given; the work half is unresolved.
Note: no --questions-root given; the awareness half is unresolved.
Use config_check as the CI-friendly form of the same question; it validates
the registries and, when given roots, the coverage contract:
$ python -m dokimi.config_check \
--tasks-root C:/Users/Public/content-repo/evaluation/harbor/tasks \
--questions-root C:/Users/Public/content-repo/questions
✓ product and intent registries are consistent