<?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>Forem: Shiro Muchiri</title>
    <description>The latest articles on Forem by Shiro Muchiri (@shiro_muchiri).</description>
    <link>https://forem.com/shiro_muchiri</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3123980%2Fafd898b0-9a81-4fb2-96a6-9d0b163a28f4.jpg</url>
      <title>Forem: Shiro Muchiri</title>
      <link>https://forem.com/shiro_muchiri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/shiro_muchiri"/>
    <language>en</language>
    <item>
      <title>Real-Time ESG Risk Monitoring Workflow: Automating with n8n and Bright Data</title>
      <dc:creator>Shiro Muchiri</dc:creator>
      <pubDate>Sat, 30 Aug 2025 19:02:43 +0000</pubDate>
      <link>https://forem.com/shiro_muchiri/real-time-esg-risk-monitoring-workflow-automating-with-n8n-and-bright-data-9o0</link>
      <guid>https://forem.com/shiro_muchiri/real-time-esg-risk-monitoring-workflow-automating-with-n8n-and-bright-data-9o0</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/brightdata-n8n-2025-08-13"&gt;AI Agents Challenge powered by n8n and Bright Data&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built an &lt;strong&gt;AI-powered ESG Risk Monitoring workflow&lt;/strong&gt; that helps companies safeguard against environmental, social, and governance (ESG) risks in real-time. Instead of waiting for quarterly reports or outdated assessments, the agent continuously gathers fresh signals from Bright Data's browser API for news, public disclosures, and online sources. These insights are analyzed, prioritized by severity, and automatically delivered to decision-makers via email and Jira, ensuring leadership acts before risks escalate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;


&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/06cf42e267794a9f856abd02f61b8077"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  n8n Workflow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/shirocodes/256c67b7ea5b2e8a9283aef0d951e405" rel="noopener noreferrer"&gt;Workflow Gist&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;System Prompt&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
The system instructions were carefully designed for two AI agent roles:&lt;br&gt;
&lt;em&gt;Risk Management Agent&lt;/em&gt; – Prompted to produce structured ESG risk reports.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extracts severity levels, identifies root causes (e.g., human rights, emissions, governance issues), and suggests next steps for compliance and mitigation.&lt;/li&gt;
&lt;li&gt;Ensures consistency by always outputting in JSON format, making it easier to parse and feed into reporting dashboards.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Error Management Agent&lt;/em&gt; – Prompted to detect workflow or parsing errors.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If JSON output is missing or malformed, this agent summarizes the issue, creates a Jira ticket automatically, and alerts the team.&lt;/li&gt;
&lt;li&gt;This ensures resilience and reliability of the monitoring pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Model&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
OpenAI GPT-based chat model, optimized for structured outputs and concise reporting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Memory&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Stateless execution per monitoring cycle, ensuring each ESG assessment remains unbiased and not influenced by past runs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Tools&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Bright Data&lt;/em&gt;: Provides real-time ESG-related news and disclosures from multiple verified sources.&lt;br&gt;
&lt;em&gt;n8n:&lt;/em&gt; Orchestrates the full workflow (data extraction, AI parsing, error handling, reporting).&lt;br&gt;
&lt;em&gt;Gmail Node:&lt;/em&gt; Delivers final ESG risk summaries and alerts to stakeholders.&lt;br&gt;
&lt;em&gt;Jira Node&lt;/em&gt;: Automatically creates tickets when errors or risks exceed severity thresholds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bright Data Verified Node
&lt;/h3&gt;

&lt;p&gt;I used Bright Data’s Browser API with the Google News resource to stream real-time ESG data directly into n8n. This ensures the pipeline captures only relevant, trusted signals — no manual curation needed. For example, in the Tesla workflow, governance controversies and emissions compliance alerts were filtered and fed into the AI model instantly.&lt;/p&gt;

&lt;p&gt;By cutting through information overload and guaranteeing accuracy + timeliness, Bright Data solves the biggest challenge in ESG monitoring: enabling companies to act on risks as they happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;The biggest challenge was translating noisy real-world ESG data into actionable intelligence. By experimenting with prompt design, JSON restructuring, and multi-node orchestration in n8n, I created a flow where every risk item is parsed, scored, and sent in a boardroom-ready format.&lt;/p&gt;

&lt;h2&gt;
  
  
  THANK YOU
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>n8nbrightdatachallenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>typer.prompt() Trap: Handling Empty Inputs Gracefully</title>
      <dc:creator>Shiro Muchiri</dc:creator>
      <pubDate>Fri, 06 Jun 2025 15:19:52 +0000</pubDate>
      <link>https://forem.com/shiro_muchiri/typerprompt-trap-handling-empty-inputs-gracefully-5740</link>
      <guid>https://forem.com/shiro_muchiri/typerprompt-trap-handling-empty-inputs-gracefully-5740</guid>
      <description>&lt;p&gt;When building a command line application (CLI), developers use CLI Option Prompt &lt;a href="https://typer.tiangolo.com/tutorial/options/prompt/" rel="noopener noreferrer"&gt;[typer]&lt;/a&gt;. However, if you need more interactivity and simplicity on the terminal, you are likely to use &lt;strong&gt;typer.prompt()&lt;/strong&gt;. &lt;/p&gt;




&lt;p&gt;&lt;em&gt;Like every library in development, we have to pause and consider: How much control are we really giving up when we depend on typer.prompt() to make our CLI more interactive?&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I have been building a CLI application to better track and predict cervical cancer in women. The Typer library was great in creating visually-appealing output on the terminal, until I needed to enable a filtering option. I wanted to give my user the option of filtering health profiles based on a single ID or leave blank to provide an unfiltered output. However, in my testing, I realized that by pressing ENTER without inputting any value, typer.prompt() re-prompted me to input a value, instead of accepting an empty string. I got into a loop of prompts.&lt;/p&gt;

&lt;p&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.amazonaws.com%2Fuploads%2Farticles%2Ffqabgqshdd2ikc7bbnc3.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.amazonaws.com%2Fuploads%2Farticles%2Ffqabgqshdd2ikc7bbnc3.png" alt="prompt() causing a loop on the terminal" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Despite expecting user_id to be "", the prompt came up again!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As usual, I thought that my logic was wrong, so I went back different 'best practices' in CLI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I began by guarding user_id by changing from:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user_id = typer.prompt("Filter by user ID (or leave blank)").strip() or None
list_all_profiles(user_id=int(user_id) if user_id else None)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user_input = typer.prompt("Filter by user ID (or leave blank)").strip()
user_id = int(user_input) if user_input else None
list_all_profiles(user_id=user_id)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;After option 1 failed, I tried added isdigit() to eliminate catch non-numeric issues, but that failed, and the loop continued. &lt;/li&gt;
&lt;li&gt;Next, I wrapped the code in a try-except block with return values to prevent re-looping due to unexpected errors and value-errors, but I kept incurring an endless loop of re-prompting. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Until I came across an 8-year old Stack Overflow issue &lt;a href="https://stackoverflow.com/questions/41772624/python-click-allow-a-prompt-to-be-empty" rel="noopener noreferrer"&gt;[Stack Overflow]&lt;/a&gt; about Python's Click limit with empty prompts. While the issue had Click's syntax, I decided to replicate it on typer.prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;elif choice == '2':
            try:
                typer.secho("Leave filters blank to view all profiles.", fg=typer.colors.BRIGHT_BLACK)

                user_input = typer.prompt("Filter by user ID (or leave blank)", default="").strip()
                user_id = int(user_input) if user_input else None
                list_all_profiles(user_id=user_id)

            except ValueError:
                typer.secho("Invalid filter values. Please use numbers or leave blank.", fg=typer.colors.RED)

            except Exception as e:
                typer.secho(f"Unexpected error: {e}", fg=typer.colors.RED)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&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.amazonaws.com%2Fuploads%2Farticles%2F14940j4dkndmal89bd7c.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.amazonaws.com%2Fuploads%2Farticles%2F14940j4dkndmal89bd7c.png" alt="prompt() works best with a default" width="800" height="668"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Call to Action&lt;/strong&gt;&lt;br&gt;
Although this Prompt behavior in Typer is logical once comprehended, it is not obvious, especially for beginners. Therefore, the Prompt's interactivity would improve by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Typer providing advanced documentation on prompt() behavior in different scenarios.&lt;/li&gt;
&lt;li&gt;Providing alternatives, especially when defaults are not set. &lt;/li&gt;
&lt;li&gt;Clear warnings or handling of empty inputs in CLIs. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Are you exploring CLIs and Typer? Have you ran into this challenge and have ways of enhancing prompt()? Consider visiting and contributing to their GitHub repository &lt;a href="https://github.com/fastapi/typer" rel="noopener noreferrer"&gt;[fastApi/typer]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Like any other bug, this prompt() problem reminded me of how all libraries have simple tools that while they simplify our codes, they demand an understanding of underlying principles.&lt;/p&gt;

&lt;p&gt;I hope my journey with Typer and empty inputs saves someone and builds to the tool's best practices. &lt;/p&gt;

</description>
      <category>cli</category>
      <category>fastapi</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>When Letting go Control Meant React Taking Over: A lesson on Agile and Development</title>
      <dc:creator>Shiro Muchiri</dc:creator>
      <pubDate>Mon, 05 May 2025 02:10:24 +0000</pubDate>
      <link>https://forem.com/shiro_muchiri/when-letting-go-control-meant-react-taking-over-a-lesson-on-agile-and-development-3ik3</link>
      <guid>https://forem.com/shiro_muchiri/when-letting-go-control-meant-react-taking-over-a-lesson-on-agile-and-development-3ik3</guid>
      <description>&lt;p&gt;Alan Kay, that genius in Objected-Oriented-Programming once said that "The best way to predict the future is to invent it." That is genius, but what happens when you are in a team and need to tone down to allow other team members to express themselves? I got my answer when in one of my recent project's sprints, I choose to let someone else take the lead on a major REACT project that I was more equipped to lead. The team was under pressure due to tight timelines and the need for everyone to contribute, and I thought it would be a good opportunity to step back and give another team member some room to lead the project. After all, collaboration is key, right?&lt;/p&gt;

&lt;p&gt;Well, let's say that the river finally broke its banks and the project failed.&lt;/p&gt;

&lt;p&gt;While I was busy handling other engagements since I had completed my assigned part, someone else was busy altering everyone's code to align to their needs and the leader did not notice the issue until it was too late. By the time we did an emergency meeting, it was a maze of merge conflicts and a tangled state management that was everything but agile. Despite having made a plan before the project started, we had a rough landing that made us rethink our 'pre-flight' checklist because all we had was a chunk of spaghetti code. &lt;/p&gt;

&lt;p&gt;Project Management take aways? Trust is significant in development, but so is remaining consistently involved. Agile development principles emphasize on adaptability and the ability to iterate, but that should never be interpreted as checking out and trusting that you can adapt at any level of development. Collaborative decision-making, constructive feedback, and communication are key in enabling successful projects. If you know that you are efficient in one aspect of the project, it is important to remain present throughout the project's life cycle, even if it means coordinating with the project lead in monitoring assigned tasks. &lt;/p&gt;

&lt;p&gt;Recall Alan Kay's words? &lt;br&gt;
Often, stepping back can be great for collaboration, but ensure you are always inventing the future by directing the plane to a safe landing - because a code has a way of serving you some mashed spaghetti. 😅&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>agile</category>
      <category>react</category>
      <category>reactjsdevelopment</category>
    </item>
  </channel>
</rss>
