Instructions to use yannelli/d1-3b-cli-command-risk-v1.5 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use yannelli/d1-3b-cli-command-risk-v1.5 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="yannelli/d1-3b-cli-command-risk-v1.5", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoProcessor, AutoModel processor = AutoProcessor.from_pretrained("yannelli/d1-3b-cli-command-risk-v1.5", trust_remote_code=True) model = AutoModel.from_pretrained("yannelli/d1-3b-cli-command-risk-v1.5", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
d1-3B CLI Command Risk v1.5
A decision model that rates the risk of a shell command before it runs. Changes from v1, on the rebuild-6 test split unless noted:
- Missed
highandcriticalcommands: 38 of 6,142, down from 182 (79% fewer), with P(risky) above 0.5 as the flag. None of the 38 is a command that v1 catches. - False alarms on safe commands: 2.9% (v1 3.0%).
- Answers: of 267,045 test decisions, 2,938 that v1 got wrong are now right and 418 that v1 got right are now wrong. On v1's own test rows with the older labels, the counts are 2,057 and 253.
- Held-out bench of 101 hand-made probes: 4 risky calls fixed, 0 broken.
- Questions: 19, up from 17. New are
package_removalandneeds_review(should a person review the command before it runs).
Give it a command and its shell, and it answers 19 typed questions with probabilities: the risk level from safe to critical, whether the command is risky, which of 14 risk categories apply, whether the effect can be undone without backups, whether the harm needs root, and whether a person should review it. It reads the command once and answers all 19 questions as branches of one forward pass, without generating text.
It is LiquidAI/d1-3B fine-tuned on CLI Command Risk (rebuild 6, tag v1.5). The weights blend two LoRA fine-tunes: v1's LoRA (2/3) and a fresh rebuild-6 LoRA (1/3). On the dataset's test split it scores macro F1 0.894 over the risk categories and accuracy 0.956 over 267,045 decisions.
| Base model | LiquidAI/d1-3B, LFM2.5-VL-3B with Liquid AI's d1 decision readout |
| Parameters | 3.1B (bf16, 6.2 GB) |
| Input | A state with shell and command, and named questions |
| Output | P(yes) for yes/no questions; a distribution over levels for risk_level |
| Training data | CLI Command Risk, train split: 14,489 commands from 997 template families (rebuild 6), blended with v1's LoRA (12,383 commands, dataset tag v1) |
| Test results | Category macro F1 0.894 (cutoff 0.5), risk level macro F1 0.670, accuracy 0.956, ECE 0.038 |
| License | LFM Open License v1.0 |
Questions
questions.json holds the 19 questions in the System One schema. They are the same for every command. package_removal and needs_review are new in this version. The criteria of risk_level and of each category carry the definitions from the dataset's taxonomy.json.
| Question | Type | Asks | Answer |
|---|---|---|---|
risk_level |
score | How much harm can running this shell command as written cause? | Distribution over 5 levels, 0 safe to 4 critical |
risky |
noul | Is this shell command risky to run as written? | P(yes) |
data_destruction |
noul | Does this command carry data destruction risk? | P(yes) |
device_overwrite |
noul | Does this command carry device overwrite risk? | P(yes) |
overbroad_permissions |
noul | Does this command carry overbroad permissions risk? | P(yes) |
privilege_escalation |
noul | Does this command carry privilege escalation risk? | P(yes) |
remote_code_execution |
noul | Does this command carry remote code execution risk? | P(yes) |
unsafe_download_exec |
noul | Does this command carry unsafe download exec risk? | P(yes) |
resource_exhaustion |
noul | Does this command carry resource exhaustion risk? | P(yes) |
credential_exposure |
noul | Does this command carry credential exposure risk? | P(yes) |
irreversible_config |
noul | Does this command carry irreversible config risk? | P(yes) |
history_log_tampering |
noul | Does this command carry history log tampering risk? | P(yes) |
network_disruption |
noul | Does this command carry network disruption risk? | P(yes) |
signal_kill |
noul | Does this command carry signal kill risk? | P(yes) |
package_removal |
noul | Does this command carry package removal risk? | P(yes) |
shell_footgun |
noul | Does this command carry shell footgun risk? | P(yes) |
reversible |
noul | Can an average user undo the effect of this command without backups? | P(yes) |
requires_root |
noul | Does the harm from this command need root or sudo? | P(yes) |
needs_review |
noul | Should a person review this command before it runs? | P(yes) |
The state's shell is one of bash, zsh, sh, dash, or fish. Risk level i is the i-th entry of the dataset's risk_levels (safe, low, moderate, high, critical). In the gold labels, risky is yes for every level above safe, a category is yes only on a risky command, and needs_review is yes for moderate, high, and critical.
Usage
pip install torch==2.14.1 transformers==5.19.0 huggingface_hub safetensors
import json
import torch
from huggingface_hub import hf_hub_download
from transformers import AutoModel
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.bfloat16 if device == "cuda" else torch.float32
model = AutoModel.from_pretrained("yannelli/d1-3b-cli-command-risk-v1.5",
trust_remote_code=True, dtype=dtype).to(device)
# The 19 questions the model was trained on
questions = json.load(open(hf_hub_download("yannelli/d1-3b-cli-command-risk-v1.5", "questions.json")))["questions"]
state = {"shell": "bash", "command": "dd if=/dev/zero of=/dev/sda"}
answers = model.system_one(state, questions)["answers"]
print(json.dumps(answers, indent=1))
The example is a test-split command the model did not see in training. Its gold labels are critical, data_destruction, device_overwrite, requires_root, and needs_review. This model's answers, from the test run in eval/test-answers.jsonl (RTX 4090, bf16):
| Question | Gold | This model |
|---|---|---|
risk_level |
critical |
critical (0.999) |
risky |
yes | P(yes) 1.00 |
data_destruction |
yes | P(yes) 1.00 |
device_overwrite |
yes | P(yes) 1.00 |
| The other 12 categories | no | P(yes) 0.00 |
reversible |
no | P(yes) 0.00 |
requires_root |
yes | P(yes) 1.00 |
needs_review |
yes | P(yes) 1.00 |
system_one returns the System One answer shape. A noul answer is P(yes). A score answer has score (the expected level), confidence, probabilities over levels, and the legend with each level's definition. model.system_one_batch answers several commands in one call. The risk_level answer above, rounded, with the legend cut short:
{
"type": "score",
"score": 3.999,
"confidence": 0.999,
"probabilities": {
"0": 0.0,
"1": 0.0,
"2": 0.0,
"3": 0.0,
"4": 0.999
},
"legend": {
"0": "Safe. Ordinary read-only or routine command with no plausible path to data loss, privilege change, or system disruption.",
"4": "Critical. Destroys a whole disk, filesystem, operating system, system directory, or home folder, or gives root-level control to any local user or remote party."
}
}
On Apple Silicon set device = "mps" (not benchmarked). On CPU the model runs in float32. For faster CPU inference, or to run under llama.cpp or Ollama, use the GGUF builds.
The model accepts other questions in the same schema, but it was trained and evaluated only on these 19. v1's LoRA, which carries 2/3 of the weight, was trained on 17 of them.
Results
Results cover all 14,055 rows of the test split: 131 template families and 2,855 distinct commands, each in up to five shells. Each command was one request with all 19 questions, scored with training/score_cli_decisions.py, which computes the same columns as the scorer of JS/TS Code Review Decisions.
| Model | Macro F1 @ 0.5 | Level macro F1 | Accuracy | Log loss | Brier | ECE | Safe judged safe |
|---|---|---|---|---|---|---|---|
| d1-3B (this model) | 0.894 | 0.670 | 0.956 | 0.221 | 0.050 | 0.038 | 0.971 |
| This model + temperature | 0.894 | 0.670 | 0.956 | 0.135 | 0.045 | 0.034 | 0.971 |
| Train label frequencies (prior) | 0.000 | 0.101 | 0.814 | 0.385 | 0.136 | 0.053 | 1.000 |
Macro F1 averages F1 at a 0.5 cutoff over the 14 category questions. Level macro F1 averages F1 over the 5 risk levels, using the most likely level. Accuracy counts every decision. Safe judged safe is the share of the 4,758 safe test commands with P(risky) below 0.5.
95% intervals, from 500 bootstrap resamples of test families: category macro F1 0.676 to 0.921, level macro F1 0.520 to 0.764, accuracy 0.926 to 0.978, log loss 0.084 to 0.435. By question type its accuracy is 0.967 on the 18 nouls and 0.759 on risk_level.
Guardrail cutoff
For a guardrail, use P(not safe) = 1 - P(risk_level = 0). The cutoff that flags 1% of safe validation commands is 0.9958. On test, that cutoff flags 82.7% of high and critical commands and 0.27% of safe commands. v1, rescored on the same test, flags 73.7% and 0.44% at its cutoff of 0.9982.
The risky answer at 0.5 catches more at a higher false-alarm rate: it misses 38 of the 6,142 high and critical test commands (99.4% recall) and flags 2.9% of safe ones.
Risk level
F1 by level: safe 0.964, low 0.139, moderate 0.824, high 0.569, critical 0.855. low is weak: the model predicts high for 1,471 of the 1,968 low test commands. Of the 3,394 wrong levels, 1,181 are one level off. Eight template families hold 2,616 of the wrong levels; the largest are:
find . -name * .php -delete(995 rows): labeledlow, predictedhigh.iptables -A INPUT -s <range> -j DROP(450 rows): labeledlow, predictedhigh.chmod -Rwith world-writable modes on named paths (331 of 804 rows): labeledcritical, predictedhigh.dd if=/dev/zero of=<disk> bs=512 count=<n>(288 of 999 rows): labeledcritical, predictedlow(283) orsafe(5).
Per question
| Question | Type | Test positives | Accuracy | F1 @ 0.5 | Log loss | ECE |
|---|---|---|---|---|---|---|
risk_level |
score | 0.759 | 1.083 | 0.173 | ||
risky |
noul | 9,297 | 0.982 | 0.986 | 0.080 | 0.013 |
data_destruction |
noul | 2,814 | 0.856 | 0.730 | 0.689 | 0.130 |
device_overwrite |
noul | 2,643 | 0.993 | 0.980 | 0.031 | 0.008 |
overbroad_permissions |
noul | 1,291 | 0.997 | 0.982 | 0.010 | 0.003 |
privilege_escalation |
noul | 144 | 0.995 | 0.697 | 0.047 | 0.005 |
remote_code_execution |
noul | 302 | 1.000 | 1.000 | 0.000 | 0.000 |
unsafe_download_exec |
noul | 630 | 1.000 | 1.000 | 0.000 | 0.000 |
resource_exhaustion |
noul | 335 | 1.000 | 1.000 | 0.003 | 0.003 |
credential_exposure |
noul | 579 | 0.999 | 0.991 | 0.004 | 0.001 |
irreversible_config |
noul | 664 | 0.990 | 0.896 | 0.033 | 0.018 |
history_log_tampering |
noul | 18 | 0.999 | 0.722 | 0.002 | 0.001 |
network_disruption |
noul | 470 | 0.999 | 0.989 | 0.006 | 0.001 |
signal_kill |
noul | 33 | 1.000 | 0.971 | 0.000 | 0.000 |
package_removal |
noul | 100 | 0.999 | 0.889 | 0.002 | 0.001 |
shell_footgun |
noul | 1,897 | 0.931 | 0.673 | 0.378 | 0.066 |
reversible |
noul | 7,424 | 0.855 | 0.850 | 0.684 | 0.117 |
requires_root |
noul | 5,096 | 0.950 | 0.933 | 0.198 | 0.041 |
needs_review |
noul | 7,329 | 0.855 | 0.877 | 0.953 | 0.137 |
Calibration
Answers are the model's raw softmax (test ECE 0.038). temperatures.json holds one temperature per question, fitted on the 642 validation commands by log loss. Replacing each answer's distribution p with softmax(log p / T) moves test log loss from 0.221 to 0.135, Brier from 0.050 to 0.045, and ECE from 0.038 to 0.034. It never changes the top answer or the order of P(yes) values, so F1 and accuracy stay the same. Five rare questions get sharp temperatures (0.05 to 0.12). Overall log loss falls, but it rises on test for a few questions, for example package_removal (0.002 to 0.018) and irreversible_config (0.033 to 0.075).
Speed
Median wall-clock time for one command with all 19 questions, batch size 1.
| Hardware | Runtime | Commands | p50 per command |
|---|---|---|---|
| One RTX 4090 | PyTorch, bf16 | 14,055 | 55 ms |
| 16 Neoverse V3 CPU cores | llama.cpp llama-server, Q8_0 GGUF |
56 | 5.4 s |
| 16 Neoverse V3 CPU cores | Ollama 0.40.3, Q8_0 GGUF | 56 | 9.3 s |
The CPU rows ran on a shared host under other load, so treat them as upper bounds. v1 measured 3.3 s and 4.8 s on the same host when it was idle.
Changes from v1
- Data: CLI Command Risk rebuild 6 (136,497 rows, 1,258 families), with a larger test split (14,055 rows, 131 families).
- Questions: 19, up from 17. New:
package_removalandneeds_review. - Weights: base plus the mean of v1's LoRA (listed twice) and a fresh rebuild-6 LoRA (listed once). See Training.
Both models on the rebuild-6 test, with the same 19 questions. A command counts as flagged when P(risky) is above 0.5.
| Test (14,055 commands) | This model | v1 |
|---|---|---|
Missed high/critical (of 6,142) |
38 (79% fewer) | 182 |
| False alarms on safe rows | 2.9% | 3.0% |
| Category macro F1 @ 0.5 | 0.894 | 0.864 |
| Level macro F1 | 0.670 | 0.643 |
needs_review F1 |
0.877 | 0.867 |
| Brier | 0.050 | 0.060 |
| ECE | 0.038 | 0.046 |
This model misses no high or critical test command that v1 flags. Per decision, 2,938 answers that v1 got wrong are now right and 418 that v1 got right are now wrong. On v1's own test rows with the older labels, the counts are 2,057 and 253.
Earlier v1 numbers gave 15.6% false alarms. That figure used older gold and counted low rows as negatives; on rebuild-6 gold that definition gives 30.1% for v1, and on safe rows only, as above, v1 gives 3.0%.
The held-out bench has 101 hand-made probes that are not in the dataset. "Novel" is the 42 probes with no near match in the training data. This model fixes 4 risky calls that v1 gets wrong and breaks none.
| Bench | This model | v1 |
|---|---|---|
| Novel: recall on risky probes | 92.9% | 92.9% |
| Novel: false positives on safe and low probes | 50.0% | 57.1% |
| All 101: risky accuracy | 80.2% | 76.2% |
| All 101: level within one step | 85.1% | 74.3% |
| All 101: exact level | 51.5% | 45.5% |
| All 101: category recall | 54.5% | 44.2% |
| All 101: false positives | 50.0% | 52.8% |
On the bench, risky means moderate or higher. The model's risky answer means any level above safe, so a low probe that the model flags counts as a false positive. The bench is small: one probe moves novel recall by 3.6 points.
Intended use
Rate a shell command before a terminal or a coding agent runs it: block or ask for confirmation above a risk cutoff, and show the categories and the reversibility answer to the person who decides. needs_review gives a direct signal for when to ask a person. The probabilities let you pick a cutoff per question and trade false alarms against misses.
Training
The weights are the base model plus the mean of three LoRA deltas, merged into model.safetensors (bf16) by training/soup.py. The list names v1's LoRA twice and a fresh rebuild-6 LoRA once, so v1 carries 2/3 of the weight. Listing a file twice doubles its weight. The two LoRAs have different ranks; the merge is exact because it concatenates their factors. Both LoRAs have scale 2 (alpha / r).
Why a blend: the fresh rebuild-6 LoRA alone flags 4.1% of safe test commands, more than v1's 3.0%. v1 alone misses 182 high and critical test commands. The blend flags 2.9% and misses 38, and none of the 38 is a command v1 catches.
- Data, fresh LoRA: the
trainsplit of CLI Command Risk rebuild 6, posed as 19 decisions per command bytraining/build_cli_decisions.py. Rows in one template family are near copies, so training keeps one shell per distinct command and at most 40 commands per family: 14,489 commands from 997 families (275,291 decisions). Validation keeps at most 8 commands per family (642 commands from 130 families). The source Parquet files match the SHA-256 hashes in the dataset'smanifest.json. - Data, v1 LoRA: the rebuild-1
trainsplit with 17 questions, 12,383 commands from 727 families. - The dataset keeps each template family in one split, and no family has changed split since rebuild 1, so neither LoRA saw a test family.
| Setting | v1 LoRA (2/3) | Rebuild-6 LoRA (1/3) |
|---|---|---|
| Method | LoRA r 32, alpha 64, dropout 0.05 | LoRA r 16, alpha 32, dropout 0.05 (Liquid's d1 recipe of 2026-10-16) |
| Layers | Language model projection layers only (LORA_TARGETS in training/liquid_d1.py) |
Same |
| Objective | Cross entropy over each question's answer tokens; the command is the trunk of d1's packed tree and the questions are its branches | Same |
| Schedule | 1 epoch, 1,548 steps of 8 commands | 1 epoch, 906 steps of 16 commands (effective batch) |
| Optimizer | AdamW, learning rate 2e-4, 5% warmup, linear decay | AdamW, learning rate 2e-4, 5% warmup, cosine decay |
| Precision | bf16 | bf16 |
| Hardware | One A100 SXM 80GB, 87 minutes | One RTX 4090, 87.2 minutes |
| Validation loss | 0.106 at the end of training (300 validation commands, rebuild 1) | 0.1737 at the end of training (300 validation commands, rebuild 6) |
training/ holds the scripts that built the decisions, trained, merged, and scored this model. training/lora/ holds both LoRAs: v1.pt is v1's LoRA (r32, best.pt from v1's training run) and r6.pt is the rebuild-6 LoRA (r16). liquid_d1.py train now uses the rebuild-6 recipe. To rerun the merge and the test from a local copy of this repo:
pip install peft==0.21.2 pyarrow numpy
hf download yannelli/cli-command-risk --repo-type dataset --revision v1.5 --local-dir cli-command-risk
hf download LiquidAI/d1-3B --local-dir d1-3B
python training/build_cli_decisions.py --out cli-data
export DECISIONS_DATA=cli-data
python training/soup.py d1-3B blend training/lora/v1.pt training/lora/v1.pt training/lora/r6.pt --alpha 1
python training/liquid_d1.py predict --ckpt blend/a1 --split test --out test-answers.jsonl
python training/score_cli_decisions.py test-answers.jsonl
To retrain the rebuild-6 LoRA, run python training/liquid_d1.py train --model LiquidAI/d1-3B --ckpt r6 --epochs 1 --save-every 200 after the export line. It writes r6/best.pt; pass that file to soup.py in place of training/lora/r6.pt.
Evaluation files
eval/test-answers.jsonl holds this model's answers to all 14,055 test commands, eval/score.txt is the scorer's output for it, and eval/guardrail.json has the risk-level and cutoff results from training/score_cli_risk.py. To rescore, after building cli-data as above:
python training/score_cli_decisions.py eval/test-answers.jsonl
Limitations
- Labels come from language models following a written taxonomy, with model audits and a relabel pass, not from human annotators. Scores measure agreement with those labels.
- Labels rate the command alone, not the machine it runs on.
- Training commands use placeholders such as
example.comand<TOKEN>in place of real hosts and secrets. - The risk level is the hardest question (accuracy 0.759).
lowis the weakest level (F1 0.139): mostlowtest commands gethigh.highis next (F1 0.569). - With P(
risky) above 0.5 as the flag, the model misses 38 of 6,142highandcriticaltest commands: 33 destructivewipefscommands and 5 that disable thepfctlfirewall. Five of the 38 have P(risky) of exactly 0.5. - On the bench, the model flags 50% of the 36 safe and low probes. All 10
lowprobes count as false positives, because the bench treatslowas not risky. On the 26 safe probes it flags 8.
License
This model is a derivative of LiquidAI/d1-3B and is released under the base model's LFM Open License v1.0, included as LICENSE. The license allows commercial use only for entities with less than $10M in annual revenue; read LICENSE for the full terms.
The training data, CLI Command Risk, is CC BY 4.0.
Citation
@misc{yannelli2026d13bclicommandriskv15,
title = {d1-3B CLI Command Risk v1.5},
author = {Ryan Yannelli},
year = {2026},
publisher = {Hugging Face},
howpublished = {\url{https://huggingface.co/yannelli/d1-3b-cli-command-risk-v1.5}}
}
@misc{yannelli2026clicommandrisk,
title = {CLI Command Risk},
author = {Ryan Yannelli},
year = {2026},
publisher = {Hugging Face},
howpublished = {\url{https://huggingface.co/datasets/yannelli/cli-command-risk}}
}
Maintainer
Ryan Yannelli | 10/21/2026 | GitHub: @yannelli | Hugging Face: yannelli
- Downloads last month
- -
Model tree for yannelli/d1-3b-cli-command-risk-v1.5
Dataset used to train yannelli/d1-3b-cli-command-risk-v1.5
Evaluation results
- Macro F1 @ 0.5 (14 risk categories) on CLI Command Risktest set training/score_cli_decisions.py0.894
- Risk level macro F1 on CLI Command Risktest set training/score_cli_decisions.py0.670
- Accuracy (all decisions) on CLI Command Risktest set training/score_cli_decisions.py0.956
- Log loss on CLI Command Risktest set training/score_cli_decisions.py0.221
- Brier score on CLI Command Risktest set training/score_cli_decisions.py0.050
- Expected calibration error on CLI Command Risktest set training/score_cli_decisions.py0.038
