<?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: Syed Kabeer Ali</title>
    <description>The latest articles on DEV Community by Syed Kabeer Ali (@syed_kabeerali_65ed7d04d).</description>
    <link>https://dev.to/syed_kabeerali_65ed7d04d</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%2F3961215%2F2477a176-9f97-4fd0-82aa-05486c26ac62.png</url>
      <title>DEV Community: Syed Kabeer Ali</title>
      <link>https://dev.to/syed_kabeerali_65ed7d04d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/syed_kabeerali_65ed7d04d"/>
    <language>en</language>
    <item>
      <title>I Built NeuroGraph: What DevOps Agents Can Learn from the Human Nervous System</title>
      <dc:creator>Syed Kabeer Ali</dc:creator>
      <pubDate>Sun, 18 Oct 2026 18:23:29 +0000</pubDate>
      <link>https://dev.to/syed_kabeerali_65ed7d04d/i-built-neurograph-what-devops-agents-can-learn-from-the-human-nervous-system-5bca</link>
      <guid>https://dev.to/syed_kabeerali_65ed7d04d/i-built-neurograph-what-devops-agents-can-learn-from-the-human-nervous-system-5bca</guid>
      <description>&lt;p&gt;A service reports that it's unhealthy. What do you do next?&lt;/p&gt;

&lt;p&gt;You might check the logs, look at its dependencies, find the owner, inspect the relevant policy, or search for an incident that looks familiar. You might discover that the last restart didn't actually fix the problem.&lt;/p&gt;

&lt;p&gt;The hard part isn't necessarily finding one piece of information. It's connecting the pieces and deciding what they mean together.&lt;/p&gt;

&lt;p&gt;That problem reminded me of something from human anatomy and physiology: the body doesn't work as a collection of completely isolated parts. Nervous signals, feedback mechanisms, and organ systems interact. A symptom alone often doesn't explain the entire picture.&lt;/p&gt;

&lt;p&gt;I started building NeuroGraph around a similar engineering intuition: an agent should understand relationships between operational facts, remember previous outcomes, and verify whether an attempted fix worked.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/MaskedMan-code/NeuroGraph" rel="noopener noreferrer"&gt;https://github.com/MaskedMan-code/NeuroGraph&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why I wanted a graph-based approach&lt;/p&gt;

&lt;p&gt;During an incident, the relevant context can be scattered across service inventories, alert descriptions, runbooks, team ownership, policies, and incident history.&lt;/p&gt;

&lt;p&gt;A conventional assistant might receive an error and produce a plausible answer. But plausibility isn't enough for an operational workflow. I wanted the system to establish what it knows, explain where the evidence comes from, and acknowledge what it cannot establish.&lt;/p&gt;

&lt;p&gt;NeuroGraph represents the operational environment as a connected graph in FalkorDB.&lt;/p&gt;

&lt;p&gt;The graph includes services, employees, teams, projects, dependencies, incidents, policies, documents, actions, outcomes, and memories.&lt;/p&gt;

&lt;p&gt;For example, Graph Explorer can find a path like this:&lt;/p&gt;

&lt;p&gt;emp-bob → svc-payment-api-stg → pol-staging-restart&lt;/p&gt;

&lt;p&gt;That path tells us more than three independent records. It connects a person to a service they own and to the policy governing a possible remediation.&lt;/p&gt;

&lt;p&gt;The graph is doing actual work here. It's not just a visualisation placed on top of an otherwise disconnected application.&lt;/p&gt;

&lt;p&gt;The stack behind NeuroGraph&lt;/p&gt;

&lt;p&gt;The project uses:&lt;/p&gt;

&lt;p&gt;Next.js for the user interface.&lt;/p&gt;

&lt;p&gt;FastAPI for backend APIs.&lt;/p&gt;

&lt;p&gt;LangGraph for workflow orchestration and session continuity.&lt;/p&gt;

&lt;p&gt;FalkorDB for graph relationships, operational data, and explicit application memory.&lt;/p&gt;

&lt;p&gt;The interface includes an operations dashboard, Graph Explorer, Incident Copilot, Memory Timeline, Audit Log, and demo settings.&lt;/p&gt;

&lt;p&gt;The workflow follows graph-backed evidence to identify an affected service, retrieve its owner and dependencies, inspect the applicable policy, look at prior incidents, and decide what the current request permits.&lt;/p&gt;

&lt;p&gt;I think of the graph as a bit like a network of connected pathways. The analogy isn't meant to suggest that a database is a biological nervous system. The engineering point is simpler: context becomes more useful when relationships can be traversed and inspected.&lt;/p&gt;

&lt;p&gt;Three request modes&lt;/p&gt;

&lt;p&gt;I separated three things that are often blurred together in agent demos.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Investigate only&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent gathers evidence about the service, its dependencies, policy, ownership, incident history, and relevant memories.&lt;/p&gt;

&lt;p&gt;This mode must not produce operational proposals or execute actions. It should still suggest sensible investigative steps if the incident remains unresolved.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Recommend action&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent can prepare a proposed remediation and explain the relevant evidence and policy constraints, but it doesn't execute the operation.&lt;/p&gt;

&lt;p&gt;That separation matters. A recommendation should remain inspectable rather than quietly becoming an action.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Request action&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An explicit action request enters the policy-controlled workflow. Permissions, environment restrictions, policy decisions, approval requirements, and tool-level checks constrain what can happen.&lt;/p&gt;

&lt;p&gt;In this prototype, operations are simulated. The production restart scenario requires human approval and remains pending rather than bypassing that requirement.&lt;/p&gt;

&lt;p&gt;I also tested alert content that included malicious instructions. The workflow treats those instructions as untrusted data; they don't get to override the system's policy simply because they appear in an incident report.&lt;/p&gt;

&lt;p&gt;A restart isn't the same as recovery&lt;/p&gt;

&lt;p&gt;This became one of my favourite tests.&lt;/p&gt;

&lt;p&gt;The staging transaction processor was degraded. NeuroGraph accepted a simulated restart, but the verification step still observed the service as degraded.&lt;/p&gt;

&lt;p&gt;A less careful demo could mark the whole workflow successful because the restart command returned successfully.&lt;/p&gt;

&lt;p&gt;NeuroGraph records the distinction between the accepted command and the failed verification. The Audit Log records the observed status, and the failed outcome is stored in application memory.&lt;/p&gt;

&lt;p&gt;Then I ran another investigation.&lt;/p&gt;

&lt;p&gt;The agent retrieved the previous failed outcome rather than treating the earlier attempt as a successful recovery.&lt;/p&gt;

&lt;p&gt;That's where another analogy from physiology becomes useful: feedback matters. A response has to be evaluated against the state it was supposed to improve. Sending a signal is not proof that the desired result occurred.&lt;/p&gt;

&lt;p&gt;For an operational agent, the equivalent is straightforward:&lt;/p&gt;

&lt;p&gt;Action accepted does not mean service recovered.&lt;/p&gt;

&lt;p&gt;Memory should preserve the outcome, not just the attempt&lt;/p&gt;

&lt;p&gt;NeuroGraph stores application memories as graph records with types and verification statuses. These include episodic memories, procedural knowledge, decisions, outcomes, and session-related records.&lt;/p&gt;

&lt;p&gt;That is deliberately separate from LangGraph's workflow checkpoints.&lt;/p&gt;

&lt;p&gt;The distinction is useful because different memories answer different questions:&lt;/p&gt;

&lt;p&gt;An episodic memory can describe a previous incident.&lt;/p&gt;

&lt;p&gt;A decision memory can record which policy applied.&lt;/p&gt;

&lt;p&gt;An outcome memory can say whether the remediation was verified.&lt;/p&gt;

&lt;p&gt;Procedural memory can capture steps worth considering during a future investigation.&lt;/p&gt;

&lt;p&gt;A previous fix should not automatically become today's answer. The present incident may have a different root cause, and a past remediation might only have mitigated the symptoms.&lt;/p&gt;

&lt;p&gt;In one investigation, the agent correctly retrieved an earlier database connection-pool issue while noting that the current root cause had not been established.&lt;/p&gt;

&lt;p&gt;I also found and corrected a response-quality problem: when no operational proposal existed, the workflow could say that no action was needed even though a service remained degraded. The updated response recommends reviewing evidence, escalating to the owner, and continuing the investigation before closing the incident.&lt;/p&gt;

&lt;p&gt;That correction was small, but the distinction matters. An agent can refrain from an unsafe operation and still give useful guidance.&lt;/p&gt;

&lt;p&gt;Testing the prototype&lt;/p&gt;

&lt;p&gt;I ran the backend suite and got 45 passing tests. The frontend passed TypeScript type checking and its Next.js production build.&lt;/p&gt;

&lt;p&gt;I also manually tested graph traversal, incident investigation, recommendations, production approval, prompt-injection handling, simulated action execution, failed verification, the Audit Log, cross-run memory retrieval, and the dashboard.&lt;/p&gt;

&lt;p&gt;Those tests establish that the demonstrated workflows run in this prototype. They are not a comprehensive security audit or a claim of production readiness.&lt;/p&gt;

&lt;p&gt;What isn't finished yet&lt;/p&gt;

&lt;p&gt;NeuroGraph currently runs in deterministic demo mode. No live LLM provider is configured, so the demo doesn't claim to show live LLM reasoning. Its operational actions are simulated and don't modify real infrastructure.&lt;/p&gt;

&lt;p&gt;Authentication is demo-grade, too. The current version isn't suitable for handling private production operational data without further work on identity, authorization, durable storage, deployment, and security.&lt;/p&gt;

&lt;p&gt;I want that boundary to be explicit because an attractive demo isn't the same thing as a production-ready incident platform.&lt;/p&gt;

&lt;p&gt;What I'd like to explore next&lt;/p&gt;

&lt;p&gt;The next stage is to finish the deployment validation, improve investigation guidance, review dependency advisories, and explore adding a live LLM without letting it bypass deterministic policy and tool controls.&lt;/p&gt;

&lt;p&gt;I'm also interested in the broader question of agent memory: how do we make sure an agent remembers a failed attempt as a failure, instead of repeatedly recommending the same action?&lt;/p&gt;

&lt;p&gt;For now, NeuroGraph has been a useful way to explore connected operational data, persistent memory, and verification-driven workflows.&lt;/p&gt;

&lt;p&gt;Try the code: &lt;a href="https://github.com/MaskedMan-code/NeuroGraph" rel="noopener noreferrer"&gt;https://github.com/MaskedMan-code/NeuroGraph&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd be interested in hearing how others approach agent memory and failed-action recovery. When an automated fix doesn't work, what should the system preserve so the next investigation actually benefits from the experience?&lt;/p&gt;

</description>
      <category>agents</category>
      <category>architecture</category>
      <category>devops</category>
      <category>sre</category>
    </item>
    <item>
      <title>How I Debugged an AI Incident Response Pipeline Using OpenTelemetry and SigNoz (And the 5 Mistakes That Nearly Broke My Hackathon Project)</title>
      <dc:creator>Syed Kabeer Ali</dc:creator>
      <pubDate>Sat, 18 Jul 2026 11:46:36 +0000</pubDate>
      <link>https://dev.to/syed_kabeerali_65ed7d04d/how-i-debugged-an-ai-incident-response-pipeline-using-opentelemetry-and-signoz-and-the-5-mistakes-58h6</link>
      <guid>https://dev.to/syed_kabeerali_65ed7d04d/how-i-debugged-an-ai-incident-response-pipeline-using-opentelemetry-and-signoz-and-the-5-mistakes-58h6</guid>
      <description>&lt;p&gt;Three days before the hackathon submission deadline, my local React dashboard looked absolutely flawless.&lt;/p&gt;

&lt;p&gt;I would trigger a simulated brute-force attack, the UI would instantly flash a red alert, the background Python engine would spin up a Google Gemini instance to analyze the threat vector, calculate a 94% confidence score, and cleanly trigger a simulated firewall tool to drop the offending IP address.&lt;/p&gt;

&lt;p&gt;From the outside, it was a software developer's dream. The frontend updated perfectly in real-time. But when I opened my self-hosted SigNoz instance to verify the backend data, the Trace Explorer was a complete ghost town.&lt;/p&gt;

&lt;p&gt;That was the exact moment I realized a foundational truth of modern software engineering: building an autonomous AI agent is only half the problem—making its internal reasoning transparent, observable, and auditable is the actual challenge.&lt;/p&gt;

&lt;p&gt;This is the raw engineering diary of how I built VigilTrace—an autonomous AI Incident Commander—and the exact telemetry roadblocks, Windows-specific traps, and OpenTelemetry architectural bugs I had to fight through to make it truly observable.&lt;/p&gt;

&lt;p&gt;What I Was Building: VigilTrace&lt;br&gt;
The design philosophy behind VigilTrace is simple: If you can't observe your AI agents, you don't own them.&lt;/p&gt;

&lt;p&gt;Instead of creating a black-box AI script that blindly triggers a shell command when a log drops, I architected an interactive pipeline that treats AI analysis as a multi-stage, regulated security investigation. The workflow operates as follows:&lt;/p&gt;

&lt;p&gt;Plaintext&lt;br&gt;
Server Simulator ──&amp;gt; Access Logs ──&amp;gt; Incident Commander (Python)&lt;br&gt;
                                                │&lt;br&gt;
  SigNoz UI &amp;lt;── OTLP Collector &amp;lt;── OpenTelemetry SDK &amp;lt;── Gemini AI&lt;br&gt;
                                                │&lt;br&gt;
                         [Blocklist.json] &amp;lt;── Firewall Simulator&lt;br&gt;
Every single link in this chain—from the raw token usage inside the Gemini LLM step to the file I/O latency inside the FirewallSimulator—had to emit structured telemetry packets over gRPC to a local OpenTelemetry Collector monitored via SigNoz.&lt;/p&gt;

&lt;p&gt;Mistake #1: The Phantom Metrics (Why create_gauge Left Me in the Dark)&lt;br&gt;
My first major roadblock was system metrics. I wanted to capture real-time resource spikes (cpu_usage and memory_usage) on the machine while the AI engine was chewing through dense security logs.&lt;/p&gt;

&lt;p&gt;I spun up a background metrics daemon in Python and wrote what I assumed was standard OpenTelemetry code:&lt;/p&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;h1&gt;
  
  
  THE BUGGY CODE THAT PRODUCED ZERO DATA IN SIGNOZ
&lt;/h1&gt;

&lt;p&gt;from opentelemetry import metrics&lt;/p&gt;

&lt;p&gt;meter = metrics.get_meter("system-monitor")&lt;br&gt;
cpu_gauge = meter.create_gauge(&lt;br&gt;
    name="system.cpu.utilization",&lt;br&gt;
    description="Tracks CPU load metrics"&lt;br&gt;
)&lt;/p&gt;

&lt;h1&gt;
  
  
  Polling loop trying to push values directly
&lt;/h1&gt;

&lt;p&gt;while True:&lt;br&gt;
    cpu_gauge.set(get_current_cpu_percent())&lt;br&gt;
    time.sleep(5)&lt;br&gt;
The script executed without crashing. No console errors, no warnings. Yet, when I checked the Metrics Explorer inside SigNoz, the dropdown menu for system.cpu.utilization simply did not exist.&lt;/p&gt;

&lt;p&gt;The Fix&lt;br&gt;
After diving into the official OpenTelemetry documentation, I realized a crucial architectural detail I had missed: metrics in OTel are primarily driven by a pull-based or asynchronous callback architecture to avoid blocking runtime threads. Synchronous gauges are often mishandled or dropped depending on how the OTLP exporter state is initialized.&lt;/p&gt;

&lt;p&gt;I had to completely refactor the metrics engine to use an Observable Gauge, passing a dedicated callback function that the SDK invokes automatically on its own collection cycle:&lt;/p&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;h1&gt;
  
  
  THE WORKING FIX: Migrating to an Asynchronous Observable Gauge
&lt;/h1&gt;

&lt;p&gt;from opentelemetry import metrics&lt;/p&gt;

&lt;p&gt;meter = metrics.get_meter("system-monitor")&lt;/p&gt;

&lt;p&gt;def get_cpu_callback(options):&lt;br&gt;
    # The SDK calls this function natively on every collection interval&lt;br&gt;
    return [metrics.Observation(get_current_cpu_percent())]&lt;/p&gt;

&lt;p&gt;meter.create_observable_gauge(&lt;br&gt;
    name="system.cpu.utilization",&lt;br&gt;
    callbacks=[get_cpu_callback],&lt;br&gt;
    description="Tracks real-time system CPU load percentage"&lt;br&gt;
)&lt;br&gt;
As soon as I spun up the script with the callback logic, the OTLP exporter began generating beautiful time-series line charts directly within the SigNoz metrics dashboard. Lesson learned: don't push data when the OpenTelemetry SDK wants to pull it.&lt;/p&gt;

&lt;p&gt;Mistake #2: The Broken Waterfall (Flat Spans vs. Nested Contexts)&lt;br&gt;
When I finally got my first trace batches to stream into the SigNoz Trace Explorer, the structural layout looked entirely wrong. Instead of a single, coherent incident timeline showing a clean hierarchy, SigNoz rendered ten completely disconnected, flat timelines:&lt;/p&gt;

&lt;p&gt;Plaintext&lt;br&gt;
❌ WHAT I SAW ORIGINALLY:&lt;br&gt;
Investigation (Trace ID: a1b2...)&lt;br&gt;
Recommendation (Trace ID: c3d4...)&lt;br&gt;
Firewall Execution (Trace ID: e5f6...)&lt;br&gt;
Because every stage was being drawn as a root span, I couldn't track the lineage of an incident. If the execution failed at the firewall stage, I had no clean visual way to trace it back to the specific LLM confidence calculation that triggered it.&lt;/p&gt;

&lt;p&gt;The Fix&lt;br&gt;
The bug was a classic context propagation error. In Python, if you use a standard async loop or call distinct functions across different files, the active OpenTelemetry tracing context can easily drop out if you don't explicitly pass it or set it inside the current execution context thread.&lt;/p&gt;

&lt;p&gt;I refactored the parent loop inside incident_commander.py to leverage the Python context manager, forcing child tasks to explicitly yield inside the parent scope:&lt;/p&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;h1&gt;
  
  
  THE FIX: Ensuring tight nesting of distributed trace spans
&lt;/h1&gt;

&lt;p&gt;from opentelemetry import trace&lt;/p&gt;

&lt;p&gt;tracer = trace.get_tracer(&lt;strong&gt;name&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;def run_incident_workflow(incident_data):&lt;br&gt;
    # Establish the overarching parent context span&lt;br&gt;
    with tracer.start_as_current_span("AI-Incident-Investigation") as parent_span:&lt;br&gt;
        parent_span.set_attribute("incident.id", incident_data["id"])&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # Explicitly passing structural execution tokens down the pipeline
    analyze_threat_vector(incident_data)
    execute_mitigation_workflow(incident_data)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def execute_mitigation_workflow(incident_data):&lt;br&gt;
    # This automatically detects and nests itself under the active parent span&lt;br&gt;
    with tracer.start_as_current_span("FirewallSimulator.block_ip") as child_span:&lt;br&gt;
        child_span.set_attribute("tool.action", "drop_packet")&lt;br&gt;
        # Simulating file I/O blocklist updates&lt;br&gt;
        write_to_blocklist(incident_data["attacker_ip"])&lt;br&gt;
This tiny adjustments paid off instantly. The next time I fired up the app, SigNoz rendered a gorgeous nested flamegraph waterfall:&lt;/p&gt;

&lt;p&gt;Plaintext&lt;br&gt;
✅ THE CORRECT HIERARCHY IN SIGNOZ:&lt;br&gt;
AI-Incident-Investigation [Trace ID: 7fa98c...]&lt;br&gt;
├── Analyze_Threat_Vector (LLM Ingestion)&lt;br&gt;
└── Execute_Mitigation_Workflow&lt;br&gt;
    └── FirewallSimulator.block_ip&lt;br&gt;
Mistake #3: The Windows Path Trap (spawn python3 ENOENT)&lt;br&gt;
Because I develop across different operating environments, I cloned my Next.js/Node.js telemetry aggregator backend onto my secondary Windows workstation to test stability.&lt;/p&gt;

&lt;p&gt;I hit npm run dev, clicked the execution button on the frontend interface, and my Node runtime exploded with this raw error block:&lt;/p&gt;

&lt;p&gt;Plaintext&lt;br&gt;
events.js:377&lt;br&gt;
      throw er; // Unhandled 'error' event&lt;br&gt;
      ^&lt;br&gt;
Error: spawn python3 ENOENT&lt;br&gt;
    at Process.ChildProcess._handle.onread (internal/child_process.js:245:12)&lt;br&gt;
    at onErrorNT (internal/child_process.js:482:16)&lt;br&gt;
The issue was painfully obvious yet highly disruptive: my Node core layer was hardcoded to invoke the background telemetry workers via a direct shell invocation to python3. While Linux and macOS environments default to python3, standard Windows installations map the runtime binary path explicitly to python.&lt;/p&gt;

&lt;p&gt;The Fix&lt;br&gt;
I refactored the application initialization handler to evaluate the host operating system dynamically via process.platform before spinning up the background telemetry workers:&lt;/p&gt;

&lt;p&gt;TypeScript&lt;br&gt;
import { spawn } from 'child_process';&lt;br&gt;
import os from 'os';&lt;/p&gt;

&lt;p&gt;// Dynamically bridge OS path execution discrepancies&lt;br&gt;
const pythonExecutable = process.platform === 'win32' ? 'python' : 'python3';&lt;/p&gt;

&lt;p&gt;const runTelemetryWorker = () =&amp;gt; {&lt;br&gt;
  const workerProcess = spawn(pythonExecutable, ['telemetry_daemon.py'], {&lt;br&gt;
    env: { ...process.env, PYTHONUNBUFFERED: '1' }&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;workerProcess.stderr.on('data', (data) =&amp;gt; {&lt;br&gt;
    console.error(&lt;code&gt;[WORKER ERROR]: ${data.toString()}&lt;/code&gt;);&lt;br&gt;
  });&lt;br&gt;
};&lt;br&gt;
This brought cross-platform parity to the project, allowing the Node orchestrator to coordinate cleanly with the Python OpenTelemetry SDK regardless of the host OS architecture.&lt;/p&gt;

&lt;p&gt;Mistake #4: The React UI Illusion (The Dashboard That Lied)&lt;br&gt;
The biggest psychological trap during development was the fidelity of my own React application UI.&lt;/p&gt;

&lt;p&gt;Because I was using standard React state objects (useState) to pass event records locally between my components, the user interface looked like an absolute engineering marvel. Spans lit up sequentially, data tables populated flawlessly, and progress bars moved perfectly.&lt;/p&gt;

&lt;p&gt;But my frontend state was completely insulated from reality. When I purposefully pulled down my Docker instances of SigNoz, my React app still looked like it was working perfectly. The frontend was happily lying to me, masking the fact that the underlying OTLP connection was completely severed and exporting absolutely zero enterprise telemetry data.&lt;/p&gt;

&lt;p&gt;The Lesson Learned&lt;br&gt;
A healthy user interface does not mean a healthy telemetry pipeline.&lt;/p&gt;

&lt;p&gt;I fundamentally altered my testing validation loop. I decoupled my reliance on the client-side state. I wrote a dedicated integration command to hit the backend directly:&lt;/p&gt;

&lt;p&gt;Bash&lt;/p&gt;

&lt;h1&gt;
  
  
  Explicitly force clean dependency instantiation and trigger an isolated log event
&lt;/h1&gt;

&lt;p&gt;npm install&lt;br&gt;
curl -X POST &lt;a href="http://localhost:3000/api/simulate-attack" rel="noopener noreferrer"&gt;http://localhost:3000/api/simulate-attack&lt;/a&gt; -d '{"type": "brute_force"}'&lt;br&gt;
From that point forward, my source of truth wasn't my shiny React UI—it was the SigNoz Services and Traces explorer panes. If a trace didn't resolve inside SigNoz, the feature was treated as broken, regardless of how beautiful the CSS animation looked on the screen.&lt;/p&gt;

&lt;p&gt;The Ultimate Payoff: Total Transparency into AI&lt;br&gt;
Once these technical integration battles were won, the true power of an OpenTelemetry-native platform like SigNoz clicked for me.&lt;/p&gt;

&lt;p&gt;By injecting custom metadata attributes directly into the span context blocks during the Gemini LLM investigation phase, I transformed standard distributed traces into comprehensive, auditable incident records. When an alert triggers, an engineer doesn't have to guess why the AI took a specific action. They can open up SigNoz, click on the active span, and immediately inspect the exact logical reasoning parameters:&lt;/p&gt;

&lt;p&gt;incident.threat_type: Credential Stuffing&lt;/p&gt;

&lt;p&gt;agent.confidence_score: 96%&lt;/p&gt;

&lt;p&gt;agent.evidence_summary: 850 failed logins from Tor Exit Node IP detected inside a 120-second window.&lt;/p&gt;

&lt;p&gt;llm.tokens_used: 1452&lt;/p&gt;

&lt;p&gt;Plaintext&lt;br&gt;
[Insert Screenshot Here: SigNoz Trace Detail side-panel clearly rendering custom metadata attributes mapping out the agent reasoning chains and exact token costs]&lt;br&gt;
What I Learned from the Terminal&lt;br&gt;
Before this hackathon, I viewed observability as a utility you wrap around server infrastructure to check if your hard drives are full or your APIs are returning HTTP 500s.&lt;/p&gt;

&lt;p&gt;Building VigilTrace changed my perspective entirely. As we move into an era dominated by autonomous AI agents, LLM tool-calling, and complex multi-step prompt chains, observability is no longer just an infrastructure requirement—it is the core framework for AI safety and explainability.&lt;/p&gt;

&lt;p&gt;By incorporating OpenTelemetry and SigNoz from line one, I didn't just build a security system that works. I built a system that can explicitly explain why it works, when it fails, and how much it costs down to the millisecond.&lt;/p&gt;

&lt;p&gt;Technology Stack Utilized&lt;br&gt;
Frontend/Orchestration: React, TypeScript, Vite, Node.js, Express, Framer Motion, Recharts&lt;/p&gt;

&lt;p&gt;AI &amp;amp; Telemetry Core: Python, Google Gemini API, OpenTelemetry SDK, OTLP/gRPC Exporters&lt;/p&gt;

&lt;p&gt;Observability Backend: SigNoz (Self-Hosted via Docker / ClickHouse architecture)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx1bxyvi1lymv03gjepg3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx1bxyvi1lymv03gjepg3.png" alt=" " width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cybersecurity</category>
      <category>signoz</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>How to Build a Custom AI Security Agent with Coral &amp; Gemini (My First Hackathon Build!)</title>
      <dc:creator>Syed Kabeer Ali</dc:creator>
      <pubDate>Sun, 31 May 2026 13:15:17 +0000</pubDate>
      <link>https://dev.to/syed_kabeerali_65ed7d04d/how-to-build-a-custom-ai-security-agent-with-coral-gemini-my-first-hackathon-build-c27</link>
      <guid>https://dev.to/syed_kabeerali_65ed7d04d/how-to-build-a-custom-ai-security-agent-with-coral-gemini-my-first-hackathon-build-c27</guid>
      <description>&lt;p&gt;Hey everyone! I just submitted my Track 2 project for the Pirates of the Coral-bean hackathon. I built The Coral Lookout, an autonomous AI agent that scans developer blogs (like Dev.to) to flag malicious npm packages and crypto scams.&lt;/p&gt;

&lt;p&gt;Tbh, building this solo was a massive learning curve. I couldn't find a lot of tutorials on hooking up custom unmapped APIs to Coral, so I figured I’d write down exactly how I did it in case anyone else gets stuck on the same things I did.&lt;/p&gt;

&lt;p&gt;Here is how to build your own custom AI agent from scratch!&lt;/p&gt;

&lt;p&gt;The Stack&lt;br&gt;
Data Pipeline: Coral CLI&lt;/p&gt;

&lt;p&gt;LLM Engine: Gemini 2.5 Flash&lt;/p&gt;

&lt;p&gt;Frontend UI: Python &amp;amp; Streamlit&lt;/p&gt;

&lt;p&gt;Deployment: Docker + Railway&lt;/p&gt;

&lt;p&gt;Step 1: Mapping the API with Coral (The Hard Part)&lt;br&gt;
So, my initial plan was to just use Coral to query Dev.to articles. But I quickly realized that Dev.to isn't natively supported in Coral out of the box.&lt;/p&gt;

&lt;p&gt;Instead of writing a wierd python scraping script, I learned you can just build a custom YAML source connector. You basically tell Coral how to read the JSON from the API.&lt;/p&gt;

&lt;p&gt;Here is what my devto_guardian_connector.yaml looked like:&lt;/p&gt;

&lt;p&gt;YAML&lt;br&gt;
name: devto_agent&lt;br&gt;
type: rest&lt;br&gt;
base_url: "&lt;a href="https://dev.to"&gt;https://dev.to&lt;/a&gt;"&lt;br&gt;
tables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name: articles
description: Latest articles pulled from Dev.to API
request:
  method: GET
  path: /api/articles
Pro tip: Make sure your indentation is perfect here. I spent like 45 minutes wondering why my SQL queries were failing only to realize I had an extra space in my YMAL file. 😅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Step 2: Querying the Data&lt;br&gt;
Once the connector is linked, you can literally just use standard SQL to fetch internet data. In my app, I just ran a simple query to pull the titles and descriptions of the latest posts.&lt;/p&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;h1&gt;
  
  
  just standard sql, no scraping required!
&lt;/h1&gt;

&lt;p&gt;query = "SELECT title, description, url FROM devto_agent.articles LIMIT 15"&lt;br&gt;
Step 3: Adding the Brains (Gemini 2.5 Flash)&lt;br&gt;
Now that we have the raw text, we need to figure out if it's safe or if it's a scam. I used the Gemini API for this because its super fast.&lt;/p&gt;

&lt;p&gt;I passed the title and description into Gemini and asked it to act like a cybersecurity expert (or in my case, a Pirate Oracle).&lt;br&gt;
Wait, actually before you do this—make sure you load your API keys using dotenv in python, otherwise your app will crash instantly when you try to run it.&lt;/p&gt;

&lt;p&gt;I wrote a prompt telling Gemini to look for high-risk signals, like links asking you to run suspicious npm install commands or random crypto airdrops. It returns a "confidence score" and a short explanation of why it flagged it.&lt;/p&gt;

&lt;p&gt;Step 4: The Streamlit UI&lt;br&gt;
I didn't want to build a boring corporate dashboard. I wanted this to feel like a real digital first mate!&lt;/p&gt;

&lt;p&gt;I used Streamlit to build the UI. Streamlit is great, but styling it can be a pain. If you want to build a custom dark theme like I did, you have to inject CSS directly into the app using unsafe_allow_html=True.&lt;/p&gt;

&lt;p&gt;Python&lt;br&gt;
st.markdown("""&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.threat-box { border-left: 5px solid red; background-color: #1a1a1a; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;""", unsafe_allow_html=True)&lt;br&gt;
This let me create a really cool chronological timeline. When the agent finds a safe article, it logs it quietly. When it spots a threat, it flashes a red alert box and quarantines the link.&lt;/p&gt;

&lt;p&gt;Step 5: Shipping it&lt;br&gt;
Finally, I wrote a quick Dockerfile and pushed the whole thing to GitHub. I connected my repo to Railway, and it automatically built and deployed the app. (If your Railway build fails on the first try, just double check that your Streamlit port is set to 0.0.0.0 in your start script).&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
Building this agent definetly pushed me to my limits, but bridging an unstructured API to a SQL database and feeding it into an LLM is a superpower.&lt;/p&gt;

&lt;p&gt;You can check out my full code here: &lt;a href="https://github.com/MaskedMan-code/devto-guardian-agent" rel="noopener noreferrer"&gt;https://github.com/MaskedMan-code/devto-guardian-agent&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
