<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: andreysparish</title>
    <description>The latest articles on DEV Community by andreysparish (@andreysparish).</description>
    <link>https://dev.to/andreysparish</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4014787%2F7f0bd48b-22e3-435d-8734-af4f84560fa2.png</url>
      <title>DEV Community: andreysparish</title>
      <link>https://dev.to/andreysparish</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andreysparish"/>
    <language>en</language>
    <item>
      <title>How to verify an LLM agent's audit log without the decryption key</title>
      <dc:creator>andreysparish</dc:creator>
      <pubDate>Sun, 04 Oct 2026 13:52:54 +0000</pubDate>
      <link>https://dev.to/andreysparish/how-to-verify-an-llm-agents-audit-log-without-the-decryption-key-2870</link>
      <guid>https://dev.to/andreysparish/how-to-verify-an-llm-agents-audit-log-without-the-decryption-key-2870</guid>
      <description>&lt;p&gt;If an agent's log says it called a tool on a given day, how does someone outside your team check that, without you handing over the key that decrypts every prompt in it?&lt;br&gt;
Below is the check we built into &lt;a&gt;Palimpsests (PALA-1)&lt;/a&gt;, an Apache-2.0 runtime for local LLM inference. You can run all of it offline in about a minute.&lt;br&gt;
&lt;strong&gt;What the verifier looks at&lt;/strong&gt;&lt;br&gt;
Every record in the log has a header and an optional body. The header stores the SHA-256 of its own body and the hash of the record before it. The verifier walks the headers one by one and compares each body with the digest stored for it. It never decrypts a body, so it never needs the key.&lt;br&gt;
&lt;strong&gt;Step 1: write a small audited run&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;pip install palimpsests&lt;br&gt;
palimpsests demo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The demo uses a deterministic backend, so nothing gets downloaded. It serves one turn, lets the model call a tool and writes the result to palimpsests-demo.pala. With 0.12.0 the output ends like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Audit chain written: palimpsests-demo.pala&lt;br&gt;
Verifying with the production reader (what an auditor runs)&lt;br&gt;
   records: 7   chain_ok: True   head: a3682a36b3a9b703…&lt;br&gt;
   recorded events: MODEL_LOAD, TOOL_CALL, TOOL_RESULT&lt;/em&gt;&lt;br&gt;
Your head hash will be different, because the headers include boot ids and timestamps.&lt;br&gt;
&lt;strong&gt;Step 2: verify the file on its own&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;palimpsests pala verify palimpsests-demo.pala&lt;br&gt;
_&lt;br&gt;
Text&lt;br&gt;
_consistency: 7 records, chain intact&lt;br&gt;
completeness: NOT CHECKED — no --anchor supplied, so tail truncation or wholesale replacement would not have been detected&lt;br&gt;
witness: no WITNESS records — existence at a point in time is not attested&lt;/em&gt;&lt;br&gt;
The exit code is 2.&lt;br&gt;
With nothing but the file, the verifier can confirm that no record inside it was changed, dropped or moved. It can't tell whether someone deleted the last few records, or swapped the whole file for another chain that is consistent with itself. So it says that it didn't check, and exits with a code your CI can tell apart from success.&lt;br&gt;
&lt;strong&gt;Step 3: give it an anchor&lt;/strong&gt;&lt;br&gt;
An anchor is the latest head hash, stored somewhere outside the file. In a real deployment that's an anchor file, a PKCS#11 token or a transparency service. For the demo, take the head from the JSON output and pass it by hand:&lt;br&gt;
&lt;em&gt;HEAD=$(palimpsests pala verify palimpsests-demo.pala --json | python3 -c "import json,sys; print(json.load(sys.stdin)['head'])")&lt;br&gt;
palimpsests pala verify palimpsests-demo.pala --anchor "$HEAD"&lt;/em&gt;&lt;br&gt;
Exit code 0. No key was used at any point.&lt;br&gt;
&lt;strong&gt;Step 4: break it&lt;/strong&gt;&lt;br&gt;
Flip one bit at byte 200 and check again with the same anchor:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;cp palimpsests-demo.pala tampered.pala&lt;br&gt;
python3 -c "d=bytearray(open('tampered.pala','rb').read()); d[200]^=1; open('tampered.pala','wb').write(d)"&lt;br&gt;
palimpsests pala verify tampered.pala --anchor "$HEAD"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Exit code 1.&lt;br&gt;
The two lines contradict each other only at first sight. The edit was in an early record, so the last record and its hash are untouched and still match the anchor. The link between records 1 and 2 no longer holds, and the verifier names where. Someone investigating can tell an edit in the middle from a cut at the end, because the tool reports them separately.&lt;br&gt;
&lt;strong&gt;Limits&lt;/strong&gt;&lt;br&gt;
The demo backend only stands in for a model. Real runs use llama.cpp or Ollama on your own hardware.&lt;br&gt;
The log implementation has not been through an independent penetration test yet.&lt;br&gt;
&lt;strong&gt;Why bother with any of this&lt;/strong&gt;&lt;br&gt;
For high-risk AI systems in the EU, Article 12 of the AI Act asks for automatic event logs, and deployers have to keep them for at least six months under Article 26(6). An auditor will usually start with the tool calls, since that's where an agent acts on the world. I wrote the legal side up separately, with dates and the actual fine levels: &lt;a href="https://palimpsests.dev/eu-ai-act-article-12/" rel="noopener noreferrer"&gt;EU AI Act Article 12 for self-hosted LLMs&lt;/a&gt;.&lt;br&gt;
The records use PALA-1 (Portable Append-only Log for Audit). The format was frozen at v1.0 in August 2026, the spec and test vectors are CC0, and five independent implementations have reproduced it from the spec alone. If you'd rather write your own verifier than trust ours, start at &lt;a href="https://palimpsests.dev/" rel="noopener noreferrer"&gt;palimpsests.dev/pala-1&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>security</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I stopped writing automations and started hiring AI workers</title>
      <dc:creator>andreysparish</dc:creator>
      <pubDate>Sat, 04 Jul 2026 09:33:31 +0000</pubDate>
      <link>https://dev.to/andreysparish/i-stopped-writing-automations-and-started-hiring-ai-workers-5bcn</link>
      <guid>https://dev.to/andreysparish/i-stopped-writing-automations-and-started-hiring-ai-workers-5bcn</guid>
      <description>

&lt;p&gt;title: "I stopped wr&lt;br&gt;
Most "AI at work" is still a chatbot in a corner: you ask, it answers, the work is still yours. I wanted the opposite — something I could hand a whole task to and get a result back, not a suggestion.&lt;/p&gt;

&lt;p&gt;So instead of building automations, I started hiring workers. Here's what that actually means in practice, and where the useful parts are.&lt;/p&gt;

&lt;h2&gt;
  
  
  First: any API becomes a tool, with no code
&lt;/h2&gt;

&lt;p&gt;Before a worker is useful, it needs things it can &lt;em&gt;do&lt;/em&gt;. The usual way to give an AI a new capability is to write an integration — read the docs, model the endpoints, wire the auth, handle errors. An afternoon each.&lt;/p&gt;

&lt;p&gt;Instead: paste a domain. If the model already knows the API, you get a working tool immediately. If it doesn't, it searches, scrapes the docs across pages, and assembles the endpoints into one schema. Add the key, activate, done — the API is now a native tool your workers can call. No hand-written JSON, no glue code.&lt;/p&gt;

&lt;p&gt;That alone removed most of the busywork. But the connectors are just the raw materials. The interesting part is who uses them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hiring a worker
&lt;/h2&gt;

&lt;p&gt;A worker isn't a prompt. It's a hire with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A role.&lt;/strong&gt; What it's for, what "good" looks like, and where its boundaries are. This is the part that decides whether a worker is useful or useless — same as hiring a human.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A brain you choose.&lt;/strong&gt; Each worker runs on the model you pick — Claude, GPT, or Gemini — so you can put a strong-reasoning model on the tricky role and a cheaper/faster one on the repetitive one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools it's allowed to use.&lt;/strong&gt; You hand a worker exactly the capabilities its job needs, and nothing else.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tool set a worker can be given is the point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Email&lt;/strong&gt; — read an inbox, send and reply over IMAP/SMTP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhooks&lt;/strong&gt; — an external event can wake a worker and hand it the payload to act on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt; — a worker remembers across runs, so it doesn't repeat itself or lose the thread of a project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File storage&lt;/strong&gt; — durable storage that survives restarts, for the documents and artifacts a worker produces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Site logins&lt;/strong&gt; — you store a worker's credentials for third-party sites (encrypted, write-only — the password is never readable back), and it can log in and do real work on those sites on your behalf.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tasks: work that starts without you
&lt;/h2&gt;

&lt;p&gt;A worker owns tasks. A task runs on a trigger, not on you sitting there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;on a &lt;strong&gt;schedule&lt;/strong&gt; (every morning, every two days, whatever the cron says),&lt;/li&gt;
&lt;li&gt;when an &lt;strong&gt;email&lt;/strong&gt; lands,&lt;/li&gt;
&lt;li&gt;when a &lt;strong&gt;webhook&lt;/strong&gt; fires.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So a content worker can draft and publish on a cadence; an inbox worker can triage mail as it arrives; a monitoring worker can react to an event the second it happens. You come back to results.&lt;/p&gt;

&lt;h2&gt;
  
  
  The supervisor: staying in control of the team
&lt;/h2&gt;

&lt;p&gt;Handing autonomy to software is only comfortable if you can rein it in. That's the supervisor layer, and it's the thing I'd have refused to run without:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hire and fire.&lt;/strong&gt; Spin up a new worker for a role, pause one, or retire it entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assign and adjust tasks.&lt;/strong&gt; Give a worker a task, change its schedule, edit its instructions, disable it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch what it does.&lt;/strong&gt; Every run is logged — you can see what each worker did, when, and why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approve the risky stuff.&lt;/strong&gt; Anything that reaches the outside world (sending mail, publishing, posting) can go through an approval gate: the worker &lt;em&gt;proposes&lt;/em&gt;, you approve, then it acts. You decide how much rope each worker gets, and you can widen it as trust builds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last part is what makes the difference between "an agent I'm nervous about" and "a teammate with a clear job." The worker does the work; the human stays the one who signs off.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is honestly not magic
&lt;/h2&gt;

&lt;p&gt;Worth saying plainly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A worker is only as good as its role. Vague instructions → vague output. The org-design thinking doesn't disappear; it moves to you.&lt;/li&gt;
&lt;li&gt;No-code connectors depend on the target API's docs. Clean docs → clean tool; weird undocumented endpoint → you'll still be nudging it.&lt;/li&gt;
&lt;li&gt;It's a hosted platform and currently closed beta, so treat sensitive data and rough edges accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that is a dealbreaker for how I use it, but "hire a worker" doesn't mean "skip the judgment."&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;It's in closed beta — the first batch of builders get lifetime access to the core, plus some provider credit. If you want to build a small team that works while you sleep: (&lt;a href="https://toolweave.dev/blog/en/build-a-team-of-ai-workers" rel="noopener noreferrer"&gt;https://toolweave.dev/blog/en/build-a-team-of-ai-workers&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Question for anyone already running agents: what's the first role you'd actually hire for — inbox triage, a QA bot, a content worker, something else? And what would you &lt;em&gt;not&lt;/em&gt; let it do without approval?&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
  </channel>
</rss>
