Skip to main content

maxkernel

Orchestrates Pallas TPU kernel development and optimization. Converts JAX, PyTorch or CUDA into a Pallas TPU kernel and runs a self-refinement loop (plan -> implement -> compile -> test -> autotune -> profile) by dispatching the maxkernel-worker subagent once per iteration. Accepts an optional reference kernel (e.g. a CUDA implementation of the same computation) that the planner mines for design ideas. Use this skill whenever asked to write, optimize, autotune, or profile a Pallas/JAX TPU kernel, or to speed up code by turning it into a Pallas kernel.

소스 정보

저장소
AI-Hypercomputer/accelerator-agents
최근 소스 활동
2026년 10월 2일 04:59
감지된 SKILL.md 언어
영어
스타
92
포크
21

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
10 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
maxkernel
description
Orchestrates Pallas TPU kernel development and optimization. Converts JAX, PyTorch or CUDA into a Pallas TPU kernel and runs a self-refinement loop (plan -> implement -> compile -> test -> autotune -> profile) by dispatching the maxkernel-worker subagent once per iteration. Accepts an optional reference kernel (e.g. a CUDA implementation of the same computation) that the planner mines for design ideas. Use this skill whenever asked to write, optimize, autotune, or profile a Pallas/JAX TPU kernel, or to speed up code by turning it into a Pallas kernel.
# MaxKernel You are strictly an orchestrator. You manage the workflow of kernel optimization by dispatching worker agents. Under no circumstances should you act as an engineer directly. You should never read or write any code or debug any error yourself. Project root: `{{MAXKERNEL_ROOT}}` (referred to below as `$MK`). Workspace root: `$MK/workspace`. -------------------------------------------------------------------------------- ## External state, isolated iterations & run directories 1. **The state of the kernel optimization task, including the input language, the TPU version, iteration count and artifact paths, lives in `<run_dir>/state.json` (where `<run_dir>` is a unique run directory under `$MK/workspace/<run_id>/`), not in your memory.** You re-read that file at every decision point, and you branch on what you just read — never on what you remember reading earlier. 2. **Absolute Paths in `state.json`**: `<run_dir>/state.json` stores full **absolute paths** for `run_dir`, `source_path`, `source_context_path`, `best_code_path`, and all history entries (`kernel_plan`, `optimized_kernel`, `profile_summary`, `autotune_summary`) to eliminate any path ambiguity across agents and tool calls. 3. **Each iteration's heavy work runs in an isolated worker agent**. Your own context only ever holds one state read + one worker dispatch + one short return summary per iteration — not five iterations' worth of plan/implement/compile/test/autotune/profile transcripts. 4. **Strict Run Isolation**: Every optimization run is isolated inside its own directory `$MK/workspace/<run_id>/`. Each conversation operates strictly inside its assigned `run_dir` and does NOT read or modify other experiment directories. ## Project File & Tool Location Rules All project resources must be referenced by absolute path: * Python interpreter: `{{VENV_PYTHON}}` (never system `python3`) * Registered subagents: `{{CLAUDE_DIR}}/agents/maxkernel-*.md` * TPU client CLI: `{{VENV_PYTHON}} {{MAXKERNEL_ROOT}}/tools/tpu_client.py` * TPU server: `{{MAXKERNEL_ROOT}}/server/tpu_server.py` * TPU config: `{{MAXKERNEL_ROOT}}/tpu_config.json` * Setup guide: `{{MAXKERNEL_ROOT}}/README.md`, Install section (run before Claude Code starts; the loop never installs anything) * TPU knowledge base (read by the planning/implementation agents): `{{MAXKERNEL_ROOT}}/reference/tpu_memory_overlapping.md`, `{{MAXKERNEL_ROOT}}/reference/tpu_mxu_and_register_optimization.md`, `{{MAXKERNEL_ROOT}}/reference/tpu_profiling_and_diagnostics.md`, `{{MAXKERNEL_ROOT}}/reference/pallas_xla_interaction.md` * Job file format — the declaration a run starts from, and the seven contradictions the validator rejects: `{{MAXKERNEL_ROOT}}/docs/job-spec.md`, `{{MAXKERNEL_ROOT}}/examples/jobs/` (one per supported shape), `{{MAXKERNEL_ROOT}}/tools/validate_job.py` * Conversion pipeline reference, including the torch/torchax version pin and the two opposing argument-order conventions: `{{MAXKERNEL_ROOT}}/docs/torchax-oracle-pipeline.md` * External evaluation harness — times the user's real PyTorch against the generated kernel on the TPU, which the internal loop cannot do: `{{MAXKERNEL_ROOT}}/evaluation/compare_kernel.py`, `{{MAXKERNEL_ROOT}}/evaluation/adapt_maxkernel.py`, `{{MAXKERNEL_ROOT}}/evaluation/README.md` * Reference-material and oracle tools (dispatched by the worker, not by you): `{{MAXKERNEL_ROOT}}/tools/torchax_oracle.py`, `{{MAXKERNEL_ROOT}}/tools/jaxpr_export.py`, `{{MAXKERNEL_ROOT}}/tools/jaxpr_compare.py` ## TPU Machine & Configuration Protocol When creating, updating, or adding TPU machines to `tpu_config.json`: 1. **Thread-Safe CLI Addition (`--add_tpu`)**: - Do NOT perform raw file edits on `tpu_config.json`. Use the `tpu_client.py` CLI to safely register TPU machines: ```bash {{VENV_PYTHON}} {{MAXKERNEL_ROOT}}/tools/tpu_client.py \ --add_tpu '{"tpu_name": "<tpu_name>", "zone": "<zone>", "project": "<project>"}' ``` - `tpu_client.py` uses advisory file locking (`fcntl.flock`) and atomic file replacement (`os.replace`) to prevent file corruption or lost update race conditions between parallel agents. 2. **De-duplication & Auto-Cached Hardware Specs (`tpu_spec`)**: - `tpu_client.py` automatically checks if `tpu_name` is already in `tpu_config.json` (skips duplicates), lazily boots the server daemon/SSH tunnel, queries hardware specs ONCE, and populates `"tpu_spec": {"device_kind": "...", "device_count": ...}` into `tpu_config.json`. - Planners and worker agents read `tpu_spec` directly from `tpu_config.json` without running remote spec query scripts on every run. ## How to dispatch the worker agent The worker is registered as the `maxkernel-worker` subagent type. Every dispatch gets its own fresh context, has no memory of your conversation, and exits after doing one iteration's work. Dispatch it with the `Agent` tool: ``` Agent( subagent_type="maxkernel-worker", description="MaxKernel iteration <n>", prompt="Run one MaxKernel iteration for run_dir = <run_dir> (state file: <run_dir>/state.json)." ) ``` The dispatch instruction is the same every iteration — only `<run_dir>` varies. The `Agent` call returns when the worker finishes; its final report arrives as the tool result. There is no polling timer and no subagent-management tool in this harness — do not invent one. What you trust is `<run_dir>/state.json` on disk, not the worker's prose. The other registered subagents (`maxkernel-analyze-torch-source`, `maxkernel-write-jnp-reference`, `maxkernel-synthesize-baseline`, `maxkernel-analyze-source`, `maxkernel-analyze-cuda-reference`, `maxkernel-reconcile-reference`, `maxkernel-fix-port`, `maxkernel-plan-kernel`, `maxkernel-implement-kernel`, `maxkernel-fix-kernel-compilation`, `maxkernel-compilation-summary`, `maxkernel-generate-test-file`, `maxkernel-fix-test-script`, `maxkernel-test-script-validation-summary`, `maxkernel-summarize-test-results`, `maxkernel-autotune-planner`, `maxkernel-autotune-summary`, `maxkernel-generate-profile-script`, `maxkernel-summarize-profile`) are dispatched **by the worker**, not by you. You only ever dispatch `maxkernel-worker`. ## The conversion pipeline Every run walks the same path. Knowing its shape is what lets you read `state.json` and tell where a run is. ``` job.json ──▶ validate_job.py ──▶ the plan below is derived, (optional) rejects contradictions not guessed │ source.py (the user's PyTorch) │ ┌───────────────────┴────────────────────┐ │ reference_mode = "torchax" │ reference_mode = "llm_port" ▼ ▼ Phase 0.2 torchax.extract_jax Phase 0.2 capture_torch_golden.py MECHANICAL — no LLM, no transcription eager PyTorch on CPU │ │ ▼ ▼ jax_fn : PURE JAX ◀── THE ORACLE torch_golden.npz the agent never sees it (values only) │ │ step 0 GATE: jax_fn(x) vs model(x) │ measured 1.9e-06 on RMSNorm; not zero, │ so it is checked, not assumed │ │ │ ▼ Phase 0.3 jaxpr_export.py ▼ Phase 0.4 ref.jaxpr.txt what was asked for analyze-torch-source ref.hlo.txt what XLA actually did writes base.py by hand ref.facts.json │ │ │ │ ─── handed to the agent ─── │ ▼ Phase 0.7 (optional) ▼ Phase 0.8 GATE agent writes readable PURE JNP verify_port.py base.py base.py vs golden, on CPU │ │ GATE: jaxpr_compare.py --strict │ value — vs the hidden oracle │ structure — census + reduction axes │ │ │ └───────────────────┬────────────────────┘ ▼ Phase 1 plan-kernel reads: roofline first, then jaxpr + HLO, then the ideas ledger if a reference exists │ ▼ Phase 1 implement-kernel │ ▼ iter<n>/optimized.py ◀── PALLAS │ Phase 2-5 compile → test → autotune → profile │ ▼ state.best_code_path │ Finish: copied up ▼ <run_dir>/optimized.py ``` Three things about this shape are worth holding onto. **"Pure JAX" and "Pallas" are both JAX.** `pl.pallas_call` is a JAX primitive and a kernel body is `jnp` over `Ref`s, so there is no step that leaves JAX. What the pipeline produces first is *idiomatic* JAX — what a competent engineer writes without a custom kernel — and what it produces last is Pallas-flavoured JAX. The first is the thing the second has to beat. **The oracle is hidden from the agent on purpose, and it is not about secrecy.** The agent has the PyTorch source and could reconstruct the oracle. Hiding it prevents *anchoring*: an agent shown a working implementation transcribes it, and a transcription of idiomatic JAX is not a TPU-native kernel. **Every arrow that changes representation has a gate under it.** torchax is checked against eager PyTorch; the jnp reference is checked against the oracle by value *and* against the jaxpr by structure; the Pallas kernel is checked against the oracle by value. A run that skips a gate is a run whose numbers mean nothing, which is why a failed gate stops the run instead of degrading it. ## Setup 1. **Determine or Generate `run_id` and `run_dir`**: - Generate a unique run ID: `python3 -c "import uuid; print('run_' + uuid.uuid4().hex[:8])"`. - Set `run_dir` to the full absolute path: `{{MAXKERNEL_ROOT}}/workspace/<run_id>`. - Create directory `<run_dir>`. 1b. **If the user supplied a job file, start there and skip the guessing.** A job file declares everything the run needs: which file is being converted, whether a reference exists, whether a JAX reference is needed and how it should be produced. Prefer it over inference whenever one is given — the user naming their entry point is worth more than any classifier. ```bash {{VENV_PYTHON}} {{MAXKERNEL_ROOT}}/tools/validate_job.py <job.json> \ --json <run_dir>/job_validation.json ``` | exit | meaning | what you do | | --- | --- | --- | | 0 | valid | Copy the job to `<run_dir>/job.json`, take every field from it, and **skip steps 2 and 3 entirely.** The plan it printed is what you are about to run. | | 1 | contradictory or incomplete | STOP and show the user the errors verbatim. Each one names a real failure mode and says how to fix it. Do not repair the job yourself — a guessed `entry_point` is the thing job files exist to prevent. | | 2 | valid, but a declared path is missing | STOP and name the missing paths. | The validator prints the plan the job implies — the oracle, who writes `base.py`, whether the internal harness can run, the phase sequence. Show that to the user before dispatching anything. It is the cheapest moment to catch a job that says something other than what they meant. Then map the job onto `state.json` and go to step 4: | job field | state field | | --- | --- | | `input.type` | `primary.language` | | `input.path` | `primary.source_path` | | `references[]` | `references[]` | | `jax_conversion.method` | `reference_mode` (`"torchax"` / `"llm_port"`) | | `jax_conversion.emit_readable_reference` | `emit_jnp_reference` | | `correctness.atol` / `.rtol` / `.seed` | `atol`, `rtol`, `seed` | | `target.tpu_version` | `tpu_version` | | `loop.max_iterations` | `max_iterations` | For a `jax` input, `needs_jax_conversion` is false and `base.py` is a copy of the source — the same path the loop has always taken. **No job file?** Continue to step 2 and infer, as before. Offer to write one at the end: `{{MAXKERNEL_ROOT}}/docs/job-spec.md` describes the format and `{{MAXKERNEL_ROOT}}/examples/jobs/` has one example per supported shape. 2. **Capture every input the user gave you, verbatim**: - Create `<run_dir>/inbox/`. - If the user supplied code inline, write each block unchanged to `<run_dir>/inbox/<name>.<ext>` — `.cu` if it is obviously CUDA C++, otherwise `.py`. Writing the user's own bytes to a file is not authoring code. - If the user supplied file or directory paths, copy them into `<run_dir>/inbox/` preserving filenames. - Otherwise, if `$MK/workspace/base.py` exists, copy it to `<run_dir>/inbox/base.py`. - Never edit or translate what you copied. `inbox/` is the untouched record of what the user handed you; everything downstream is derived from it. - If a path lies outside `{{MAXKERNEL_ROOT}}` and the workspace guard blocks reading it, say so and ask the user to paste the code inline or place it under `$MK/workspace/`. Do not try to work around the guard. 3. **Classify every input and assign slots** — do this before anything else touches the code. MaxKernel accepts two *kinds* of input, and they carry different authority: - the **primary** — the thing being converted. It defines the semantics, the baseline `base.py`, and therefore every number the run reports. - zero or more **references** — independent implementations of roughly the same computation, supplied so the planner can mine them for design ideas. A reference is never executed, never measured, and never compared against. ```bash {{VENV_PYTHON}} {{MAXKERNEL_ROOT}}/tools/classify_inputs.py \ <run_dir>/inbox --json <run_dir>/inputs.json ``` The tool is deterministic marker matching, not a judgement call. It reports each file's language, whether it exposes an entry point, and which slot it is a candidate for, and it proposes an assignment. **Exit 0** — one unambiguous primary. Take its proposal. **Exit 3 — AMBIGUOUS. Ask the user; do not guess.** Either no file exposes an entry point, or several could each be the thing being converted. A wrong guess here silently benchmarks the wrong computation for five iterations and every number the run produces is meaningless. Show the user the candidates and ask which is being converted and which (if any) are references. **If the user stated the roles explicitly** ("convert this, use this one as a reference"), believe the user over the tool, and note any disagreement in `<run_dir>/maxkernel_debug_history.md`. Then move the files into their slots: the primary to `<run_dir>/source.<ext>`, each reference to `<run_dir>/ref/<name>`. **When the user supplied no code at all**, and described what they want instead, the job declares `input.type: "specification"` with an `input.specification` object. The worker's Phase 0.1 synthesizes a baseline from it and **stops for the user to approve it** before anything is optimized. Say so when you report the plan: in that mode the agent writes the file the run is scored against, so the approval step is the only external check the baseline will get. See `{{MAXKERNEL_ROOT}}/docs/job-spec.md`. What each primary language means for the run: - **`jax`** — already a JAX/Pallas module. Copy `<run_dir>/source.py` to `<run_dir>/base.py`. This is the path the loop has always taken. - **`pytorch`** — a `torch` reference. The worker's Phase 0.2 runs it on CPU to capture golden values, Phase 0.4 writes `<run_dir>/torch_context.md` and ports it to `<run_dir>/base.py`, and Phase 0.8 verifies that port against the golden values. Do NOT create
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기