Kern TS module v0.6 (Qwen3.5-4B trunk)

Kern is a family of small code models that check their answers with the toolchain. This repository holds the TypeScript module of Kern as deployed in our pilot: a LoRA adapter on the Qwen3.5-4B trunk, both as GGUF files for llama.cpp, plus a small script that sends a task to the model in the exact prompt format it was trained on.

With the adapter this is not a chat assistant. The trunk is the post-trained Qwen3.5-4B (run with its thinking mode off) and the adapter narrows it to one job: given project files and an instruction, reply with a structured edit (the Kern format) that compiles under strict TypeScript, passes ESLint recommended rules and is Prettier-formatted, or ask one question, or refuse. In the product the answer goes through an edit transaction: the host applies the edit on a copy of the repository, runs tsc, ESLint and the tests, and accepts the change or rolls it back; a failed check gets one repair turn with the diagnostics. The model is meant for small, local edits (a compile fix, a diagnostic repair, a function change, a test fix), not for writing features from scratch.

Files

File Size sha256
kern-ts-v0.6-repair-s0-lora-f16.gguf 65 MB fb21eace94a89994c9d214bd3c9b6b3191acfd86feefd56d2eecbf5673a0a0e2
qwen35-4b-base-Q4_K_M.gguf 2.78 GB 1fbe3aa41105a3b5ea15dec14551575de0154492abcaa41659ca41d46deea5bd
kern_try.py sends a task directory to a running llama-server and prints the answer with timings
example/ex-ts-0001-parse-range/ one public example task (repository, task.json, hidden tests, reference patch)

The trunk is our Q4_K_M quantization of Qwen/Qwen3.5-4B at revision 851bf6e806efd8d0a36b00ddf55e13ccb7b8cd0a (Apache 2.0; the file name keeps our internal name for the trunk). The adapter is a LoRA in f16; llama.cpp applies it at run time, so the trunk stays shared between modules.

Quick start

Requirements: a llama.cpp build from October 2026 or newer (Qwen3.5 support), about 4 GB of free memory, Python 3.

brew install llama.cpp            # or build https://github.com/ggml-org/llama.cpp (we deploy commit 8bb3cf0 of 2026-10-12)
hf download MoxxyLabsAI/kern-ts-lora --local-dir kern-ts-lora
cd kern-ts-lora
llama-server -m qwen35-4b-base-Q4_K_M.gguf --lora kern-ts-v0.6-repair-s0-lora-f16.gguf -c 16384 --jinja --port 18001

Faster decoding on builds that support the Qwen3.5 multi-token prediction head (this is how we deploy it):

llama-server -m qwen35-4b-base-Q4_K_M.gguf --lora kern-ts-v0.6-repair-s0-lora-f16.gguf -c 16384 --jinja --port 18001 \
  --spec-type draft-mtp --spec-draft-n-max 2

Then, in a second terminal:

python3 kern_try.py example/ex-ts-0001-parse-range

The script builds the prompt from the task directory (every source file of repo/, the diagnostics and the instruction of task.json), asks the server with temperature 0 and prints the answer and the timings. Point it at your own task: a directory with a repo/ folder of TypeScript files and a task.json with an instruction (and optionally context.diagnostics), or pass the instruction on the command line:

python3 kern_try.py path/to/your/project --instruction "parseRange must also accept '5..10'"

Keep the project small (the model was evaluated with prompts of 1 000 to 7 000 tokens; the context window is 16 384). The script does not apply the edit. In Kern the harness does that inside a transaction with the checks; here you read the <edit> blocks and apply them yourself, or use the harness.

Prompt format

The adapter was trained and evaluated with this exact rendering (chat template of the trunk, thinking off). System prompt:

You are Kern, a small code-editing model for TypeScript. Reply in the Kern format only, with no prose before it.
Decide first:
- <act:answer><fmt:block> followed by one or more blocks:
<edit path="PATH" symbol="SYMBOL">
FULL NEW CONTENT OF THE TOP-LEVEL DECLARATION (use Class.method for a class member)
</edit>
- <act:answer><fmt:file> followed by <file path="PATH">FULL FILE</file>, only for small files.
- <act:clarify> followed by one short question, when a fact needed to act is missing and cannot be read from the code.
- <act:refuse> followed by one or two sentences, when the request is outside TypeScript code editing.
Code must compile under strict TypeScript, pass ESLint recommended rules and be Prettier-formatted (80 columns).
Never edit tests or configuration, never use @ts-ignore, @ts-expect-error or eslint-disable.

User message (the example task of this repository):

Project files:

--- src/range.ts ---
export interface Range {
  start: number;
  end: number;
}

/** Parses "a-b" into a numeric range. */
export function parseRange(input: string): Range {
  const [start, end] = input.split("-").map(Number);
  return { start, end };
}

Instruction: parseRange ma akceptować zapis '5-10' i '5..10' oraz rzucać RangeError przy odwrotnej kolejności albo wartościach, które nie są liczbami całkowitymi.

When the task has diagnostics, a Diagnostics: section with one file:line code message line each goes between the files and the instruction. Instructions may be in English or Polish. The answer looks like this:

<act:answer><fmt:block>
<edit path="src/range.ts" symbol="parseRange">
export function parseRange(input: string): Range {
  ...
}
</edit>

symbol names a top-level declaration (function, class, interface, type, enum, const) or Class.method; the whole declaration is replaced, export included. A symbol that is not in the file is appended; a file that does not exist is created. The harness rejects edits of tests, configuration and lockfiles, and any new @ts-ignore, @ts-expect-error or eslint-disable.

Results

All numbers are from the configuration in this repository (Q4_K_M trunk, f16 adapter, llama.cpp with MTP, temperature 0, thinking off) unless stated otherwise. "After the loop" means one repair turn with the tsc and ESLint diagnostics for answers that failed the visible checks. A task passes when the edit applies, builds, lints and passes the hidden tests.

Set Tasks First answer After the loop Notes
Dev exam TS v0.1 (private; 14 open-source repositories disjoint from training, 127 task clusters) 450 147 (32.7%, 95% CI 28.2 to 37.4) 162 (36.0%, 31.4 to 40.7) this adapter (seed 0); seeds 1 and 2 of the same recipe: 35.8% and 31.3% first answer, 38.4% and 34.2% after the loop
Golden TS v0.1 (private) 101 50.7 (mean of three seeds) previous data version v0.5: 48.3; the bare trunk without the adapter: 12 (20 with a tolerant parser)
Verify TS v0.1 (private) 160 137.0 (mean of three seeds) v0.5: 123.7; bare trunk 83 and teacher GLM-5.2 151 (both measured in bf16 on a GPU)
Moxxy pilot, real tasks on our own repositories, warm edit transaction on a MacBook Air 100 P15 29 to 32% P15 = correct and accepted within 15 s including the checks; 11% with a cold prompt cache

By category on the dev exam (after the loop): compile fixes 80.0% (45 tasks), test fixes 34.5% (200), function edits 31.9% (135), refactors that move code to a new module 20.0% (70). Changes reproduced from repository history are harder than authored ones (15.7% against 42.0%).

Latency on a fanless MacBook Air (Apple silicon, 16 GB): about 26 tokens per second with MTP, 0.6 s to the first token when the project prefix is cached, median answer 270 tokens, so a typical warm answer takes about 10 s and a short diagnostic fix 3 to 6 s. Resident memory of the server with the 4B trunk is about 4.3 GB.

Training data

Supervised fine-tuning only (LoRA, recipe v0.6, three seeds; this is seed 0). The set has 10 875 training records: synthetic TypeScript editing tasks with answers written by the teacher model GLM-5.2 (weights under MIT, served by us) through our task generators, filtered by the toolchain (the reference must compile, lint and pass the hidden tests; the unchanged snapshot must fail them), plus 1 361 repair records (a wrong first answer of an earlier Kern module, the diagnostics, and the corrected answer). No code from external repositories: all tasks are synthetic. Decontaminated against our golden and verify sets (13-gram overlap). The evaluation sets above never enter training or data generation.

Limitations

  • Not a chat model and not an agent: one edit per request, no tool calls, no multi-file planning.
  • Whole-file refactors (moving code to a new module) mostly fail: the model writes the moved symbols without their imports. Prefer tasks with a block edit in one or two files.
  • Training contexts are shorter than real repositories (synthetic prompts of 135 to 437 tokens median against about 1 800 on our pilot repositories); quality drops with very long contexts.
  • The model answers only in the Kern format; without the harness you apply the edits yourself.
  • Strict TypeScript, ESLint recommended and Prettier at 80 columns are assumed by the training data.

Provenance

Release manifest 849f4b927eebf4d7 of the Kern workspace (artifact hashes above, llama.cpp commit 8bb3cf0d216a5ae48360179f2931daf284be4d01, harness TS 0.2.7). Qualification report: dev exam TS v0.1 of 2026-10-16. Contact: MoxxyLabs.

Downloads last month
58
GGUF
Model size
32.5M params
Architecture
qwen35
Hardware compatibility
Log In to add your hardware

4-bit

16-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for MoxxyLabsAI/kern-ts-lora

Finetuned
Qwen/Qwen3.5-4B
Adapter
(1,034)
this model