<?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: Kyle Keon</title>
    <description>The latest articles on DEV Community by Kyle Keon (@kylekeon).</description>
    <link>https://dev.to/kylekeon</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%2F4198854%2Fe7a109cf-d468-4014-84e7-842a1621f16b.jpg</url>
      <title>DEV Community: Kyle Keon</title>
      <link>https://dev.to/kylekeon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kylekeon"/>
    <language>en</language>
    <item>
      <title>What I Built</title>
      <dc:creator>Kyle Keon</dc:creator>
      <pubDate>Wed, 21 Oct 2026 18:44:04 +0000</pubDate>
      <link>https://dev.to/kylekeon/what-i-built-3fod</link>
      <guid>https://dev.to/kylekeon/what-i-built-3fod</guid>
      <description>&lt;p&gt;What I Built&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftjwr2pthm0ay6ndz8lj4.jpg" 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%2Ftjwr2pthm0ay6ndz8lj4.jpg" alt=" " width="800" height="1733"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;This post is my submission for&lt;/em&gt; &lt;a href="https://dev.to/deved/build-apps-with-google-ai-studio"&gt;&lt;em&gt;DEV Education Track: Build Apps with Google AI Studio&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built &lt;strong&gt;MythicCanvas&lt;/strong&gt;, an AI-powered fantasy RPG character studio using Google AI Studio and Gemini image models. It combines high-resolution fantasy portrait generation, natural-language image editing, character identity customization, D20-inspired hero generation, character sheets, and a roster gallery into one cohesive creative workspace.&lt;/p&gt;

&lt;p&gt;My goal was to move beyond a basic AI image generator and create a tool that supports the full character-creation workflow, from generating an initial hero concept to refining the portrait and organizing characters for a fantasy world or RPG campaign.&lt;/p&gt;

&lt;p&gt;Some of the core instructions guiding the build focused on creating a premium fantasy RPG studio, combining image generation with prompt-based editing, establishing a clear visual hierarchy, and making character creation feel like an integrated experience rather than a collection of disconnected tools.&lt;/p&gt;

&lt;p&gt;The application interface uses &lt;code&gt;gemini-3-pro-image-preview&lt;/code&gt; for portrait generation, with 1K, 2K, and 4K resolution options, and &lt;code&gt;gemini-nano-banana-2.1&lt;/code&gt; for prompt-driven image editing.&lt;/p&gt;

&lt;p&gt;Key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fantasy Portrait Studio:&lt;/strong&gt; Generate detailed character artwork at multiple resolutions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prompt Editor:&lt;/strong&gt; Refine existing artwork using natural-language instructions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prompt Inpainting:&lt;/strong&gt; Support targeted visual edits without treating every change as a completely new generation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Character Identity &amp;amp; Heritage:&lt;/strong&gt; Customize character concepts and attributes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;D20 Hero Generator:&lt;/strong&gt; Introduce randomized hero creation into the experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Character Sheets and Roster Gallery:&lt;/strong&gt; Provide a dedicated workflow for managing character concepts and creations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interface uses a dark fantasy aesthetic with gold accents, distinctive typography, and dedicated navigation for the different creative tools.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Try MythicCanvas in Google AI Studio:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ai.studio/apps/23da042c-ad8a-42a4-a644-17f54b49af97" rel="noopener noreferrer"&gt;https://ai.studio/apps/23da042c-ad8a-42a4-a644-17f54b49af97&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app preview showcases the MythicCanvas RPG Studio, including its Portrait Studio, Prompt Editor, Roster &amp;amp; Gallery, D20 hero-generation control, and dual-image-engine workflow.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Screenshot:&lt;/em&gt; MythicCanvas running in Google AI Studio.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience
&lt;/h2&gt;

&lt;p&gt;Building MythicCanvas reinforced an important lesson about AI development: &lt;strong&gt;the model is only one part of the application. The experience built around it is what makes the tool useful.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Image generation is exciting, but creating a character often involves multiple iterations. A user might generate a hero, adjust the appearance, refine individual details, explore alternative concepts, and keep the final result organized for later use. I wanted MythicCanvas to bring these activities together in a single environment.&lt;/p&gt;

&lt;p&gt;One of the most interesting design considerations was separating image creation from image editing. Generating a new portrait and refining an existing one are different creative tasks. Structuring the interface around both workflows provides a more natural way to explore ideas while retaining control over the creative process.&lt;/p&gt;

&lt;p&gt;I also learned to think beyond functionality when designing an AI application. Visual hierarchy, navigation, feedback, and the relationship between different tools all contribute to whether an application feels cohesive. For a fantasy-focused product, the interface itself should reinforce the creative experience rather than feel like a generic dashboard.&lt;/p&gt;

&lt;p&gt;Google AI Studio gave me a practical environment for developing the concept and working with Gemini's image capabilities. It helped me explore how generative AI could be integrated into a purpose-built application with a defined audience and workflow.&lt;/p&gt;

&lt;p&gt;The biggest takeaway is that building with AI is not simply about finding a powerful model or writing one good prompt. It is about translating an idea into a complete product experience, making deliberate design decisions, and continually refining how users interact with the underlying capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I want to continue improving MythicCanvas with a focus on character consistency across generations, more precise image editing, character-sheet usability, and a smoother workflow for managing larger character rosters.&lt;/p&gt;

&lt;p&gt;The longer-term vision is to make MythicCanvas a useful creative workspace for tabletop RPG players, game masters, indie game developers, and fantasy worldbuilders.&lt;/p&gt;

&lt;p&gt;If you're experimenting with Google AI Studio, I'd be interested in hearing how you're using Gemini to build applications that go beyond a simple chat interface.&lt;/p&gt;




&lt;p&gt;Built with Google AI Studio and Gemini image models.&lt;/p&gt;

&lt;h1&gt;
  
  
  GoogleAIStudio #Gemini #BuildWithAI #WebDev #GameDev
&lt;/h1&gt;

</description>
      <category>deved</category>
      <category>learngoogleaistudio</category>
      <category>ai</category>
      <category>gemini</category>
    </item>
    <item>
      <title>MythicCanvas: Building a Fantasy RPG Portrait Studio with Google AI Studio</title>
      <dc:creator>Kyle Keon</dc:creator>
      <pubDate>Wed, 21 Oct 2026 18:41:05 +0000</pubDate>
      <link>https://dev.to/kylekeon/mythiccanvas-building-a-fantasy-rpg-portrait-studio-with-google-ai-studio-339</link>
      <guid>https://dev.to/kylekeon/mythiccanvas-building-a-fantasy-rpg-portrait-studio-with-google-ai-studio-339</guid>
      <description>&lt;h2&gt;
  
  
  MythicCanvas: Building a Fantasy RPG Portrait Studio with Google AI Studio
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This post is my submission for &lt;a href="https://dev.to/deved/build-apps-with-google-ai-studio"&gt;DEV Education Track: Build Apps with Google AI Studio&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built &lt;strong&gt;MythicCanvas&lt;/strong&gt;, a high-fidelity fantasy portrait generator and character-design studio powered by Google's Gemini image models. The goal was to create a unified workspace where RPG players, tabletop game masters, and fantasy creators can generate original character portraits, refine them through natural-language prompts, and organize their creations into a reusable character roster.&lt;/p&gt;

&lt;p&gt;Rather than building a basic image-generation interface, I designed MythicCanvas around the character-creation workflow. The interface brings together portrait generation, prompt-based editing, character identity and heritage settings, character sheets, and a roster gallery.&lt;/p&gt;

&lt;p&gt;Key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI fantasy portrait generation:&lt;/strong&gt; Generate detailed character portraits using Gemini image generation, with 1K, 2K, and 4K resolution options.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt-based image editing:&lt;/strong&gt; Refine existing portraits using natural-language instructions, including targeted prompt-based inpainting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Character identity and heritage:&lt;/strong&gt; Build character concepts around identity and character attributes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D20-inspired randomization:&lt;/strong&gt; Roll a D20 to generate a hero concept and reroll character attributes when exploring alternatives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Character sheets and gallery:&lt;/strong&gt; Support a workflow for developing characters and keeping creations organized.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application uses &lt;code&gt;gemini-3-pro-image-preview&lt;/code&gt; for portrait generation and &lt;code&gt;gemini-nano-banana-2.1&lt;/code&gt; for prompt-driven editing, as displayed in the application interface.&lt;/p&gt;

&lt;p&gt;The central design principle was to treat AI image generation as part of a complete creative tool rather than an isolated prompt box.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Try MythicCanvas:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://ai.studio/apps/23da042c-ad8a-42a4-a644-17f54b49af97" rel="noopener noreferrer"&gt;https://ai.studio/apps/23da042c-ad8a-42a4-a644-17f54b49af97&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The preview shows the MythicCanvas RPG Studio interface, including the portrait studio, prompt editor, roster and gallery navigation, D20 hero generation, and the dual-image-engine workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience
&lt;/h2&gt;

&lt;p&gt;Working on MythicCanvas was an opportunity to explore how Google AI Studio can be used to develop a more specialized AI application around a concrete creative workflow.&lt;/p&gt;

&lt;p&gt;One of the main takeaways was the importance of designing around the user's actual process. Generating an image is only one step in character creation. Users also need to explore variations, refine specific details, maintain a consistent character concept, and organize the results. Bringing those capabilities into one interface makes the application feel more like a creative studio than a standalone AI demonstration.&lt;/p&gt;

&lt;p&gt;Another important consideration was separating the generation and editing workflows. Creating a new portrait and modifying an existing one are different tasks. Designing the application around those distinct needs provides a clearer structure for the experience and creates room for more precise creative control.&lt;/p&gt;

&lt;p&gt;I also focused on the presentation. Fantasy character creation benefits from a visual identity that feels appropriate to the subject matter. MythicCanvas uses a dark interface, gold accents, fantasy-inspired typography, and clearly differentiated tools to establish an RPG-focused aesthetic.&lt;/p&gt;

&lt;p&gt;The broader lesson for me is that building an AI application involves more than connecting a model to a user interface. The surrounding workflow, interaction design, visual hierarchy, and ability to iterate on generated results are all important parts of the product.&lt;/p&gt;

&lt;p&gt;Google AI Studio provided the environment for developing and experimenting with this concept, while Gemini's image capabilities formed the foundation of the portrait-generation and editing experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The next stage is continuing to refine the character-creation workflow, with particular attention to portrait consistency, more precise editing, character-sheet usability, and the overall experience of managing a growing roster of fantasy characters.&lt;/p&gt;

&lt;p&gt;My goal is to keep developing MythicCanvas into a practical creative tool for RPG players, tabletop campaigns, and fantasy worldbuilding.&lt;/p&gt;

&lt;p&gt;If you're building with Google AI Studio, I'd be interested in hearing how you're approaching the challenge of turning generative AI capabilities into complete, useful applications.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Google AI Studio and Gemini image models.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>deved</category>
      <category>learngoogleaistudio</category>
      <category>ai</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Python Automation, Machine Learning, or AI? A Practical Guide</title>
      <dc:creator>Kyle Keon</dc:creator>
      <pubDate>Wed, 21 Oct 2026 17:08:08 +0000</pubDate>
      <link>https://dev.to/kylekeon/python-automation-machine-learning-or-ai-a-practical-guide-3b8d</link>
      <guid>https://dev.to/kylekeon/python-automation-machine-learning-or-ai-a-practical-guide-3b8d</guid>
      <description>&lt;p&gt;Python gives you several ways to solve a problem: a deterministic script, a machine-learning model, or an AI feature that works with unstructured input. The right choice is usually the least complex approach that meets the requirement and can be checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the shape of the problem
&lt;/h2&gt;

&lt;p&gt;Ask what the software must do, what information it can use, and what happens when it is wrong. A stable rule and a fuzzy prediction are different engineering problems, even if both can be described as “using AI.”&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Need&lt;/th&gt;
&lt;th&gt;A sensible starting point&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Move, rename, validate, or transform known data&lt;/td&gt;
&lt;td&gt;Python automation&lt;/td&gt;
&lt;td&gt;The rules are explicit and results are repeatable.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apply a stable business rule&lt;/td&gt;
&lt;td&gt;Ordinary Python logic&lt;/td&gt;
&lt;td&gt;A test can describe the expected result directly.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Predict a category or value from examples&lt;/td&gt;
&lt;td&gt;Machine learning&lt;/td&gt;
&lt;td&gt;A model may help when patterns are difficult to encode as fixed rules.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Summarize or extract meaning from varied text&lt;/td&gt;
&lt;td&gt;A language model with review&lt;/td&gt;
&lt;td&gt;The input is unstructured, and outputs need evaluation and guardrails.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table is a starting point, not a substitute for requirements. A Python application can combine these approaches: validate inputs with ordinary code, call a model for one uncertain step, and keep a person in the loop when the result matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  When rules are enough
&lt;/h2&gt;

&lt;p&gt;Use a regular Python function when the rule is known and should behave the same way every time. Rules are easier to test, explain, and maintain. They are often the right answer for file processing, format checks, calculations, integrations, and workflow automation.&lt;/p&gt;

&lt;p&gt;If the rule list keeps growing because inputs vary in subtle ways, that is a signal to review the problem. More exceptions do not automatically mean machine learning is needed; the process or data may simply need clarification.&lt;/p&gt;

&lt;h2&gt;
  
  
  When machine learning may help
&lt;/h2&gt;

&lt;p&gt;Machine learning is worth evaluating when there are representative examples, a pattern to learn, and a measurable definition of success. Before training or selecting a model, check that the examples reflect real use, labels are consistent, and the evaluation data is kept separate from training data.&lt;/p&gt;

&lt;p&gt;Choose a metric that matches the cost of mistakes. In a screening workflow, for example, a false negative may matter more than a false positive. Accuracy alone can hide that difference. Review errors by category and test on new examples before relying on predictions.&lt;/p&gt;

&lt;h2&gt;
  
  
  When generative AI fits
&lt;/h2&gt;

&lt;p&gt;A language model can be useful for varied text tasks such as drafting, summarizing, or extracting candidate fields. Its output is probabilistic: the same prompt can produce different wording, and a confident answer can still be wrong.&lt;/p&gt;

&lt;p&gt;Treat generated output as a suggestion unless the task is low risk and quality has been carefully tested. Validate structure, protect sensitive data, set clear limits, and provide a review path for uncertain or consequential results. A model should not quietly make a decision that the process owner expects a person to make.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical evaluation sequence
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Define the outcome and what counts as an acceptable result.&lt;/li&gt;
&lt;li&gt;Build the smallest deterministic baseline you can measure.&lt;/li&gt;
&lt;li&gt;Collect representative examples and identify likely failure cases.&lt;/li&gt;
&lt;li&gt;Compare alternatives using the same evaluation set and cost assumptions.&lt;/li&gt;
&lt;li&gt;Decide how to handle low-confidence, invalid, or high-impact cases.&lt;/li&gt;
&lt;li&gt;Monitor behavior after release; input patterns and model performance can change.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python is useful across this process: it can prepare data, run checks, connect services, expose a web API, and automate repeatable work. The model is only one component. Good system design also accounts for privacy, latency, cost, maintenance, and a way to recover when something fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Choose Python rules when the rules are known. Evaluate machine learning when examples reveal a pattern that is difficult to express directly. Consider generative AI for genuinely unstructured tasks, with testing and human oversight appropriate to the risk. If a simple baseline solves the problem, keep the solution simple.&lt;/p&gt;




&lt;p&gt;I'm Kyle Keon, a Python developer in Pembroke, Ontario, focused on practical work across AI, workflow automation, machine learning, and web development. &lt;a href="https://kyle-keon.pages.bu.app/" rel="noopener noreferrer"&gt;Portfolio and contact&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>A Practical Python Checklist for Automating Repetitive Work</title>
      <dc:creator>Kyle Keon</dc:creator>
      <pubDate>Wed, 21 Oct 2026 17:06:36 +0000</pubDate>
      <link>https://dev.to/kylekeon/a-practical-python-checklist-for-automating-repetitive-work-hbo</link>
      <guid>https://dev.to/kylekeon/a-practical-python-checklist-for-automating-repetitive-work-hbo</guid>
      <description>&lt;p&gt;Python automation works best when it removes a repeatable step without making the process harder to trust. Before writing a script, define the input, output, rules, and what should happen when something is missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with a one-sentence specification
&lt;/h2&gt;

&lt;p&gt;Write down the job in this form: “Given &lt;strong&gt;this input&lt;/strong&gt;, produce &lt;strong&gt;this output&lt;/strong&gt;, using &lt;strong&gt;these rules&lt;/strong&gt;, and stop or report when &lt;strong&gt;this condition&lt;/strong&gt; occurs.” If those details are still changing, clarify the process before automating it.&lt;/p&gt;

&lt;p&gt;For example, a monthly contact export might need consistent names and email addresses. That is a good candidate for a small Python script if the file format and rules are stable. A workflow that includes judgment, approvals, or exceptions may need a human review step instead of full automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate reading, validation, and writing
&lt;/h2&gt;

&lt;p&gt;A reliable workflow has a few visible stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the source without changing it.&lt;/li&gt;
&lt;li&gt;Check that required fields and assumptions are present.&lt;/li&gt;
&lt;li&gt;Transform the data in memory.&lt;/li&gt;
&lt;li&gt;Write a new output only after validation succeeds.&lt;/li&gt;
&lt;li&gt;Report what happened so the result can be checked.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a small standard-library example for cleaning a CSV. Test it on a copy of the input first. It refuses to overwrite an existing output file, so a previous report is not silently replaced.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inbox/contacts.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reports/contacts_clean.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;required_columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8-sig&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;missing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;required_columns&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fieldnames&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing columns: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;cleaned_rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing email on row &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;line_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;cleaned_rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fieldnames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeheader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cleaned_rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Wrote &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cleaned_rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; rows to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example makes the rules explicit: trim whitespace, normalize email casing, and stop if a required value is missing. It does not send messages, delete source data, or make decisions about whether a contact is valid. Those boundaries are part of a safe automation design.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make reruns predictable
&lt;/h2&gt;

&lt;p&gt;A script should be safe to run again. Prefer a clearly named output, avoid accidental appends, and decide what to do if that output already exists. For tasks that update an external system, add a way to identify work already completed so a retry does not create duplicates.&lt;/p&gt;

&lt;p&gt;Also plan for failure. A useful run should make it clear which input was processed, how many records succeeded, and where an error occurred. For sensitive or business-critical tasks, add logging, alerts, access controls, and a human review before the automation performs an irreversible action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start manually, schedule later
&lt;/h2&gt;

&lt;p&gt;Run the script by hand on representative sample files. Compare its output with a known-good result and test missing columns, blank values, empty files, and existing output paths. Only after those checks should you consider a scheduler such as cron or Windows Task Scheduler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where AI fits
&lt;/h2&gt;

&lt;p&gt;Python automation is a strong fit when rules are known and repeatable. AI or machine learning may help when the input is unstructured or patterns are difficult to express as fixed rules, but it adds uncertainty. Keep a measurable baseline, test representative examples, and route uncertain or high-impact decisions to a person.&lt;/p&gt;

&lt;h2&gt;
  
  
  A short checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Is the task repeated often enough to justify automation?&lt;/li&gt;
&lt;li&gt;Are the inputs, rules, and expected outputs clearly defined?&lt;/li&gt;
&lt;li&gt;Can the script validate data before changing anything?&lt;/li&gt;
&lt;li&gt;Is rerunning safe, and are failures visible?&lt;/li&gt;
&lt;li&gt;Has the result been tested on copies before scheduling?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A small, well-scoped Python tool can be more valuable than a large system. Start with one stable task, make its behavior observable, and expand only when the first version is dependable.&lt;/p&gt;




&lt;p&gt;I'm Kyle Keon, a Python developer in Pembroke, Ontario, focused on practical work across Python, workflow automation, AI, machine learning, and web development. &lt;a href="https://kyle-keon.pages.bu.app/" rel="noopener noreferrer"&gt;Portfolio and contact&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
