<?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: Michal Žídek</title>
    <description>The latest articles on DEV Community by Michal Žídek (@m1chlcz18).</description>
    <link>https://dev.to/m1chlcz18</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%2F4177693%2Fcf5be6bf-5017-46f8-8bfc-a6dd2c0163fb.png</url>
      <title>DEV Community: Michal Žídek</title>
      <link>https://dev.to/m1chlcz18</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/m1chlcz18"/>
    <language>en</language>
    <item>
      <title>AgentWave: policy-validated assistant suggestions for Go backends</title>
      <dc:creator>Michal Žídek</dc:creator>
      <pubDate>Sun, 11 Oct 2026 20:37:05 +0000</pubDate>
      <link>https://dev.to/m1chlcz18/agentwave-policy-validated-assistant-suggestions-for-go-backends-1cp3</link>
      <guid>https://dev.to/m1chlcz18/agentwave-policy-validated-assistant-suggestions-for-go-backends-1cp3</guid>
      <description>&lt;p&gt;I maintain &lt;a href="https://github.com/M1chlCZ/agentwave" rel="noopener noreferrer"&gt;AgentWave&lt;/a&gt;, an MIT-licensed Go project for adding an assistant to admin panels, CRMs, dashboards, and internal tools.&lt;/p&gt;

&lt;p&gt;The interface is small: send a request and the current screen route, then receive one action suggestion that passes a configured policy. Your application decides whether to show or apply it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The request flow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Your application's backend sends a request over a private Unix socket.&lt;/li&gt;
&lt;li&gt;AgentWave creates a job and asks its Codex CLI backend for a suggestion.&lt;/li&gt;
&lt;li&gt;The result must match the policy. A result outside the policy becomes a failed job.&lt;/li&gt;
&lt;li&gt;Your backend retrieves the result. Any action still goes through your application's permission checks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A browser cannot connect to the Unix socket directly. Your backend acts as the proxy and supplies the actor ID from its own user or session context.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small policy example
&lt;/h2&gt;

&lt;p&gt;This example comes from the repository's README:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"help"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"navigate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lookup"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"modules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"home"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"contacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reports"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"routePrefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queryActions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lookup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"contacts"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, an admin panel can ask where to find a contact from &lt;code&gt;/admin/contacts&lt;/code&gt;. The assistant can return a &lt;code&gt;lookup&lt;/code&gt; suggestion. The host application decides how to handle it.&lt;/p&gt;

&lt;p&gt;The HTTP interface has three routes: &lt;code&gt;GET /healthz&lt;/code&gt;, &lt;code&gt;POST /jobs&lt;/code&gt;, and &lt;code&gt;GET /job&lt;/code&gt;. Job submission returns a &lt;code&gt;working&lt;/code&gt; status; the client polls until the job is &lt;code&gt;ready&lt;/code&gt; or &lt;code&gt;failed&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;p&gt;The Go module has no external dependencies. The generation backend requires the Codex CLI, configured model access, and any authentication that access requires. The MIT license covers AgentWave's code; it does not provide free model access.&lt;/p&gt;

&lt;p&gt;The repository includes local setup instructions, Docker and Compose examples, and a backend proxy example. Policy validation is one layer of the integration; keep authentication and authorization in your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/M1chlCZ/agentwave" rel="noopener noreferrer"&gt;Source code and setup instructions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback on the policy format, job API, and integration examples is welcome. My other Go project, &lt;a href="https://github.com/M1chlCZ/nsfw_sherlock" rel="noopener noreferrer"&gt;NSFW Sherlock&lt;/a&gt;, provides a self-hosted image moderation API.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prepared with AI assistance from the project's public documentation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>NSFW Sherlock: a self-hosted image moderation API in Go</title>
      <dc:creator>Michal Žídek</dc:creator>
      <pubDate>Sun, 11 Oct 2026 19:16:35 +0000</pubDate>
      <link>https://dev.to/m1chlcz18/nsfw-sherlock-a-self-hosted-image-moderation-api-in-go-5bnm</link>
      <guid>https://dev.to/m1chlcz18/nsfw-sherlock-a-self-hosted-image-moderation-api-in-go-5bnm</guid>
      <description>&lt;p&gt;I maintain &lt;a href="https://github.com/M1chlCZ/nsfw_sherlock" rel="noopener noreferrer"&gt;NSFW Sherlock&lt;/a&gt;, an open-source image moderation API written in Go. It uses ONNX Runtime and offers HTTP and gRPC interfaces.&lt;/p&gt;

&lt;p&gt;You send an image to your own instance and get structured classification results. The service classifies photos and anime, detects explicit regions, and can use Tesseract OCR to check text in images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try the CPU Docker image
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;APP_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;web &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:4000:4000 m1chl/nsfw-sherlock
curl http://localhost:4000/ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The image includes the models and OCR support, with Linux amd64 and arm64 builds. Binding the port to &lt;code&gt;127.0.0.1&lt;/code&gt; keeps this first test local to your machine.&lt;/p&gt;

&lt;p&gt;Image requests use JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"base64"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;base64-encoded image&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"filename"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"image.jpg"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST /pic/check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Image and text flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST /pic/labels&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Classification probabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST /pic/analyze&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verdict, model scores, detected regions, and timing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For gRPC, start with &lt;code&gt;APP_ENV=grpc&lt;/code&gt;. The &lt;a href="https://github.com/M1chlCZ/nsfw_sherlock/blob/main/proto/nsfw.proto" rel="noopener noreferrer"&gt;protobuf definition&lt;/a&gt; describes its methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Profiles and limits
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;balanced&lt;/code&gt; profile is the default. &lt;code&gt;fast&lt;/code&gt; uses lighter models for part of the pipeline, while &lt;code&gt;max&lt;/code&gt; uses a larger region detector. &lt;code&gt;compat&lt;/code&gt; keeps the legacy five-label classifier. The README lists the exact models and settings.&lt;/p&gt;

&lt;p&gt;The current backend is ONNX Runtime; older references to TensorFlow do not describe the current engine.&lt;/p&gt;

&lt;p&gt;Classification is probabilistic. Scores and model details help applications make their own decisions; they do not guarantee every image will be classified correctly.&lt;/p&gt;

&lt;p&gt;NVIDIA CUDA and AMD MIGraphX configuration are documented, but GPU inference has not yet been verified on physical NVIDIA or AMD hardware. The CPU container is the starting point shown here.&lt;/p&gt;

&lt;p&gt;The code is AGPL-3.0. Upstream model licenses remain separate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/M1chlCZ/nsfw_sherlock" rel="noopener noreferrer"&gt;Source, setup, and API documentation&lt;/a&gt; · &lt;a href="https://hub.docker.com/r/m1chl/nsfw-sherlock" rel="noopener noreferrer"&gt;Docker image&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd welcome feedback on API integration and which response format is useful in your application. Please do not put private images in public issues.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prepared with AI assistance from the project's public documentation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>go</category>
      <category>opensource</category>
      <category>api</category>
    </item>
    <item>
      <title>Rust-a-Log: filter recent errors in a large log, then keep watching</title>
      <dc:creator>Michal Žídek</dc:creator>
      <pubDate>Sun, 11 Oct 2026 19:14:19 +0000</pubDate>
      <link>https://dev.to/m1chlcz18/rust-a-log-filter-recent-errors-in-a-large-log-then-keep-watching-2p6</link>
      <guid>https://dev.to/m1chlcz18/rust-a-log-filter-recent-errors-in-a-large-log-then-keep-watching-2p6</guid>
      <description>&lt;p&gt;I maintain &lt;a href="https://github.com/M1chlCZ/Rust-a-Log" rel="noopener noreferrer"&gt;Rust-a-Log&lt;/a&gt;, a small command-line log viewer written in Rust. It reads recent records, filters them, and follows new writes.&lt;/p&gt;

&lt;p&gt;The useful detail is where the line count applies. If you ask for the last 20 errors or warnings, it finds 20 matching records, rather than taking the last 20 lines and discarding everything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try the current source
&lt;/h2&gt;

&lt;p&gt;With Rust installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--git&lt;/span&gt; https://github.com/M1chlCZ/Rust-a-Log &lt;span class="nt"&gt;--locked&lt;/span&gt;
rual app.log &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows the last 20 errors or warnings and follows new records. Press Ctrl+C to stop.&lt;/p&gt;

&lt;p&gt;For a one-time search:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rual app.log &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nb"&gt;timeout&lt;/span&gt; &lt;span class="nt"&gt;--ignore-case&lt;/span&gt; &lt;span class="nt"&gt;--once&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can combine the two:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rual app.log &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; database &lt;span class="nt"&gt;-n&lt;/span&gt; 5 &lt;span class="nt"&gt;--once&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prints the last five error records that also contain &lt;code&gt;database&lt;/code&gt;. The text filter is literal, not a regular expression.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why scan backwards?
&lt;/h2&gt;

&lt;p&gt;When you only need recent records, reading the entire file first does unnecessary work. Rust-a-Log scans backwards in 64 KiB blocks until it finds enough matching records. Its memory use depends on the longest record and a small buffer, rather than the total file size.&lt;/p&gt;

&lt;p&gt;A rare filter can still require scanning the whole file. There is no search index or cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few limits to know
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Input must be a regular, seekable text file. Stdin, compressed logs, and multiline event grouping are not supported.&lt;/li&gt;
&lt;li&gt;Level filters recognise bracketed labels such as &lt;code&gt;[ERROR]&lt;/code&gt;, &lt;code&gt;[WARN]&lt;/code&gt;, and &lt;code&gt;[INFO]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Linux and macOS can reopen a renamed or replaced log. On Windows, rename rotation requires restarting the viewer.&lt;/li&gt;
&lt;li&gt;Following uses polling, so a file that is truncated and regrown between checks can lose records.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://github.com/M1chlCZ/Rust-a-Log#readme" rel="noopener noreferrer"&gt;README&lt;/a&gt; covers the full behaviour and includes an example screenshot. The project is free and MIT-licensed.&lt;/p&gt;

&lt;p&gt;I'd welcome feedback on the log formats you use and which filtering or rotation cases are awkward with your current tools. Reproducible examples are especially useful.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was prepared with AI assistance from the project's public documentation.&lt;/em&gt;&lt;/p&gt;

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