Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
2fd5ba1
runtime: the batch wire format, with no field for an address
sriharshapy Aug 10, 2026
ddded37
runtime: the IDL, qaic generation, and the MIT attribution it obliges
sriharshapy Aug 10, 2026
8bd50ef
runtime: a test that fails if qaic's fail-closed check is removed
sriharshapy Aug 10, 2026
3d9c0b6
runtime: generate DSP entry points from the spec that already declare…
sriharshapy Aug 10, 2026
c2ce470
runtime: make the requires tests distinguish checked from documented
sriharshapy Aug 10, 2026
8980275
skel: the host writes fds and offsets, the DSP writes addresses
sriharshapy Aug 10, 2026
6430ca9
skel: test the clear-before-lookup invariant where it lives, not by f…
sriharshapy Aug 10, 2026
30a0cb3
skel: VTCM size from the runtime, and the reclaim callback registered
sriharshapy Aug 10, 2026
05dcaca
skel: test that every VTCM failure path returns a status
sriharshapy Aug 10, 2026
3d8c14e
skel: batch walk, PCYCLE around the kernel call only, failure as the …
sriharshapy Aug 10, 2026
a281603
runtime: the simulator host and the qexe link, from a recipe known to…
sriharshapy Aug 10, 2026
09d19f6
runtime: say plainly what the simulator path does not prove
sriharshapy Aug 10, 2026
938a8f2
host: dlopen the driver, unsigned PD on CDSP, and no address on the wire
sriharshapy Aug 10, 2026
d38e04f
host: tighten the URI, dlopen and request-id tests to check use, not …
sriharshapy Aug 10, 2026
0dfb41c
runtime: a QuRT-hosted sim build, so VTCM acquisition is really exerc…
sriharshapy Aug 10, 2026
c67654c
docs: retarget Task 8 and the spec at the QuRT-hosted sim build
sriharshapy Aug 10, 2026
c5016e6
docs: mark the standalone qexe link recipe superseded, with the reason
sriharshapy Aug 10, 2026
ccae3fb
runtime: actually git-ignore the generated sim configs, and say where…
sriharshapy Aug 10, 2026
d0ef88c
chore: untrack two simulator artifacts I committed by accident
sriharshapy Aug 10, 2026
0a6225e
stage 1 GREEN: scale_fp16 through the skel batch path on the simulato…
sriharshapy Aug 11, 2026
2920c5f
stage 2: cross-compile hexlib_run for arm64 and the skel as a device .so
sriharshapy Aug 11, 2026
5fa5203
qdc: submit, and detect completion from log files rather than job status
sriharshapy Aug 11, 2026
df3a8bf
qdc: use the SDK's own API-key client, and stop requiring a base URL …
sriharshapy Aug 11, 2026
897f4ac
host: define the remote_handle64 forwarders, so the driver stays dlop…
sriharshapy Aug 11, 2026
e3bc6f7
tests: one comment-aware block matcher, so 40 source assertions inspe…
sriharshapy Aug 11, 2026
765d786
qdc: the on-device test, and --device on the CLI
sriharshapy Aug 11, 2026
f9edc3b
host: --unmapped, --coherency-check, and print the DSP's cycle count
sriharshapy Aug 11, 2026
ba5762a
docs: the handoff record said three flags did not exist -- they lande…
sriharshapy Aug 11, 2026
8b35c00
fix: the arch check could never pass, coherency misfired on -0.0, and…
sriharshapy Aug 11, 2026
63becd3
tests: prove the -0.0 coherency fix behaviourally, and stop skipping …
sriharshapy Aug 11, 2026
9af5803
tests: the slicer was comment-aware only at its boundaries, so payloa…
sriharshapy Aug 11, 2026
07d0cee
tests: CI ran zero tests and exited 2, and the guard against that was…
sriharshapy Aug 11, 2026
f864ead
docs: the HVX-clean rule banned what ATTRIBUTION.md deliberately does
sriharshapy Aug 11, 2026
7af6cd3
runtime: requires was enforced on neither side of the DSP transport
sriharshapy Aug 11, 2026
853ef57
docs: rewrite the front door, and fix three numbers that were wrong i…
sriharshapy Aug 11, 2026
eb8ab1e
ci: the `|| pip install pytest` fallback could never fire, so pytest …
sriharshapy Aug 11, 2026
4d64ee2
runtime: the DSP's cycle read had no handling of the one bit it depen…
sriharshapy Aug 11, 2026
ddb068d
skel: one contended VTCM page would have failed every session on silicon
sriharshapy Aug 11, 2026
e35fb30
skel: hwinfo claimed five DSP facts and reports one
sriharshapy Aug 11, 2026
e346808
tests: an "outputs first" refactor would have swapped every kernel's …
sriharshapy Aug 11, 2026
d3f39ce
qdc: a 3-minute budget would submit a 240-minute job, and a skipped t…
sriharshapy Aug 11, 2026
3e2d362
qdc: the traversal guard only held on the OS you happened to test on
sriharshapy Aug 11, 2026
8b20443
docs: the address claim was false for base, and three published figur…
sriharshapy Aug 11, 2026
1fe8871
tests: blanking comments closed one vehicle for C2 and left the strin…
sriharshapy Aug 11, 2026
67766e4
exec: layernorm gated green for a day without being dispatchable at all
sriharshapy Aug 11, 2026
a7f586f
fix: the four remaining Importants from the merge gate
sriharshapy Aug 11, 2026
ca41626
test: the simhost fd-patch bound, checked on the simulator rather tha…
sriharshapy Aug 11, 2026
29aa165
test: the simhost bound test was green with the bound removed
sriharshapy Aug 11, 2026
dd0ca96
runtime: the block-quantized weight path, so matmul_epilogue can exist
sriharshapy Aug 11, 2026
fd0c1ca
kernels: transpose_hd_fp16, the perm(0,2,1) the sibling kernel called…
sriharshapy Aug 11, 2026
ed81390
kernels: softmax_fp16 and rope_2d_fp16, both vectorised and both disc…
sriharshapy Aug 11, 2026
27eae11
runtime: one op kind, several kernels -- SPECS keyed by variant
sriharshapy Aug 11, 2026
922f29f
exec: softmax and rope_2d dispatch -- coverage 111 -> 159 of 259
sriharshapy Aug 11, 2026
b58c207
kernels: patchify_fp32, and `merge` is not metadata
sriharshapy Aug 11, 2026
0e14272
test: the four new kernels actually dispatch, and _out_shape had to l…
sriharshapy Aug 11, 2026
9568dae
exec: Scalar.codes, so a string attr can cross a wire that carries on…
sriharshapy Aug 11, 2026
5085054
fix: eight of the merge gate's Minors, and one of them was wrong
sriharshapy Aug 11, 2026
f6d1bd0
exec: a reference q4_0 quantizer, because nothing in the tree could m…
sriharshapy Aug 11, 2026
62edbab
test: the whole encoder end to end, every kernel on the simulator's D…
sriharshapy Aug 11, 2026
bff4d66
kernels: matmul_epilogue_fp16, q4_0 weights through bias and gelu
sriharshapy Aug 12, 2026
9a2c99d
fix: the gate's simulator ceiling was below what a scalar near-miss c…
sriharshapy Aug 12, 2026
23e3049
gate: attribute a simulator timeout instead of guessing at it
sriharshapy Aug 12, 2026
7a41e96
kernels: matmul_fp16, the encoder's 24 attention matmuls
sriharshapy Aug 12, 2026
18b4e14
qdc: the first two reasons a device job could never report anything
sriharshapy Aug 12, 2026
a491774
qdc: the tests run on the runner and reach the phone by adb, not on t…
sriharshapy Aug 12, 2026
94e2def
qdc: a flat zip is accepted, dispatched, and never runs
sriharshapy Aug 12, 2026
964ee1a
exec: matmul dispatches -- 160 of 259 encoder ops becomes 184
sriharshapy Aug 12, 2026
7094ac8
exec: matmul_epilogue dispatches -- q4_0 weights across the wire
sriharshapy Aug 12, 2026
03ccd9c
test: the encoder runs with no reference fallback at all
sriharshapy Aug 12, 2026
da83304
test: the encoder's coverage number, asked of select() not of a tally
sriharshapy Aug 12, 2026
cf25017
fix: matmul_fp16 read B rows aligned, and only a multiple-of-64 N mad…
sriharshapy Aug 12, 2026
9ecaf15
fix: two claims made today that measurement did not support
sriharshapy Aug 12, 2026
06cc2a4
fix: gate matmul_fp16 at N=200, the shape the aligned-load bug hid be…
sriharshapy Aug 12, 2026
91ad9de
qdc: the first path that reaches silicon, and what it found there
sriharshapy Aug 12, 2026
62f67eb
kernels: patchify_fp32's RESULT.md timestamp, from a re-measurement
sriharshapy Aug 13, 2026
524a41f
docs: untrack docs/ entirely, and fix the one test that depended on it
sriharshapy Aug 13, 2026
30479e1
exec: the whole encoder as ONE batch -- a single entry into the DSP, …
sriharshapy Aug 13, 2026
5677167
fix: the skel was linked under a name FastRPC never looks for
sriharshapy Aug 13, 2026
1e7fc54
host: --batch can stage an in-out arena, which is what a whole plan is
sriharshapy Aug 13, 2026
ab383c5
skel: write the DSP's cache back, without which the host reads stale …
sriharshapy Aug 13, 2026
3089aa9
qdc: the session can run a whole plan, and the dual-name push is gone
sriharshapy Aug 13, 2026
ab9d463
models: the checkpoint->const mapping moves into the library
sriharshapy Aug 13, 2026
da76dcc
quant: q8_0, because four bits is not enough for this encoder
sriharshapy Aug 13, 2026
da24dd3
hmx: the first HMX kernel, and the wall it hit -- DOES NOT PASS ITS GATE
sriharshapy Aug 13, 2026
c830c5a
hmx: the four things HMX needs before mxmem runs, read out of llama.cpp
sriharshapy Aug 13, 2026
7586b36
docs: the tracked documentation catches up with ten commits of measur…
sriharshapy Aug 15, 2026
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
41 changes: 41 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Normalize line endings. Without this, every commit from a Windows checkout
# prints "warning: CRLF will be replaced by LF the next time Git touches it",
# and a contributor on another platform sees whole-file diffs that contain no
# actual change.
#
# `text=auto eol=lf` means: store everything Git detects as text with LF in the
# repository, and check it out with LF everywhere, including on Windows. LF is
# the right choice rather than native because the DSP-side C is read by
# hexagon-clang and by this repo's own source-assertion tests, which slice C
# function bodies by byte offset (hexlib/tests/csource.py) -- a mixed-ending
# working tree makes those offsets platform-dependent.
* text=auto eol=lf

# Explicitly text, so no heuristic has to guess.
*.py text eol=lf
*.c text eol=lf
*.h text eol=lf
*.idl text eol=lf
*.md text eol=lf
*.json text eol=lf
*.toml text eol=lf
*.cfg text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.txt text eol=lf
*.sh text eol=lf

# Binary. Never normalize, never diff as text.
*.npz binary
*.bin binary
*.elf binary
*.so binary
*.a binary
*.png binary
*.zip binary

# The committed vision-encoder golden vectors. Marked binary explicitly rather
# than relying on the *.npz rule above, because this file is the correctness
# oracle for the whole encoder (docs/research/oracle-provenance.md) and a
# line-ending "fix" applied to it would corrupt it silently.
hexlib/tests/data/qwen35_vision_tiny.npz binary
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install -e ".[dev]" || pip install -e . pytest
# No `|| pip install -e . pytest` fallback. That was here to be a safety
# net and could not be one: pip treats a missing extra as a warning and
# exits 0, so with no `dev` extra defined the fallback never ran and
# pytest was never installed. The extra is defined in pyproject.toml now
# and this install is required to be sufficient by itself.
- run: pip install -e ".[dev]"
- run: python -m pytest -q -m "not sdk"

kernel-contract:
Expand Down
67 changes: 66 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# ---- hexlib build and verification output ----
# `hexlib test` writes ELFs, objects, disassembly, and result tables here.
_work/
#
# NOTE: these two patterns match the transient `<name>.result.md` /
# `<name>.result.json` a run drops in the working directory. They do NOT match
# `kernels/*/RESULT.md`, which is the promoted, reviewed record for a gated
# kernel and IS tracked on purpose. Do not "unify" these into `RESULT.md` or
# `*result*` -- that would untrack every kernel's evidence.
_work*/
*.result.json
*.result.md

Expand All @@ -24,11 +30,33 @@ _work/
pmu_stats*.txt
packet_analyze*.json

# QuRT-hosted simulator configs generated by
# hexlib.runtime.build.write_qurt_sim_configs (task 7b). Each is a thin,
# machine-specific reference to an SDK path (the QuRT debugger model DLL, the
# qtimer/l2vic cosim DLLs) -- regenerated on every build, and named exactly
# rather than matched by a blanket *.cfg so a config someone actually means to
# commit elsewhere in the repo is not silently swallowed.
osam.cfg
q6ss.cfg

# FastRPC / qaic generated sources (silicon path). These are generated from
# the IDL at build time; the IDL is the source of truth.
*_stub.c
*_skel.c

# Generated runtime artifacts (qaic output, skel objects, entry points)
hexlib/runtime/gen/
kernels/*/_build/
_work/runtime/

# Task 10's cross-compiled Android arm64 client (hexlib/runtime/build.py's
# build_device_binary). It is a stripped ELF executable with NO extension --
# the target is Android/aarch64, not the build host, so `tc.exe()` is never
# applied to it and none of the extension-based rules above (*.elf, *.o, ...)
# match it. Named exactly, the same way osam.cfg/q6ss.cfg are, rather than a
# blanket rule that could also swallow an unrelated file named "hexlib_run".
hexlib_run

# The Hexagon SDK is license-restricted and is NEVER vendored, bundled, or
# fetched. It is discovered through HEXAGON_SDK_ROOT. These guard against an
# accidental copy landing in the repository.
Expand Down Expand Up @@ -92,7 +120,34 @@ qdc_credentials*
# ---- Agent workspace ----
# Plan-scoped scratch: ledgers, briefs, reports, review packages. Git history
# is the durable record.
#
# Because this directory is never published, NO tracked document may cite a
# path inside it as evidence a reader can check. Where an older doc does, the
# durable record is the commit message and docs/STATE.md, not the report.
.superpowers/
.claude/

# ---- Project documentation, deliberately untracked ----
# `docs/` -- STATE.md, the design specs, the plans, the HVX tour, the research
# audits -- is kept on disk and OUT of the repository, and was purged from git
# history rather than merely untracked from here on.
#
# The consequence, stated once so nobody rediscovers it: a tracked file MAY
# still cite a `docs/...` path as provenance for a decision, and those
# citations are now unresolvable to anyone but the author. They are left in
# place because a comment naming where a fact came from is still worth more
# than no attribution -- but NOTHING tracked may DEPEND on a docs path at run
# time. One test did (`test_host_source.py`'s §6.1 coherency-table check read
# the design spec) and passed only on the machine that still had the untracked
# copy on disk; it was fixed when this rule landed, not after CI found it.
docs/

# ---- Patch and merge debris ----
*.orig
*.rej
*.bak
*.patch.tmp
*.log

# ---- Editors ----
.vscode/
Expand All @@ -116,3 +171,13 @@ $RECYCLE.BIN/

# ---- Windows / MSYS ----
*.stackdump

# ---- Simulator run artifacts, never committed ----
# A sim run writes these RELATIVE TO THE LAUNCHING PROCESS'S CWD, not to --usefs
# (see hexlib/runtime/build.py sim_qurt_command). So a suite run from the repo
# root drops them here. Two were committed by accident in f796edd via a blanket
# `git add -A` and removed in the following commit.
hexlib_out.bin
hexlib_rsp.bin
hexlib_in.bin
hexlib_batch.bin
44 changes: 39 additions & 5 deletions ATTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,45 @@ llama.cpp or ggml, and none of the copied headers reference ggml (verified by
`hexlib/tests/test_vendored_headers.py`, which fails the build if a `ggml` reference
appears in any of them, or if the vendored directory is empty).

**Deferred to plan 2 (the tile DSL / v2 spec):** ggml-hexagon's IDL, host driver
(`htp-drv.cpp`), and CMake toolchain file are also planned to be copied under this
same MIT attribution, once the DSL and device runtime work that needs them begins.
Nothing under those categories has been copied yet in this plan; when it is, this
document must be updated alongside it.
## Adapted: ggml-hexagon's FastRPC runtime (MIT)

**Source:** `ggml/src/ggml-hexagon/` in
[`ggml-org/llama.cpp`](https://github.com/ggml-org/llama.cpp).
**License:** MIT. **Copyright:** (c) 2023-2026 The ggml authors.
**Upstream commit:** `6a32c29a746a2e44de463de647f9f6661eb5086b` (2026-08-06).

hexlib's silicon-path runtime (`hexlib/runtime/`) is **adapted** from this
backend — rewritten in hexlib's own tree, not copied verbatim. What was adapted,
and from where:

| hexlib | upstream | what was taken |
|---|---|---|
| `runtime/idl/hexlib_iface.idl` | `htp/htp_iface.idl` | the session lifecycle: `start`, `stop`, `mmap`, `munmap`, `hwinfo` |
| `runtime/host/driver.c` | `htp-drv.cpp` | dlopen/dlsym of `libcdsprpc`, so a missing driver is a message rather than a loader failure |
| `runtime/skel/skel_bufs.c` | `htp/main.c` `reuse_buf`/`mmap_buf`/`prep_tensor` | fd→base mmap caching, and the **(buffer index, offset)** tensor addressing that keeps host addresses off the wire |
| `runtime/skel/skel_vtcm.c` | `htp/main.c` `vtcm_acquire`/`vtcm_alloc` | `HAP_compute_res_*` acquisition with a release callback |
| `runtime/skel/hexlib_dsp.h` | `htp/htp-ops.h` | the batch descriptor SHAPE, and `htp_status`'s "OK is 1, not 0" |
| `runtime/wire.py` | `htp/htp-ops.h` `htp_opbatch_req` | the batch request SHAPE that `wire.py:10` credits: a fixed header, then buffer descriptors, tensor descriptors and ops in one opaque blob. The Python serializer is hexlib's own; only the layout is adapted, and it is the host-side mirror of the `hexlib_dsp.h` row above |
| `runtime/skel/skel.c` | `htp/main.c` session entry points | the `open`/`close`/`start`/`stop`/`mmap`/`munmap`/`hwinfo` lifecycle qaic's skel dispatches to; `invoke` is hexlib's own (a single opaque batch, not a dspqueue packet per op) |
| `runtime/host/session.c` (`hexlib_query_caps`'s `ARCH_VER` query) | `htp-drv.cpp` `htpdrv_get_arch` | the `remote_dsp_capability` / `DSPRPC_GET_DSP_INFO` query shape. Not adapted from it: hexlib queries every capability it needs (`DOMAIN_SUPPORT`, `UNSIGNED_PD_SUPPORT`, `HVX_SUPPORT_128B`, `VTCM_PAGE`, `VTCM_COUNT`, `ARCH_VER`, `HMX_SUPPORT_DEPTH`) through one loop rather than one bespoke function per attribute, and cross-checks the **arch** against the skel's own `hwinfo` reply rather than trusting the driver alone. **Corrected 2026-08-11:** this row previously implied every capability is cross-checked. Only `arch` is. `vtcm_page × vtcm_count` vs the skel's `vtcm_size`, `hvx_support_128b` vs `n_hvx`, and `hmx_support_depth` vs `n_hmx` are queried and never compared — and `n_hvx`/`n_hmx` are host echoes rather than DSP facts anyway, so there is currently nothing on the DSP side to compare them against |
| `runtime/host/session.c` `hexlib_decode_bcd_arch` | `htp-drv.cpp` `htpdrv_get_arch` (the decode, not just the query shape) | the actual formula, copied line-for-line: `val = arch_ver & 0xff; arch = (val >> 4) * 10 + (val & 0x0f)`. **Bug found and fixed while adapting this, not upstream's:** an earlier draft of this file compared the skel's plain-decimal `__HEXAGON_ARCH__` (75) directly against the driver's raw, BCD-packed `ARCH_VER` (0x8c75 = 35957) with no decode at all, which can never agree on any real device and would have refused every session unconditionally; extracting and adapting `htpdrv_get_arch`'s decode is the fix |
| `exec/quant.py` | `ggml/src/ggml-quants.c` `quantize_row_q4_0_ref` and `ggml/src/ggml-common.h` `block_q4_0` | the **q4_0 block format and the quantization arithmetic**, transcribed rather than copied: the 18-byte block (one fp16 scale then 32 nibbles), the `j`/`j+16` nibble pairing, the signed `d = max / -8` scale, and the `min(15, (int8_t)(x * id + 8.5f))` truncating quantize step. hexlib needs it because 75 of the encoder's plan steps take a q4_0 weight and hexlib has no checkpoint loader, so nothing else in the tree can produce one. It is a reference implementation in numpy for tests and the end-to-end run -- not on any hot path -- and it is bound to an independent scalar transcription of the same upstream loop by `tests/test_quant_q4_0.py`, byte for byte |
| `runtime/host/buffers.c` | `htp-drv.cpp` | the sequence, not the code. It performs the same `rpcmem_alloc` / `rpcmem_to_fd` / `fastrpc_mmap` calls that `htp-drv.cpp` wraps, written from the SDK's own documented call order rather than copied — upstream's allocation call sites live in `htp-drv.cpp`'s caller, not in the file the `driver.c` row above already attributes |

**Deliberately not adapted:** `dspqueue` dispatch (`htp_main_thread`,
`htp_packet_callback`, `process_opbatch`), because it has no simulator path;
`htp_tensor`'s `ne`/`nb` strides, because hexlib uses an enumerated layout; and
the ggml opcode enum.

**One upstream defect is fixed rather than carried over:** `mmap_buf` returns
silently with `base == 0` when all mmap slots are occupied, after which
`prep_tensor` computes `0 + offset` and the kernel reads or writes a small bogus
address; it also `abort()`s on a failed mapping. hexlib returns
`HEXLIB_DSP_ERR_NO_MMAP_SLOT` / `HEXLIB_DSP_ERR_MMAP_FAILED` and runs no op.

This is **adapted, not vendored** — unlike `include/hexlib/hvx/`, which is
byte-identical upstream and must never be edited in place. hexlib still has no
build or runtime dependency on llama.cpp or ggml.

## Adapted, not vendored: hexbench (same author)

Expand Down
18 changes: 14 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,20 @@ A kernel clears these one at a time, and is unsupported until it clears all six.
documented authorship record, and a comment explaining *why* it is fast.
5. **Adversarial** — the `nearmiss_*.c` variants must fail, and `spec.json` edge cases
become named tests.
6. **Silicon** — batched QDC or local device, sim-vs-silicon drift recorded. **Not
implemented in this plan.** Gate 6, the `local` and `qdc` backends, and drift
recording arrive with the silicon-path plan. A kernel that has cleared gates 1-5
here has not cleared gate 6, and hexlib does not currently have a way to run it.
6. **Silicon** — batched QDC or local device, sim-vs-silicon drift recorded. **The
transport now exists; the per-kernel record does not.** A QDC session with
`--stage-dir` pushes a batch blob and its arena to an SM8650, runs it, and pulls the
arena back — the whole encoder has gone through it in a single FastRPC invoke, and
the one sim-vs-silicon cycle comparison that produced is in `README.md`. What is
still missing is a *per-kernel* drift record and a place to put it, so a kernel that
has cleared gates 1-5 has still not cleared gate 6. Do not mark one as gate-6 clear
on the strength of the whole-encoder run.

**An HMX kernel cannot clear gates 3 and 5 on the standalone-ELF path at all** — HMX
needs power, acquisition, a lock and possibly a dedicated thread, none of which exist
in a program with no protection domain around it. HMX work belongs on the QuRT-hosted
batch path; see `kernels/hmx_matmul_fp16/README.md`, which is a worked example of a
kernel committed *without* a `RESULT.md` because it does not gate.

`hexlib new-kernel <name>` scaffolds a directory that satisfies the structural half of
gates 1-5 (required files, a near-miss stub, a matching `spec.json`); `hexlib
Expand Down
Loading
Loading