-rw-r--r-- 10m Agent runtime An unknown outcome is its own state
A process crashes mid-execution. The audit log shows the action was authorized. The runtime logs show it was attempted.
root@amaltsev >:~/writing$ ls -la
69 notes on agent runtime security, embedded Rust, and the parts of a system that break in production.
A process crashes mid-execution. The audit log shows the action was authorized. The runtime logs show it was attempted.
Every step is in scope. The chain is a bulk data export to an external recipient. The agent executes them in order, because the task it was given was "produce a customer report".
A policy has a test suite. The tests pass. Then someone finds an input that gets through, and the retrospective is always the same shape.
Most agent audit logs are a table someone can UPDATE. That records what the system believed at write time.
The worker is on another pod. The queue keeps delivering jobs. Another worker picks up the in-flight execution.
There is a question most governance frameworks never ask, because it does not come up until an agent can write code, configure integrations or modify its own workflows.
An agent is authorized to issue refunds up to five hundred dollars. The permission is valid, and the agent uses it correctly.
The trust list has an entry that says delete_user is allowed. What the agent calls is delete_user. Same string, two different things.
Three agents, one platform. The support agent reads the CRM, opens tickets, and refunds up to fifty dollars.
A team wants an agent that issues refunds. Security is nervous. There are exactly two options on the table, and both are bad.
A tool is described by a JSON schema: its parameters, their types, what it accepts. This vocabulary fits an interface.
The sequence is short. An agent submits an action for approval. The operator approves it. The agent crashes.
Every framework ships a human-in-the-loop step. A human sees a card, the human clicks approve, the tool runs.
A team ships a human-in-the-loop approval step. The tests pass, the demo works, the security review signs off.
Fail-closed is a one-sentence rule: when the rule cannot be evaluated, refuse. Every enforcement system claims it.
A tool starts returning poor results. The agent notices, retries, gets poor results again, retries. Four hundred calls later it either trips a provider rate limit or exhausts the budget.
Between the get and the decrby, every other agent in the system reads the same stale balance and draws the same conclusion.
Every "control your LLM spend" guide reaches the same place: you set a monthly cap somewhere and hope the number on the dashboard means something.
The first version of this always looks the same. There is a number, the number grows, and when the number crosses a threshold the request is rejected.
Almost every comparison of agent security tools lines up vendors on a feature grid and lets the reader decide.
Same agent. Same tool. Same permission. A support agent with refund access approves a twenty-dollar refund, which is exactly what it is there for.
The request that shows up repeatedly in agent framework issue trackers is a developer who wants to inspect and block a tool call before it executes.
An agent produces a perfectly acceptable response and then sends the wrong payment, deletes the wrong resource, modifies the wrong record, or calls a tool with a mutated argument.
Most production AI systems have an excellent model and a mess around it. I have seen GPT-4, Claude and Gemini sitting behind hardcoded prompts, zero validation and no separation of concerns.
This final article connects the embedded AI device to the real world. It describes how inference results leave the MCU, travel through MQTT and HTTP, land in a Rust backend.
The TinyML lifecycle on a microcontroller, from dataset preparation and model training to TensorFlow Lite Micro on bare metal, with the model bound into Rust firmware through a custom FFI wrapper.
This article covers the hardware I use in my AI device project, why I chose it, and how I structured the firmware in Rust.
This series covers the building of an ESP32-S3 device with ML built right into the firmware, along with the decisions, compromises, and challenges that came up along the way.
This project converts raster images into cross-stitch and needlepoint patterns. The output is a structured, printable and editable SVG pattern, with full control over the size and the color palette.
A playground for the micro:bit v2.21: GPIO, I2C, SPI, UART, ADC and PWM experiments on the nrf52833.
Synchronization is what keeps the processor, the peripherals, the timers and the interrupts operating in a consistent and accurate manner, based on a common clock source.
An interrupt lets the microcontroller respond to an important event without spending cycles polling its peripherals.
The clock system is the basis for timers and interrupts. It sets the pace of every digital component of the microcontroller.
Timers are hardware modules of the microcontroller for actions with time counting and event generation without the participation of the main code.
The classic way to do that is to reduce the voltage through a rheostat or a potentiometer. That is inefficient, since part of the energy is lost as heat.
A step-by-step template for a Cortex-M Rust project: config.toml, rust-toolchain.toml, memory.x, probe-rs, defmt and the panic handler.
Microcontroller peripherals are functional blocks integrated into the chip that enable it to interact with the outside world or carry out specific tasks, often without involving the processor core.
A processor register is a quickly accessible location available to a computer's processor.
A microcontroller talks to its peripherals through one of a small number of I/O models, and the choice decides how much of the CPU's time the transfer costs, how quickly the peripheral gets serviced.
MMIO (Memory-Mapped I/O) is a way for the central processing unit (CPU) to interact with peripheral hardware devices.
Software development runs in a cycle: write, run, check, fix. On a desktop, debugging is simplified by built-in logs, breakpoints and step-by-step code execution directly in the IDE.
I2C (Inter-Integrated Circuit) is a low-speed two-wire master-slave serial protocol, widely used for short-distance data transmission over a data bus (SDA) with a clock synchronization line (SCL).
SPI (Serial Peripheral Interface) is a low-speed four-wire master-slave full-duplex serial protocol, widely used as a faster alternative to UART/I2C for transferring data between an intelligent…
UART (Universal Asynchronous Receiver / Transmitter) is a low-speed two-wire asynchronous multi-duplex serial protocol.
Digital systems are built on bits, and beyond using bits they often have to move them between two components, an MCU and a sensor or an LCD, for instance.
In general, developing programs for an MCU is aimed at obtaining some information from the surrounding world, performing necessary calculations with this data and interacting back.
A playground for the Raspberry Pi Pico W: Wi-Fi, GPIO, I2C, SPI, UART, ADC and PWM experiments on the RP2040.
Firmware for hardware that cannot be patched in the field has a different cost of failure than an application you can restart.
GPIO stands for general purpose input/output. It is a type of pin found on an integrated circuit that does not have a specific function.
Rust handles memory through its type system, and a handful of questions follow.
This is the second part of my exploration into the stages and optimizations of Rust compilation, focusing now on embedded systems development.
The PN junction is the fundamental building block of many semiconductor devices, from diodes to transistors and solar cells.
Embedded Rust firmware is size constrained because the microcontroller has very little memory to spend.
Semiconductors sit between conductors and insulators, and their behavior comes down to how electrons are arranged in atoms.
Rust turns source code into a machine-executable binary through a pipeline of intermediate representations.
An Anchor program that stores and updates user-defined key-value entries on-chain, a small favorites manager.
Two Anchor programs where one calls the other through a CPI, with a System Program transfer alongside it.
A minimalist on-chain guessing game built with Rust and Anchor: the contract picks a number, the player guesses it.
A minimal native Rust Solana program that increments and decrements an on-chain counter owned by the user's keypair.
RestOn is an agent that generates backend code from a text query. It is built in Rust on top of Actix-web.
How to manage Rust with rustup: release channels, toolchain overrides, components and build profiles.
A multi-threaded HTTP server written with the Rust standard library only: thread pool, TCP listener and static file serving.
An async RESTful notes service built with Actix-Web, Tokio, SQLx and SQLite: the architecture, the routes and the setup.
A terminal inventory manager built with Rust and Cursive: create, list and delete items, persisted in a flat JSON file.
A keyboard-driven Pomodoro timer built with Rust and Cursive, with a configurable session length and a minimal interface.
A Rust and wasm-bindgen experiment: build a WebAssembly tax calculator and serve it from a static page.
Three C++ games built in Unreal Engine 5 - Dungeon Raider, Toon Tanks and ISSRiot - and what they taught me about level design.
A Java Swing desktop app that creates and launches Android emulators, downloads missing system images and lists running devices.
A Spring Boot pipeline that fetches a page, parses it with Jsoup, maps the data to POJOs and writes an Excel file.
Nothing matches that. Clear the search, or pick another subject.
Four channels, all of them read. Pick the one that suits the question.
Where to start: a short question goes to Telegram, a brief goes to email.
No match.