[{"categories":["AI","Machine Learning","recomended"],"contents":"How I Built a System One Option Scorer like Jev Scott Davis · Hecaton Labs · September 2026\nOn September 15, 2026, TypeSafe AI came out of stealth and released Jev, its first System One model, into early access. Jev is not a chatbot. It takes a situation (state), scores a short list of allowed moves (options), and returns a structured choice software can act on. No essay. No tool-call monologue. A decision.\nThat launch put a public name on something many builders already need: a small decide(state, options) model you can train for your own product loop and run locally, instead of renting a giant text generator for every turn.\nI built my own. About 256MB on disk, trained on a single RTX 3060, roughly 18ms per turn. The speed comes from a one-pass design: score each legal option against the state in a single forward pass, then pick. No token-by-token generation in the loop.\nArchitecture got the latency into range. Training decided whether those scores would transfer into control.\nThe contract The job is narrow on purpose. Given a state and a short list of legal options, return one ranked choice. Software already knows what moves are allowed. The model only has to decide which one fits this state.\nUnder the hood that is DistilBERT (Sanh et al., 2019): a small language model that reads the state and one option together, then outputs a score. For each legal option, the input looks like:\n[CLS] state [SEP] option [SEP] One forward pass per option. Softmax turns the scores into probabilities. Argmax (or sampling) picks the move. There is no decode loop writing tokens until an answer appears. That one-pass contract is why sub-20ms turns are realistic on a local GPU.\nScoring the state and each option separately, then combining those embeddings later, barely beat random guessing in early trials. Joint scoring (state and option in the same pass) was what started beating random guessing. The rest of this post is about what training data made those rankings useful for control, not only for language labels.\nFirst training: language as option ranking The model only needed to do one job: given a situation, pick the best option from a short list. Every training row used the same record shape:\n{ \u0026#34;state\u0026#34;: \u0026#34;The server returned 503 after the deploy.\u0026#34;, \u0026#34;options\u0026#34;: [ \u0026#34;roll back the release\u0026#34;, \u0026#34;retry the request\u0026#34;, \u0026#34;ignore and continue\u0026#34; ], \u0026#34;chosen\u0026#34;: 0 } state is the situation. options is the candidate list. chosen is the index of the ranked answer. Language tasks and, later, game logs both land in this format before training.\nThe first supervision came from language data reshaped into that contract. Entailment-style sets such as all-nli and ANLI became three-way choices (premise as state, labels as options). Multiple-choice reading and reasoning sets such as Cosmos QA, HellaSwag, and PIQA became the same shape: question as state, answers as options. The goal was not “learn natural language inference.” It was plentiful supervision that already has a ranked choice.\nWith that data, a frozen encoder barely moved. Accuracy sat on random guessing for a three-way choice. Packing state and option into one DistilBERT pass finally left random guessing (~33%) and landed around 42% held-out. That was the first clear sign the model was ranking options instead of picking at random. Lightly unfreezing DistilBERT on a modest slice pushed validation into the mid-seventies. Pushing the same mixture harder mostly plateaued.\nUseful, and still incomplete. Ranking language labels is not the same job as choosing actions in a game. The architecture could score options fast. The next experiment was whether supervised play logs, in the same schema, would transfer those rankings into control.\nPlay logs taught control Language option ranking was still language about language. A model that ranks entailment labels still does not know when to flap, heal, or disable a target. For control, the training rows had to be decisions from play.\nSo I wrote small scripted experts: programs that already know a correct policy for a tiny game, play thousands of turns, and log each decision in the same {state, options, chosen} schema. Those logs are supervised training data. The scripts are not the product. They exist to manufacture labeled play.\nThe first game was the Flappy Bird harness from OpenJev, where Flappy is used as a real-time System One–style control demo. Pointing the language-trained scorer at it like a policy failed. After training on the scripted Flappy logs (and fitting a small head to those logs), the same model could play.\nFantasy party combat came next, and that is where the training problem got sharper. In one fight, healer, tank, DPS, and support do not share a single “best” move for the board. A healer’s state stresses who is about to die and whether a heal beats waiting. A tank’s state stresses threat, mitigation, and when to guard. A DPS’s state stresses the kill target without wasting a turn. Support with crowd control (abilities that lock an enemy out of acting) stresses who to disable, when to refresh that disable, and when a small damage option is better than another crowd-control cast.\nSame schema every turn. Different goals in the state text. Different legal option sets. Different ranked answers. That role split is what forced the scorer to learn decisions that depend on who is acting, not a generic best move for the whole board.\nThose play logs are what taught transfer into control. More language ranking alone would not have.\nOne support turn Here is a support turn from the live party demo. Tidecaller (enemy healer) is already crowd-controlled and nearly dead. Legal options are cast crowd control, refresh crowd control, or chip for small damage.\nState\nrole=support side=flare name=Support id=flare_support t=43 active=flare_support self hp=72/72 mana=11/11 status=none:0 defend_hits=0 allies: Rockjaw(tank) hp=62/110 mana=10/10 status=none:0 defend_hits=2; Warmheart(healer) hp=78/78 mana=14/14 status=none:0; Emberpup(dps) hp=69/88 mana=10/11 status=none:0 enemies: Shellguard(tank) hp=0/110 mana=10/10 status=none:0; Tidecaller(healer) hp=9/78 mana=14/14 status=cc:1; Aquafin(dps) hp=0/88 mana=11/11 status=none:0; Drowsprite(support) hp=0/72 mana=11/11 status=none:0 cc_enemies: Tidecaller our_taunt_holder=none focus_target=Tidecaller ally_lowest_hp_frac=0.56 need_heal=1 need_defend=0 options_hint: defend/guard/brace | heal/mend | taunt | nuke | risky_aoe | cc | refresh_cc Options\n[ { \u0026#34;id\u0026#34;: \u0026#34;cc\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;use CC: Disable a priority foe (skip turns)\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;refresh_cc\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;use Refresh CC: Refresh disable on a locked foe, else CC fresh\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;chip\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;use Chip: Small chip damage (~10)\u0026#34; } ] Model output\n{ \u0026#34;scores\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;chip\u0026#34;, \u0026#34;score\u0026#34;: 0.647 }, { \u0026#34;id\u0026#34;: \u0026#34;refresh_cc\u0026#34;, \u0026#34;score\u0026#34;: 0.307 }, { \u0026#34;id\u0026#34;: \u0026#34;cc\u0026#34;, \u0026#34;score\u0026#34;: 0.046 } ], \u0026#34;chosen\u0026#34;: { \u0026#34;id\u0026#34;: \u0026#34;chip\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;use Chip: Small chip damage (~10)\u0026#34; }, \u0026#34;latency_ms\u0026#34;: 18 } The scorer preferred chip over refreshing crowd control. Tidecaller died, and the fight ended. A healer looking at the same fight would get state text that stresses ally HP and heal pressure. A tank’s state would stress threat and guard. Same schema. Different emphasis. Same ~18ms one-pass ranking.\nWatch the loop A single support turn is easy to inspect. A full fight is where the contract has to hold: every role, every turn, same schema, one ranked action, fast enough on the 3060.\nFigure: Video. Fantasy party battle driven by the option scorer.\nThe support turn above is one frame from that demo: raw state, options, and scores. The video is the same loop over a full fight. State in. Role-aware option list in. One scored choice out. Repeat until the encounter ends.\nClose The scorer is a one-pass ranker over state and option. Language data got ranking off the ground. Scripted play logs, especially multi-role fantasy combat, are what transferred that ranking into control. Same schema. Different goals per role. One scored choice per turn.\nAppendix Dataset reshape notes Entailment-style sets: premise as state, labels as options, gold label index as chosen. Multiple-choice sets: question as state, answers as options, correct index as chosen.\nReferences TypeSafe AI. Introducing System One Models and Jev. 2026. https://typesafe.ai/blog/introducing-system-one-models-and-jev Victor Sanh, Lysandre Debut, Julien Chaumond, and Thomas Wolf. DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter. 2019. https://arxiv.org/abs/1910.01108 Hugging Face. DistilBERT (Transformers docs). https://huggingface.co/docs/transformers/en/model_doc/distilbert sentence-transformers. all-nli dataset. https://huggingface.co/datasets/sentence-transformers/all-nli Facebook AI. ANLI dataset. https://huggingface.co/datasets/facebook/anli AllenAI. Cosmos QA dataset. https://huggingface.co/datasets/allenai/cosmos_qa Rowan Zellers et al. HellaSwag dataset. https://huggingface.co/datasets/Rowan/hellaswag Yonatan Bisk et al. PIQA dataset. https://huggingface.co/datasets/ybisk/piqa AlexWortega. OpenJev (Flappy Bird System One–style harness). https://huggingface.co/AlexWortega/openjev ","permalink":"https://terriblesoftware.dev/en/posts/how-i-built-an-open-system-one-option-scorer/","tags":["AI","System One","DistilBERT","Machine Learning","Jev"],"title":"How I Built a System One Option Scorer like Jev"},{"categories":["Linux","Automation","Development","recomended"],"contents":"Automating Cursor Updates on Linux: A Bash Script Solution This script has saved me countless hours of manual updates and ensures that I am running latest version of Cursor.\nFeel free to modify the script to suit your specific needs, and let me know if you have any improvements or suggestions!ss\nAs a someone who uses Cursor daily, I found myself manually downloading and updating the application whenever new versions were released. This could me a few times a day. It was super tedious, so I created a comprehensive bash script that automates the entire process. In this post, I\u0026rsquo;ll walk you through the script and explain how it works.\nThe Problem Cursor releases frequent updates (sometimes may times a day), and AUR is slow to update. So I needed a solution that would:\nCheck for the latest version automatically Download and install updates seamlessly Integrate with the desktop environment Provide command-line access Handle version checking to avoid unnecessary downloads The Solution: A Comprehensive Update Script Here\u0026rsquo;s the complete script that solves all these problems:\nYou can view, copy, or download the complete script as a GitHub Gist here: auto-update-cursor.sh\nKey Features 1. Smart Version Checking The script uses Cursor\u0026rsquo;s API to fetch the latest version information and compares it with the currently installed version. This prevents unnecessary downloads when you\u0026rsquo;re already up to date.\n2. Force Update Option Sometimes you might want to reinstall even if you have the latest version. The -f or --force flag allows you to bypass version checking.\n3. Desktop Integration The script automatically:\nDownloads and sets up the icon Creates a desktop entry for the application menu 4. Command Line Access After installation, you can launch Cursor from the terminal using the cursor command. The script creates a wrapper in ~/bin/cursor that launches the AppImage. (make sure you have ~/bin in your $PATH)\nUsage Basic Usage # Make the script executable chmod +x update-cursor.sh # Run the update ./update-cursor.sh Force Update # Force update even if latest version is installed ./update-cursor.sh --force Help # Show usage information ./update-cursor.sh --help Prerequisites The script requires two common Linux tools:\ncurl - for downloading files jq - for parsing JSON responses Install them on your system:\nUbuntu/Debian:\nsudo apt update sudo apt install curl jq Omarchy:\nsudo yay -S curl jq How It Works API Query: The script queries Cursor\u0026rsquo;s download API to get the latest version information Version Comparison: It compares the latest version with the currently installed version Download: If an update is needed (or forced), it downloads the latest AppImage Installation: The script replaces the old AppImage with the new one Integration: It updates the desktop entry and creates command-line access Cleanup: Temporary files are removed Customization You can easily customize the script by modifying these variables at the top:\nINSTALL_DIR=\u0026#34;$HOME/opt\u0026#34; # Change installation directory APP_NAME=\u0026#34;Cursor\u0026#34; # Change application name Automation To make this even more convenient, you can set up a cron job to run the script automatically:\n# Add to crontab to check for updates daily at 9 AM 0 9 * * * /path/to/update-cursor.sh Or create a systemd timer for more sophisticated scheduling.\n","permalink":"https://terriblesoftware.dev/en/posts/auto-update-cursor-linux-script/","tags":["Linux","Bash","Cursor","Automation","Scripting"],"title":"Automating Cursor Updates on Omarchy"},{"categories":["GDScript","Godot","recomended"],"contents":"TDIL: The Magic of Callable.bind in GDScript Today I learned (TDIL) about a super helpful feature in GDScript: Callable.bind. If you\u0026rsquo;re working with signals in Godot and find yourself needing to pass additional data to a single handler, Callable.bind is your new best friend.\nThe Problem In many UI setups, you might have multiple buttons that trigger the same function. However, these buttons often represent different actions or carry unique context. For example: A list of character abilities with each button corresponding to a specific skill. A menu system where each button navigates to a different scene or executes a unique task. The usual approach is to connect each button\u0026rsquo;s pressed signal to the same function. But how do you tell which button triggered the signal? And what if you need to pass more data (e.g., an ID, name, or reference) to your handler?\nThe Solution: Callable.bind Callable.bind allows you to attach additional arguments to a function call. This means you can make your signal handler more dynamic without writing extra boilerplate code.\nThe Button.button_up signal doesn\u0026rsquo;t allow any arguments to be returned to the handler function, so we solve this by binding data.\nLet\u0026rsquo;s break it down with an example:\nfunc create_chracter_button(character: Networking.Proto.Entiy) -\u0026gt; Button: var button: Button = Button.new() button.text = character.get_name() button.size.y = 100 button.button_up.connect(on_character_button_released.bind(character)) return button func on_character_button_released(character: Networking.Proto.Entiy) -\u0026gt; void: print(character.get_name() + \u0026#34; selected\u0026#34;) current_character = character %CharacterName.clear() %CharacterName.text = \u0026#34;[center][b]\u0026#34; + character.get_name() + \u0026#34;[/b][/center]\u0026#34; ","permalink":"https://terriblesoftware.dev/en/posts/adding-data-to-signals-gdscript/","tags":["Godot","GDScript","Signals"],"title":"TDIL: The Magic of Callable.bind in GDScript"},{"categories":["GDScript","Godot","recomended","Terrian 3D"],"contents":"Terrian 3D: Doing in game actions based on the texture the character is standing on Enhance gameplay by triggering actions based on terrain textures. Use Terrian3D to fetch texture IDs at the player\u0026rsquo;s position:\nget_texture_id() returns a Vector3 containg Vector3(base texture id, overlay id, blend value).\n@export var terrian:Terrain3D) func _physics_process(_delta: float) -\u0026gt; void: var texture_pos: Vector3 = terrian.data.get_texture_id(PlayerManager.get_player().get_position()) print_debug(\u0026#34;Texture ID: {0}\u0026#34;.format([texture_pos])) var base_texture_id = int(texture_info.x) # Base texture ID (e.g., 1 = Grass, 2 = Dirt, 3 = Sand) # base_texture_id is the index of the texture in the terrain from the Terrian3D inspector # in my case 1 is grass, 2 is dirt, 3 is sand print_debug(\u0026#34;Base Texture ID: {0}, Overlay ID: {1}, Blend: {2}\u0026#34;.format([base_texture_id, texture_info.y, texture_info.z])) match base_texture_id: 1: print_debug(\u0026#34;Grass\u0026#34;) # Trigger grass-related actions 2: print_debug(\u0026#34;Dirt\u0026#34;) # Trigger dirt-related actions 3: print_debug(\u0026#34;Sand\u0026#34;) # Trigger sand-related actions Use this to adjust movement speed, trigger sounds, or create particle effects for immersive gameplay. It\u0026rsquo;s simple yet powerful!\n","permalink":"https://terriblesoftware.dev/en/posts/detecting-texture-under-character-terrian-3d/","tags":["Godot","GDScript","Terrian 3D"],"title":"Terrian 3D: Doing in game actions based on the texture the character is standing on"}]