Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/.licenserc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ header:
# CHANGELOG.md, which carries the header itself.
- 'dokimi/changelog.d/[0-9]*.md'
- 'dokimi/changelog.d/fragment_template.md.j2'
# Third-party eval files copied unchanged, under their own licenses
# (dokimi/tests/fixtures/task_formats/MANIFEST.yaml, LICENSES/).
- 'dokimi/tests/fixtures/task_formats/**'

comment: never

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### Added

- **`tasks inspect <path> [--json] [--out FILE]`** — detects the eval-task
format of a file, a task directory or a whole tree and reports its
structure: kind (executable, answer-only, trigger, localization), item
count, present and missing parts, lint problems and which dokimi backends
consume it today. Recognises Harbor, BenchFlow `task.md`, terminal-bench v1,
SWE-bench instances, Inspect AI samples (JSONL and CSV) and `@task` files
(scanned as text, never imported), OpenAI evals JSONL and registry specs,
skill-creator `evals.json` and trigger sets, skill-reach query sets,
promptfoo configs and test files, dokimi question sets and ExploreBench
tasks; anything else is reported as `unknown` with its files. A dataset
file a config names (an Inspect `FieldSpec` remap, an OpenAI evals
model-graded spec, promptfoo `tests: file://`) is read as that config says,
and a git-LFS pointer stub is reported as one. `--json` and `--out` write
the `task_inspect.v1` artifact. Detection only: no new format runs yet.
2 changes: 1 addition & 1 deletion dokimi/docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ points up:
| Layer | Modules |
| --- | --- |
| front end | `cli`, `commands`, `__main__` (the argparse front end; no layer below imports it) |
| tracks | `runner`, `report`, `subjects`, `novelty`, `harnesses`, `context`, `repos`, `explore`, `tool_preference`, `external`, `dashboard`, `orchestrator`, `datasets_export`, `coverage`, and the checkers `config_check`, `schema_check`, `schema_compat` |
| tracks | `runner`, `report`, `subjects`, `novelty`, `harnesses`, `context`, `repos`, `explore`, `tool_preference`, `external`, `dashboard`, `orchestrator`, `datasets_export`, `coverage`, `task_formats`, and the checkers `config_check`, `schema_check`, `schema_compat` |
| evaluation | `eval`, `personas`, `questions`, `treatments`, `plugins` |
| components | `ingest`, `metrics`, `gate`, `mcp`, `skills`, `agent_profiles` |
| foundation | `__init__` (the `dokimi` package itself), `_version`, `artifacts`, `records`, `llm`, `process`, `caching`, `config`, `registry`, `intents`, `defaults`, `console`, `utils`, `metrics/usage.py` |
Expand Down
46 changes: 46 additions & 0 deletions dokimi/docs/coding-harnesses.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,52 @@ refused (a few hundred bytes of nested aliases expand without bound), and
frontmatter nested too deeply to parse is a parse error. YAML and TOML dates
and times become ISO strings, and YAML sets sorted lists.

### Other eval formats: `tasks inspect`

`python cli.py tasks inspect <path> [--json] [--out FILE]` names the eval-task format of a
file, a task directory, or every item under a tree, and reports its structure:
kind, item count, which parts are present or missing (instruction,
environment, oracle, verifier, metadata), lint problems, and what in dokimi
can consume it today. It only reads: nothing is run or converted, a Python
file is scanned as text and never imported, and a file that does not parse is
a problem on its report, not an error. A path no format claims is reported as
`unknown` with its files (or keys) and likely prompt and verifier files; when
two formats claim a path about equally, the report lists the other as
`ambiguous` with its evidence. `--json` prints and `--out` writes the report
as a `task_inspect.v1` artifact (`schemas/task_inspect.v1.json`).

A dataset file a config in the same tree names is read as that config says:
an Inspect `@task` file's `json_dataset("x.jsonl", FieldSpec(input="question",
target="answer"))` makes `x.jsonl` Inspect samples under those keys, an OpenAI
evals registry spec makes its `samples_jsonl` OpenAI evals (with no `ideal`
needed when the spec's class is model-graded), and promptfoo `tests:
file://tests.csv` makes that file promptfoo tests. The report says which file
named it. A file that is a git-LFS pointer stub (a clone without `git lfs
pull`) is reported as `git-lfs-pointer`, with the format a config expects it
to be when one names it. `tests/fixtures/task_formats/` holds a small corpus of
real files in each format, with their sources in its `MANIFEST.yaml`.

| Format | Recognised by | Kind | Consumed by |
|---|---|---|---|
| `harbor` | directory with `task.toml` | executable | Harbor-backed harnesses (unless Harbor would refuse it), `docker-*` (with `environment/Dockerfile`) |
| `task-md` | directory with a BenchFlow `task.md` | executable | `benchflow*`, `docker-*` (with `environment/Dockerfile`) |
| `terminal-bench-v1` | directory with `task.yaml` + `run-tests.sh` / `Dockerfile` / `solution.sh` | executable | none yet |
| `swe-bench` | JSON/JSONL rows with `instance_id`, `repo`, `base_commit`, `problem_statement` (`FAIL_TO_PASS`) | executable | none yet |
| `inspect-samples` | JSON/JSONL/CSV rows with `input` and `target` (or the keys a `FieldSpec` names) | answer-only | none yet |
| `inspect-task` | `.py` importing `inspect_ai` with a `@task` function | answer-only (executable with a `sandbox=`) | none yet |
| `openai-evals` | JSONL rows with `input` (chat messages) and `ideal` | answer-only | none yet |
| `openai-evals-spec` | registry YAML with `class: evals.elsuite.*` run specs | answer-only | none yet |
| `skill-creator-evals` | `evals.json` with `skill_name` and `evals[].prompt` | answer-only | none yet |
| `skill-creator-trigger` | rows with `query` and `should_trigger` | trigger | none yet |
| `skill-reach` | `QuerySet` (`queries[]` with `query_id`/`id`, `text`, `expected_skill`) | trigger | none yet |
| `promptfoo` | `promptfooconfig*.yaml`/`.json`, or a config with `prompts`, `providers`/`targets` and `tests`/`scenarios`/`redteam` | answer-only | none yet |
| `promptfoo-tests` | CSV with `__expected` columns, or rows of `{vars, assert}` | answer-only | none yet |
| `dokimi-questions` | questions.v1/v2 JSON | answer-only (trigger with `expected_skill`) | questions track |
| `dokimi-explore-task` | YAML with `id`, `query` and `references[].path` | localization | explore track |
| `git-lfs-pointer` | a git-LFS spec v1 pointer stub | unknown | none (fetch it first) |

`tasks list` and `tasks run` still read only the first two.

The `docker-*` harnesses mount the oracle at `/solution` and `/oracle` and the
verifier at `/tests` and `/verifier`, because a script written for one layout
refers to its siblings by that layout's path. The directory's contents are
Expand Down
3 changes: 2 additions & 1 deletion dokimi/dokimi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
[`dashboard`][dokimi.dashboard] aggregates results across libraries and
[`orchestrator`][dokimi.orchestrator] runs the one-command pipeline.
- Executable tasks: [`harnesses`][dokimi.harnesses] runs coding agents on task
directories.
directories; [`task_formats`][dokimi.task_formats] names the format of other
eval-task files and directories (detection only).
- [`context`][dokimi.context] reads what a run's context window held.
- Content novelty: [`novelty`][dokimi.novelty]. Repositories as subjects:
[`repos`][dokimi.repos]. Subject scorecards, one per run:
Expand Down
6 changes: 4 additions & 2 deletions dokimi/dokimi/artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
model), ``guidance_reach`` (L1 reach probes), ``repo_readiness`` (L0 claim
checks), ``tool_preference`` (which of two equal tools a model picks, and
what moves it), ``repo_environment`` (static inspection of what a
repository offers an agent) and ``repo_budget`` (what a repository puts
into an agent's context). This module stamps each with a
repository offers an agent), ``repo_budget`` (what a repository puts
into an agent's context) and ``task_inspect`` (which eval-task format each
path under a tree is). This module stamps each with a
``schema_version`` and validates it against the JSON Schema in
``dokimi/schemas/`` on save and load, so fixtures and baselines stay
forward-compatible and self-describing.
Expand Down Expand Up @@ -52,6 +53,7 @@
"tool_preference": "tool_preference.v1",
"repo_environment": "repo_environment.v1",
"repo_budget": "repo_budget.v1",
"task_inspect": "task_inspect.v1",
}

# kind -> superseded versions still accepted on *load*, newest first. An artifact written under an
Expand Down
53 changes: 53 additions & 0 deletions dokimi/dokimi/commands/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,50 @@ def cmd_tasks_list(args: argparse.Namespace) -> None:
print(f"{task.name}\t{difficulty}\t{','.join(tags)}")


def _inspect_line(report: dict) -> str:
n = report["items"]
items = "" if n is None else f"\t{n} item{'' if n == 1 else 's'}"
return f"{report['path']}\t{report['format']}\t{report['kind']}{items}\t-> {', '.join(report['consumers'])}"


def _print_inspect(reports: list[dict]) -> None:
for r in reports:
print(_inspect_line(r))
if r["present"] or r["missing"]:
print(f" parts: {', '.join(r['present']) or '-'}; missing: {', '.join(r['missing']) or '-'}")
for alt in r["alternatives"]:
print(f" ambiguous: also {alt['format']} ({alt['confidence']:.2f}: {', '.join(alt['evidence'])})")
for problem in r["problems"]:
print(f" problem: {problem}")
by_format: dict[str, int] = {}
for r in reports:
by_format[r["format"]] = by_format.get(r["format"], 0) + 1
print(f"{len(reports)} item{'' if len(reports) == 1 else 's'}: " + ", ".join(f"{f} {n}" for f, n in sorted(by_format.items())))


def cmd_tasks_inspect(args: argparse.Namespace) -> None:
"""Detect the eval-task format of a path (or of everything under it) and report its structure."""
import json

from dokimi.artifacts import save_artifact, stamp
from dokimi.task_formats import inspect_path

try:
reports = [r.as_dict() for r in inspect_path(Path(args.path))]
except FileNotFoundError as exc:
raise SystemExit(f"error: {exc}") from None
payload = {"root": str(args.path), "items": reports}
if args.out:
try:
save_artifact("task_inspect", payload, Path(args.out))
except OSError as exc:
raise SystemExit(f"error: cannot write {args.out}: {exc}") from None
if args.json:
print(json.dumps(stamp("task_inspect", dict(payload)), indent=2, default=str))
else:
_print_inspect(reports)


def cmd_tasks_harnesses(args: argparse.Namespace) -> None:
from dokimi.harnesses import known_harnesses

Expand Down Expand Up @@ -185,6 +229,15 @@ def register(sub, positive_int) -> None:
list_p.add_argument("--tasks-root", default=None, help=_TASKS_ROOT_HELP)
list_p.set_defaults(func=cmd_tasks_list)

inspect_p = tasks_sub.add_parser(
"inspect",
help="Detect the eval-task format of a file or directory tree and report its structure (no run)",
)
inspect_p.add_argument("path", help="A task directory, a dataset file, or a tree holding either")
inspect_p.add_argument("--json", action="store_true", help="Print the task_inspect.v1 report as JSON")
inspect_p.add_argument("--out", default=None, help="Write the task_inspect.v1 report to this file")
inspect_p.set_defaults(func=cmd_tasks_inspect)

harnesses_p = tasks_sub.add_parser("harnesses", help="List known coding harness aliases")
harnesses_p.set_defaults(func=cmd_tasks_harnesses)

Expand Down
65 changes: 65 additions & 0 deletions dokimi/dokimi/schemas/task_inspect.v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/intel/dokimi/schemas/task_inspect.v1.json",
"title": "Eval-task format inspection v1",
"description": "What `tasks inspect <path>` found under a path, from the files alone: nothing is imported, run or converted (dokimi/docs/coding-harnesses.md). One item per task directory or dataset file a format probe claims; a path nothing claims is a single `unknown` item. `details` is per format and open; every other level is closed.",
"type": "object",
"required": ["schema_version", "root", "items"],
"additionalProperties": false,
"properties": {
"schema_version": {"const": "task_inspect.v1"},
"root": {"type": "string", "description": "The path given to `tasks inspect`, as given."},
"items": {"type": "array", "minItems": 1, "items": {"$ref": "#/$defs/item"}}
},
"$defs": {
"format": {
"enum": ["harbor", "task-md", "terminal-bench-v1", "swe-bench", "inspect-samples", "inspect-task",
"openai-evals", "openai-evals-spec", "skill-creator-evals", "skill-creator-trigger",
"skill-reach", "promptfoo", "promptfoo-tests", "dokimi-questions", "dokimi-explore-task",
"git-lfs-pointer", "unknown"],
"description": "The probe that claimed the item. `git-lfs-pointer` is a dataset file whose content was never fetched (`details.expected_format` names its format when a config in the scan names it); `unknown` is a path no probe claims."
},
"part": {"enum": ["instruction", "environment", "oracle", "verifier", "metadata"]},
"item": {
"type": "object",
"required": ["path", "format", "kind", "confidence", "evidence", "items", "present", "missing",
"problems", "consumers", "alternatives", "details"],
"additionalProperties": false,
"properties": {
"path": {"type": "string"},
"format": {"$ref": "#/$defs/format"},
"kind": {
"enum": ["executable", "answer-only", "trigger", "localization", "unknown"],
"description": "`executable`: an environment and a verifier; `answer-only`: prompt/target samples; `trigger`: skill-selection queries; `localization`: where-is questions scored on cited locations."
},
"confidence": {"type": "number", "minimum": 0, "maximum": 1, "description": "0 for `unknown`."},
"evidence": {"type": "array", "items": {"type": "string"}},
"items": {"type": ["integer", "null"], "minimum": 0, "description": "Records in a dataset file; null for a task directory or an unread file."},
"present": {"type": "array", "items": {"$ref": "#/$defs/part"}},
"missing": {"type": "array", "items": {"$ref": "#/$defs/part"}},
"problems": {"type": "array", "items": {"type": "string"}, "description": "Lint findings: what a consumer would refuse or misread."},
"consumers": {
"type": "array",
"minItems": 1,
"items": {"enum": ["harbor", "docker-*", "benchflow", "questions track", "explore track", "none-yet"]},
"description": "What in dokimi reads the item today; `none-yet` when nothing does."
},
"alternatives": {
"type": "array",
"description": "Other probes that claimed the item about as strongly.",
"items": {
"type": "object",
"required": ["format", "confidence", "evidence"],
"additionalProperties": false,
"properties": {
"format": {"$ref": "#/$defs/format"},
"confidence": {"type": "number", "minimum": 0, "maximum": 1},
"evidence": {"type": "array", "items": {"type": "string"}}
}
}
},
"details": {"type": "object", "description": "Per-format structure (metadata summary, field map, references to dataset files, LFS oid and size)."}
}
}
}
}
16 changes: 16 additions & 0 deletions dokimi/dokimi/task_formats/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (C) 2026 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

"""Eval-task format detection: which format is a path, and what does it hold?

Detection and a structure report only: nothing here runs or converts a task.
``dokimi tasks inspect <path>`` is the command line; :func:`inspect_path` the API.
"""

from dokimi.task_formats.detect import DIR_PROBES, FILE_PROBES, PROBES, detect, inspect_path, unknown
from dokimi.task_formats.model import Fingerprint, Probe, Report

__all__ = [
"DIR_PROBES", "FILE_PROBES", "PROBES", "Fingerprint", "Probe", "Report", "detect",
"inspect_path", "unknown",
]
Loading
Loading