Posts

Pinned Post

NodePulse: so your Lightning node speaks up before it gets expensive

Bild
  A Lightning node is an odd kind of device. It sits on a shelf somewhere, a Raspberry Pi with an SSD, and as long as everything works you don’t look at it for weeks. That is exactly the problem. When LND hangs, the SSD fills up or a peer has been offline for days, nobody tells you. You only notice when a payment fails. Or worse: when an HTLC is about to expire and nobody reacts. RaspiBlitz comes with a lot, but not with alerting that actively nudges me. The ready-made solutions I looked at were either too big (Prometheus, Grafana and Alertmanager on a Pi that is supposed to run a Bitcoin node) or they ran as a service somewhere else, with access to my node data. I didn’t want either. So I built NodePulse. A small program that runs directly on the node, checks every minute whether everything is fine, and sends me a Telegram message when it isn’t. And another one once the problem is gone. On top of that there is a dashboard in the browser. In this article I explain what NodePulse...

Taken out again

Bild
  I took the framework out again The first post in this series started with two agents, a classic one and an AI one, "both implemented as Jido agents". Every cover since has carried a small purple label saying "Jido". The last post built a loop, a process per conversation, an approval before generated code runs for the first time. Now Jido is no longer in the mix.exs . Three merge requests, eleven packages fewer in the lockfile at the end, and the code in lib is fifty lines shorter than before, even though it now does things itself that the framework used to do. This is not a verdict on Jido. It is a report on what a framework does in a demo that is meant to show what an agent is, and why I did not want it in this demo anymore. What I actually used Before taking anything out, I counted. Jido brings a lot: plugins, sensors, scheduled jobs, pods, a memory of its own with threads, observability, compensation on failure, persistence to hibernate and thaw agents. ...

Plan, Run, Look Again

Bild
  Last time it still could not see its own results The last post ended with a prediction. The steps were not chained, step two did not see what step one returned, and changing that meant results needed stable names, the plan would stop being a flat list and become a small dataflow graph, with cycles and types that change shape between two steps. "It is not a small change dressed up as one." It was a small change. I had just solved the wrong problem. You need a dataflow graph when the whole plan has to be fixed up front. It does not. If the planner sees the results after every round and gets asked again, it simply writes the value from step one into step two as a concrete parameter. The graph never exists, because the model is the dataflow. The agent, now as a loop defp loop(%{steps: []} = plan, agent, _context, rounds, _left, _opts), do: finish(agent, rounds, plan.reasoning, :answered) defp loop(plan, agent, context, rounds, left, opts) do steps = Enum.map(plan.ste...

Who picks the tool

Bild
The previous post ended with an agent that writes a missing tool into a running node. Generate, sanitize, persist, compile, load, execute, about 25 milliseconds after the model answers. I was happy with that for roughly a week. Then I looked at the demo page again and counted the text fields. Tool name. What it should do. Parameters as JSON. I had filled in all three. The gap-finding was real. The deciding was mine. MetaPlannerAgent.run("Publish the article", [ %{tool: "classic_plan", params: %{goal: "Write draft, review, publish"}}, %{tool: "slugify_text", description: "Turns a title into a URL slug", params: %{text: "Hello World"}} ]) Everything interesting in that call sits in the second argument, and I typed it. The agent resolved slugify_text , noticed it wasn't in the catalog and had it written. It never asked whether the task needed a slug at all. So this post is about the agent in front of that, the on...

The tool that wasn't there, so the agent wrote it

Bild
Last time I had two agents doing the same job, one on fixed rules, one asking a language model. The AI agent was free to decide the order of its steps, but it could only pick from tools I had written beforehand. Everything it was able to do, I had guessed in advance. So what happens when it needs something that isn't in the catalog? Normally a polite refusal. I wanted to know what the other answer costs, the one where the agent writes the tool itself, in the running system, without a restart. I built it over a weekend. Getting code out of the model worked after two hours. The rest of the Sunday went into everything that comes after that. A catalog is a list, and lists end Tool calling works the same way everywhere. You give the model a list of functions with their parameters, it picks one, you run it, you hand the result back. That's fine, and it has a ceiling that's easy to overlook. The agent can only ever be as capable as my list. For a support bot with eleven known ...

OpenSpec UI: ein Live-Dashboard für deine Specs

Bild
OpenSpec UI: ein Live-Dashboard für deine Specs Wer mit einem KI-Agenten und OpenSpec arbeitet, kennt das Bild. Im Projekt wächst ein Verzeichnis openspec/ heran: Changes mit proposal.md , design.md , tasks.md und ihren Delta-Specs, daneben die kanonischen Specs der einzelnen Capabilities. Die Absicht hinter dem Code steht damit endlich geschrieben, statt sich in ihm zu verstecken. Nur verteilt sie sich über Dutzende Markdown-Dateien, und der Editor zeigt eben Dateien. Was er nicht zeigt, ist der Zustand. Woran arbeitet der Agent gerade? Welcher Task ist der nächste offene? Und was hat sich verändert, während ich zehn Minuten woanders hingeschaut habe? Genau diese Lücke füllt OpenSpec UI , ein kleines Phoenix-LiveView-Dashboard, das lokal neben deinem Projekt läuft und den OpenSpec-Workspace im Browser zeigt — live, während gearbeitet wird. Der Code liegt offen auf GitLab: https://gitlab.com/public_elixir/openspec_ui Ein Blick statt Datei-Hopping Du startest den Server, gibst d...
Bild
Spec Driven Development mit OpenSpec: ein Praxisbeispiel Die meisten Änderungen an einer Software fangen mit einem Halbsatz an: „Bau mal eben ein Cover in den Artikel ein.” Und dann geht es sofort in den Editor. Unterwegs treffen wir ein Dutzend kleiner Entscheidungen, raten, was wohl gemeint war, und am Ende läuft es irgendwie. Nur weiß hinterher niemand mehr genau, was das System eigentlich können soll. Diese Wahrheit steckt dann im Code, verteilt über viele Dateien, und entfernt sich mit jedem Commit ein Stück weiter von der ursprünglichen Absicht. Spec Driven Development, kurz SDD, dreht die Reihenfolge um. Zuerst wird beschrieben, was das System tun soll. Erst danach geht es an das Wie. In diesem Artikel zeige ich, was dahintersteckt, wie der Prozess mit dem Werkzeug OpenSpec (openspec.dev) konkret aussieht und welche Befehle man dafür braucht. Als roter Faden dient eine echte Änderung aus dem Projekt pdf_finder. Was Spec Driven Development ist Im Kern trennt SDD zwei Dinge, die s...

Beliebte Posts aus diesem Blog

Splitting an ML model and a web app across two BEAM nodes — the technical blueprint

Jido in Practice: Agents in Elixir as Composable Actions

A Foundation Model in the BEAM: On-Chain Anomalies with Google TimesFM in Elixir