<?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: kohei matsunobu</title>
    <description>The latest articles on DEV Community by kohei matsunobu (@koheip).</description>
    <link>https://dev.to/koheip</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%2F4190326%2F1903be46-5d21-4631-9c60-2ad32b3a8b7b.jpg</url>
      <title>DEV Community: kohei matsunobu</title>
      <link>https://dev.to/koheip</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/koheip"/>
    <language>en</language>
    <item>
      <title>Eliminating Accidental Submissions in Kaggle Work: The Kaggle CLI, a Confirmation Wrapper, and Measuring on Production Hardware</title>
      <dc:creator>kohei matsunobu</dc:creator>
      <pubDate>Sat, 17 Oct 2026 10:56:10 +0000</pubDate>
      <link>https://dev.to/koheip/eliminating-accidental-submissions-in-kaggle-work-the-kaggle-cli-a-confirmation-wrapper-and-2a82</link>
      <guid>https://dev.to/koheip/eliminating-accidental-submissions-in-kaggle-work-the-kaggle-cli-a-confirmation-wrapper-and-2a82</guid>
      <description>&lt;p&gt;&lt;em&gt;This article was originally published in Japanese on &lt;a href="https://zenn.dev/koheip/articles/kaggle-safe-submit-workflow" rel="noopener noreferrer"&gt;Zenn&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I've been working on Kaggle with help from LLM agents and scripts. Automation makes things easier, but it also nearly caused accidents, like the workflow going all the way to submission without anyone checking.&lt;/p&gt;

&lt;p&gt;In this article, I'll cover how to work with notebooks using the Kaggle CLI, a wrapper that always puts a human confirmation step in the loop, and what I learned from the differences between my validation environment and the production environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Checking notebook status with the Kaggle CLI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up the token
&lt;/h3&gt;

&lt;p&gt;With the newer token method, you put your token in the &lt;code&gt;KAGGLE_API_TOKEN&lt;/code&gt; environment variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;KAGGLE_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"(your token issued by Kaggle)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Getting notebook status and output
&lt;/h3&gt;

&lt;p&gt;You can check the status of a notebook running on Kaggle and fetch its output from the CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check whether it's running, finished, or failed&lt;/span&gt;
kaggle kernels status &amp;lt;username&amp;gt;/&amp;lt;notebook-name&amp;gt;

&lt;span class="c"&gt;# Download the output files locally&lt;/span&gt;
kaggle kernels output &amp;lt;username&amp;gt;/&amp;lt;notebook-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since you can see the status without opening a browser, it's much easier to handle from scripts and agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. A confirmation wrapper to prevent accidental submissions
&lt;/h2&gt;

&lt;p&gt;I once had an automated batch go all the way to submission without any confirmation. Submissions are often limited in number, and they can't be undone.&lt;/p&gt;

&lt;p&gt;So I built a wrapper that splits the path to submission into these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Show which file will be submitted&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confirm with y/N&lt;/strong&gt; (pressing just Enter means "No")&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run it&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate the output&lt;/strong&gt; (whether the file exists, whether the format is correct, etc.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only display the submit command and stop there&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the final submission, a human runs the displayed command themselves. This way, even if something breaks somewhere in the automation, a human always takes a look right before submission.&lt;/p&gt;

&lt;p&gt;The confirmation part can be written in Python in just a few lines, for example:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; [y/N]: &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;return&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&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="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run with this file?&lt;/span&gt;&lt;span class="sh"&gt;"&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;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Aborted&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 key is making "No" the default. Even when it's called from an agent or script with no input, it won't proceed on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Measure time-limited workloads on the same hardware as production
&lt;/h2&gt;

&lt;p&gt;When I was doing local validation on a fast GPU, the trends in the results sometimes differed from those on the slower GPU used in production.&lt;/p&gt;

&lt;p&gt;When a workload has a time limit, slower hardware alone can cause it to be cut off partway, or change what you can get done within the limit. Just because something "fits in time" on a fast environment doesn't mean it will in production.&lt;/p&gt;

&lt;p&gt;I learned that for time-limited workloads, it's important to &lt;strong&gt;measure on the same hardware as production&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Once you set &lt;code&gt;KAGGLE_API_TOKEN&lt;/code&gt;, the Kaggle CLI lets you track your notebooks with &lt;code&gt;kernels status&lt;/code&gt; and &lt;code&gt;kernels output&lt;/code&gt;, no browser needed&lt;/li&gt;
&lt;li&gt;Even with automation, always put a human confirmation step right before submission (default to "No", and only display the submit command)&lt;/li&gt;
&lt;li&gt;Measure time-limited workloads on the same hardware as production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more I automate, the more I feel it's important to decide up front "where a human steps in to stop things."&lt;/p&gt;

</description>
      <category>kaggle</category>
      <category>python</category>
      <category>cli</category>
      <category>automation</category>
    </item>
    <item>
      <title>I Stopped Feeding Whole Jupyter Notebooks to LLMs and Cut Tokens by Over 95% (Claude Code / Codex CLI / PowerShell)</title>
      <dc:creator>kohei matsunobu</dc:creator>
      <pubDate>Sat, 17 Oct 2026 10:56:09 +0000</pubDate>
      <link>https://dev.to/koheip/i-stopped-feeding-whole-jupyter-notebooks-to-llms-and-cut-tokens-by-over-95-claude-code-codex-2ljh</link>
      <guid>https://dev.to/koheip/i-stopped-feeding-whole-jupyter-notebooks-to-llms-and-cut-tokens-by-over-95-claude-code-codex-2ljh</guid>
      <description>&lt;p&gt;&lt;em&gt;This article was originally published in Japanese on &lt;a href="https://qiita.com/koheip/items/9cd92a31e747e019da0b" rel="noopener noreferrer"&gt;Qiita&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When I work on Kaggle, I write code in Jupyter notebooks and ask Claude Code or Codex CLI for reviews and advice along the way. The problem: passing a whole notebook to an LLM came to &lt;strong&gt;about 30k tokens per notebook&lt;/strong&gt;, and after asking a few times, the cost added up fast.&lt;/p&gt;

&lt;p&gt;In this article, I'll share the tricks I used to save tokens, plus the gotchas I hit when calling these CLIs from Windows PowerShell.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Pass only the "code cell diff" of the notebook
&lt;/h2&gt;

&lt;p&gt;An .ipynb file is JSON under the hood, and it's packed with cell outputs (logs and images) and metadata. In most cases, the code is all I actually want the LLM to look at, so I wrote a script that does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drops outputs and metadata, and extracts only the code cells&lt;/li&gt;
&lt;li&gt;Outputs &lt;strong&gt;only the diff&lt;/strong&gt; against the previous version&lt;/li&gt;
&lt;li&gt;Replaces long lines over 300 characters with their "length" and a "hash" (all I need to know is whether the content changed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this, comparing versions fits in &lt;strong&gt;about 1–1.6k tokens (a reduction of over 95%)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Also, long prompt strings inside a notebook make it hard to read, so I create a "reading view" where those strings are split out into separate .txt files. The notebook I actually run stays as a single file, and I pass the reading view to the LLM or for reviews. That's how I keep the two roles separate.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Calling Claude Code / Codex CLI as commands from another program
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Claude Code
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;claude -p&lt;/code&gt;, you can ask a single question and get an answer back without opening the interactive UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nt"&gt;--max-turns&lt;/span&gt; 1 &lt;span class="nt"&gt;--disallowedTools&lt;/span&gt; &lt;span class="s2"&gt;"Bash,Read,..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key is to &lt;strong&gt;disallow tools like file reading and pass only the summary you've prepared yourself&lt;/strong&gt;. Since it won't go off and read files in your repository on its own, token usage stays cheap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Codex CLI
&lt;/h3&gt;

&lt;p&gt;I installed it with npm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @openai/codex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When logging in through the browser failed, authenticating with a URL and a code worked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex login &lt;span class="nt"&gt;--device-auth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I pass the question via standard input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Your question here"&lt;/span&gt; | codex &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--skip-git-repo-check&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Japanese text gets garbled in Windows PowerShell
&lt;/h2&gt;

&lt;p&gt;When I piped a Japanese prompt from PowerShell into the CLI, the text came out garbled (mojibake). Setting the following three to UTF-8 fixes it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;InputEncoding&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;System.Text.Encoding&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="nx"&gt;OutputEncoding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;System.Text.Encoding&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$OutputEncoding&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;System.Text.Encoding&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, PowerShell doesn't let you chain commands with &lt;code&gt;&amp;amp;&lt;/code&gt; the way cmd does; you get an &lt;code&gt;AmpersandNotAllowed&lt;/code&gt; error. If you write commands with a cmd mindset, this will trip you up, so watch out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Instead of passing the whole notebook, passing only the code cell diff cut tokens by over 95%&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;claude -p&lt;/code&gt;, disallowing tools and passing only a summary keeps it cheap&lt;/li&gt;
&lt;li&gt;If Codex CLI login fails, try &lt;code&gt;codex login --device-auth&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;When passing Japanese text in PowerShell, set the three encodings to UTF-8&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this helps anyone else who's going back and forth between LLMs and notebooks like I am.&lt;/p&gt;

</description>
      <category>python</category>
      <category>jupyter</category>
      <category>llm</category>
      <category>powershell</category>
    </item>
  </channel>
</rss>
