Skip to content
Closed
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
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

SHELL := /bin/bash

.PHONY: help docker-shell docker-check-agents docker-smoke docker-build-rdna4 docker-run docker-parallel-run docker-quality-loop docker-sikl-task-builder docker-setup-flydsl docker-setup-geak \
.PHONY: help docker-shell docker-check-agents docker-smoke docker-build-rdna4 docker-run docker-parallel-run docker-quality-loop docker-sikl-task-builder docker-setup-flydsl docker-setup-geak docker-setup-forge \
slurm-shell slurm-smoke slurm-parallel-smoke slurm-check-agents slurm-run slurm-parallel-run slurm-submit slurm-parallel-submit \
check-docker-runner check-slurm-runner check-evaluator check-held-out check-visualization \
visualization-build visualization-serve visualization-run \
Expand Down Expand Up @@ -34,6 +34,7 @@ help:
@echo " Use SIKL_BUILDER_ARGS='resume --run-id ...' to resume"
@echo "make docker-setup-flydsl - Install FlyDSL when absent (for flydsl2flydsl, torch2flydsl, and triton2flydsl)"
@echo "make docker-setup-geak - Install the Claude Agent SDK when absent (for the geak agent)"
@echo "make docker-setup-forge - Install Hyperloom[forge] from HYPERLOOM_ROOT's HEAD (for the forge agent)"
@echo "make check-docker-runner - Check Docker runner syntax and runtime-specific arguments"
@echo "make check-slurm-runner - Check Slurm/Spur resource and Docker handoff arguments"
@echo ""
Expand Down Expand Up @@ -170,6 +171,11 @@ docker-setup-flydsl:
docker-setup-geak:
@$(DOCKER_RUNNER) setup-geak

# Install Hyperloom[forge] from the committed HEAD of HYPERLOOM_ROOT into the
# mounted pip user-base. Run and preflight repeat it when that revision changes.
docker-setup-forge:
@$(DOCKER_RUNNER) setup-forge

check-docker-runner:
@bash tests/test_docker_benchmark.sh

Expand Down
21 changes: 19 additions & 2 deletions agents/forge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,27 @@ checks that both commands still take the options the adapter builds.
only as a library. It refuses anything else.

Upstream owns its GPU DSL/compiler support and SDKs. Install the `forge` extra in
the GPU runtime environment (it also pulls the agent SDK dependencies):
the GPU runtime environment (it also pulls the agent SDK dependencies). Through
Docker, name the pinned checkout on the host:

```bash
HYPERLOOM_ROOT=/path/to/Hyperloom make docker-setup-forge
HYPERLOOM_ROOT=/path/to/Hyperloom make docker-run CONFIG=<forge-run-config>
```

For `forge` runs the runner mounts `HYPERLOOM_ROOT` read-only, provisions the
agent backend's CLI and authentication (Claude Code unless the run sets
`agent.agent_backend: codex`), forwards Claude credentials by name as for GEAK,
and prepends `.aka-pyuserbase/forge-engine/<Python cache tag>` to `PYTHONPATH`,
since an image upgrade can change the Python ABI. Setup installs the
committed `HEAD` of `HYPERLOOM_ROOT` there with `pip install --target`, from an
exported copy because setuptools builds in tree. It records the revision in
`.aka-hyperloom-revision` and warns that uncommitted changes are not installed.
Run and preflight repeat the install only when that revision changes, then
require `agents/forge/engine.py --arena-probe` to pass. Outside Docker, install
into the interpreter directly:

```bash
# HYPERLOOM_ROOT names the separately mounted/pinned checkout in the container.
python3 -m pip install "${HYPERLOOM_ROOT}[forge]"
python3 agents/forge/engine.py --arena-probe
```
Expand Down
6 changes: 4 additions & 2 deletions agents/geak/bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ def copy_task(source: Path, destination: Path, *, remaining: Callable[[], float]

def snapshot_mapping(snapshot: WorkspaceSnapshot) -> dict:
return {"digests": snapshot.digests,
"initial_symbols": {k: sorted(v) for k, v in snapshot.initial_symbols.items()}}
"initial_symbols": {k: sorted(v) for k, v in snapshot.initial_symbols.items()},
"initial_patching": snapshot.initial_patching}


class Bridge:
Expand All @@ -218,7 +219,8 @@ def _guard(self, root: Path, key: str = "harness") -> None:
saved = self.job[key]
verify_workspace_harness(WorkspaceSnapshot(
root, saved["digests"], self.spec,
{k: frozenset(v) for k, v in saved["initial_symbols"].items()}))
{k: frozenset(v) for k, v in saved["initial_symbols"].items()},
saved.get("initial_patching")))

def baseline_unchanged(self) -> None:
self._guard(self.context.baseline, "baseline_harness")
Expand Down
9 changes: 5 additions & 4 deletions agents/geak/compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ def adapt_lane(source: str) -> str:
return source


def arena_contract(bridge: Bridge, python: str) -> str:
def arena_contract(bridge: Bridge, python: str, knowledge: str = "") -> str:
command = shlex.join([python, str(Path(__file__).with_name("bridge.py")),
"--job", str(bridge.job_path)])
spec = bridge.spec.to_mapping()
return f"""Arena task contract (takes precedence over upstream layout/harness examples)
contract = f"""Arena task contract (takes precedence over upstream layout/harness examples)
Target language: {bridge.spec.candidate.language}. Initial state: {bridge.spec.candidate.initial_state}.
Read the task's config.yaml, README.md if present, declared instructions and entrypoints.
Keep all relative paths, multifile interfaces, and symbol-scoped restrictions exactly as declared:
Expand Down Expand Up @@ -141,9 +141,10 @@ def arena_contract(bridge: Bridge, python: str) -> str:
Upstream analysis/KB source is advisory; runtime dependencies are provisioned by Arena.
GEAK metrics guide search only. Arena independently evaluates delivered candidate files.
"""
return contract + (f"\n{knowledge}" if knowledge else "")


def prepare_engine(checkout: Path, bridge: Bridge, *, python: str, options: dict) -> dict:
def prepare_engine(checkout: Path, bridge: Bridge, *, python: str, options: dict, knowledge: str = "") -> dict:
verify_upstream(checkout, remaining=bridge.remaining)
bridge.remaining()
private = bridge.root / "engine"
Expand All @@ -156,7 +157,7 @@ def prepare_engine(checkout: Path, bridge: Bridge, *, python: str, options: dict
roles = Path(__file__).with_name("roles")
for role in roles.glob("*.md"):
copy_file(role, workflow / "roles" / role.name, remaining=bridge.remaining, overwrite=True)
contract = arena_contract(bridge, python)
contract = arena_contract(bridge, python, knowledge)
dispatcher = workflow / "kernel_workflow.js"
for role in (workflow / "roles").glob("*.md"):
bridge.remaining()
Expand Down
10 changes: 9 additions & 1 deletion agents/geak/launch_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from agents import register_agent
from agents.geak.workflow_runner import _read_json
from src import knowledge_wiki
from src.harness_guard import snapshot_workspace_harness
from src.task_execution import _run_process
from src.task_spec import load_task_spec
Expand Down Expand Up @@ -175,6 +176,7 @@ def prepare_job(context: TaskContext, run_dir: Path, options: dict, *,
@register_agent("geak")
def launch_agent(eval_config: dict, task_config_dir: str, workspace: str) -> str:
options = load_options(eval_config)
wiki = knowledge_wiki.resolve(eval_config)
started = time.monotonic()
deadline = started + options["timeout_seconds"]
deadline_epoch = time.time() + options["timeout_seconds"]
Expand Down Expand Up @@ -204,7 +206,13 @@ def launch_agent(eval_config: dict, task_config_dir: str, workspace: str) -> str
status = {"status": "FAILED", "delivery": "NOT_ATTEMPTED", "arena_acceptance": "PENDING"}
try:
bridge = prepare_job(context, run_dir, options, deadline=deadline, deadline_epoch=deadline_epoch)
bridge.job["engine"] = prepare_engine(checkout, bridge, python=python, options=options)
knowledge = ""
if wiki is not None:
wiki_log = run_dir / knowledge_wiki.LOG_NAME
knowledge = wiki.instructions(python, wiki_log)
status["knowledge_wiki"] = {**wiki.identity(), "log": str(wiki_log)}
write_json(run_dir / "knowledge_wiki.json", status["knowledge_wiki"])
bridge.job["engine"] = prepare_engine(checkout, bridge, python=python, options=options, knowledge=knowledge)
write_json(bridge.job_path, bridge.job)
code = _run_engine(bridge, python)
result_path = run_dir / "engine_result.json"
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ python -m sphinx -T -b html docs docs/_build/html
| `how-to/task-validator.md` | How-to | Current task-validator execution, checks, and framework-finalized reports. |
| `how-to/quality-loop.md` | How-to | Repository-wide validation, one-pass optimization, task hardening, and single-draft-PR publication. |
| `how-to/held-out-evaluation.md` | How-to | Generate private shapes and evaluate completed runs for generalization. |
| `how-to/knowledge-wiki.md` | How-to | Offer a read-only kernel knowledge base to GEAK, with every query logged. |
| `how-to/visualization.md` | How-to | Build dashboard data and serve the comparison dashboard. |
| `examples/examples.md` | Examples | Step-by-step walkthroughs with expected output. |
| `about/license.md` | License | Apache 2.0 notice and link to the full repository `LICENSE`. |
Expand Down
16 changes: 15 additions & 1 deletion docs/how-to/add-task.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,21 @@ protected function definitions. Existing editable non-entrypoint configuration
helpers must pass a restricted body check: configuration data/local assignments,
returns, and branches using protected predicates or supported configuration
operations. Initial aliases, kernel entrypoints, and newly introduced factories
do not gain permission to run at definition time. The guard reports its
do not gain permission to run at definition time. Every editable Python file,
whatever its scope, also may not add runtime patching: calls to `globals()`,
`vars()`, `setattr`/`delattr`, `exec`/`eval`/`__import__`, `importlib` or frame
inspection (`sys._getframe`, `inspect.currentframe`), reads of code-object and
frame internals (`__code__`, `__globals__`, `f_back`, ...), assignments to an
imported module or object (`torch.Tensor.contiguous = ...`) or through an
attribute chain (`t.Tensor.contiguous = ...`), and rebinding an imported name.
Every editable C/C++/HIP file may not add library operator calls outside
comments: hipBLAS, hipBLASLt, rocBLAS, Tensile or MIOpen calls, and the
ATen/torch matrix products, softmax, losses, norms and reductions a task asks
the candidate to implement (`at::matmul`, `torch::mm`, `at::layer_norm`,
`.bmm(`, `.softmax(`, `.sum(`, ...). The host code of a Triton candidate, outside
its `@triton.jit` functions, may not add PyTorch or library operators either
(`torch.matmul`, `F.softmax`, `x @ w`, `torch.ops.*`, `aiter`, `flash_attn`, ...).
Sites the starting file already has stay allowed. The guard reports its
effective policy in the validator context. It is a structural integrity check,
not isolation of arbitrary Python code; reference/test manipulation remains
forbidden and subject to semantic review.
Expand Down
73 changes: 73 additions & 0 deletions docs/how-to/knowledge-wiki.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
myst:
html_meta:
"description": "Offer a read-only kernel knowledge base to the GEAK agent of an AgentKernelArena run, with every query logged."
"keywords": "AgentKernelArena, knowledge base, ROCmKernelWiki, GEAK, A/B testing"
---

# Offer a kernel knowledge base to agents

A run can give its agents read-only access to a kernel knowledge base checkout
that follows the [KernelWiki](https://github.com/mit-han-lab/KernelWiki) layout,
such as [ROCmKernelWiki](https://github.com/jhinpan/ROCmKernelWiki). The feature
exists for A/B experiments that compare the same agent with and without the
knowledge base. Both arms of such an experiment must differ only in this setting.

The GEAK agent supports it. A run that enables it for any other agent fails
before its first task.

## Enable it

Add the run-level key to the configuration of the knowledge-base arm only:

```yaml
agent:
template: geak
knowledge_wiki:
enabled: true
```

Name the checkout on the host when starting the run:

```bash
AKA_KNOWLEDGE_WIKI_ROOT=/path/to/ROCmKernelWiki make docker-run CONFIG="$CONFIG_PATH"
```

For a run that enables `knowledge_wiki`, the Docker runner mounts that checkout
read-only at the same path and forwards `AKA_KNOWLEDGE_WIKI_ROOT`. Runs that do
not enable it neither mount the checkout nor receive the variable. Keep the checkout
outside the AgentKernelArena repository, because the repository root is mounted
into every container.

The checkout must provide `scripts/query.py`, `scripts/get_page.py` and
`scripts/grep_wiki.py`. The run stops with an error when the key is enabled but
the variable or these scripts are missing.

## What agents see

GEAK appends the instructions from `src/knowledge_wiki.py` to the Arena contract
on every role and Workflow call, and its agents query from the shell:

```text
<python> src/knowledge_wiki.py --root <checkout> --log <log> search "<question>" [filters]
<python> src/knowledge_wiki.py --root <checkout> --log <log> page <page-id>
<python> src/knowledge_wiki.py --root <checkout> --log <log> grep "<regex>"
```

The command passes the knowledge base's own output and exit status through
unchanged. The instructions name only the options these knowledge bases share
and point agents at each subcommand's `--help` for the rest.

## Logs and identity

Every query appends one JSON line to `knowledge_wiki_calls.jsonl` in the hidden
GEAK run directory. Each line records the timestamp, subcommand, arguments, exit
code, duration, output size, and the page IDs or files returned.

The adapter status records the checkout's commit, whether its tree was dirty,
and the instructions version and the SHA-256 of the text it delivered. GEAK also
writes them to `knowledge_wiki.json`, and the run log repeats them at startup.
Compare these values across arms before comparing results.

A knowledge-base arm whose log is empty received the instructions but never used
the knowledge base. Report that count rather than dropping the run.
7 changes: 7 additions & 0 deletions docs/how-to/run-evaluation.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ For debugging, enter the same Docker runtime used by the experiment:
make docker-shell
```

To run one command non-interactively in that runtime, without provisioning an
agent CLI or forwarding credentials (for example, a baseline-only measurement):

```bash
AKA_VISIBLE_GPU=0 bash src/scripts/docker_benchmark.sh exec python3 <script> [args...]
```

The Docker runner currently supports Codex, Claude Code, and Cursor Agent login
reuse from the host. It preflights the selected config before starting the run.

Expand Down
2 changes: 2 additions & 0 deletions docs/sphinx/_toc.yml.in
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ subtrees:
title: Audit and harden tasks
- file: how-to/held-out-evaluation
title: Evaluate on held-out shapes
- file: how-to/knowledge-wiki
title: Offer a kernel knowledge base to agents
- file: how-to/visualization
title: Visualize and compare runs

Expand Down
5 changes: 5 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright(C) [2026] Advanced Micro Devices, Inc. All rights reserved.
import argparse
import json
import logging
import os
import re
Expand All @@ -9,6 +10,7 @@

import yaml

from src import knowledge_wiki
from src.tasks import get_task_config
from src.preprocessing import (
get_task_workspace_path,
Expand Down Expand Up @@ -347,6 +349,7 @@ def _build_context(
return None
try:
validate_run_budget_mode(agent.value, config["agent"])
wiki = knowledge_wiki.validate_run(config, agent.value)
except ValueError as error:
print(f"Error: {error}")
return None
Expand All @@ -364,6 +367,8 @@ def _build_context(
logger = _configure_logging(config, agent, timestamp, run_directory_name, args, role=role)
logger.info(f"Agent: {agent.value}")
logger.info(f"Target Architecture: {config['target_gpu_model']}")
if wiki is not None:
logger.info(f"Knowledge wiki: {json.dumps(wiki.identity(), sort_keys=True)}")
logger.info(f"Workspace Directory: {workspace_directory}")
logger.info(f"Run Directory: {run_directory}")
logger.info(f"{'RESUME' if resume_mode else 'NEW'} RUN: {run_directory_name}")
Expand Down
Loading
Loading