<?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: AI Sensei LAB</title>
    <description>The latest articles on DEV Community by AI Sensei LAB (@crypteasensei).</description>
    <link>https://dev.to/crypteasensei</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%2F4193525%2F7453679d-636a-4acc-a23e-f13b98d5f9c3.jpg</url>
      <title>DEV Community: AI Sensei LAB</title>
      <link>https://dev.to/crypteasensei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crypteasensei"/>
    <language>en</language>
    <item>
      <title>Gemini Gems to Skills: What Changes in November 2026 and How to Move Your Gems Now</title>
      <dc:creator>AI Sensei LAB</dc:creator>
      <pubDate>Tue, 20 Oct 2026 01:10:26 +0000</pubDate>
      <link>https://dev.to/crypteasensei/gemini-gems-to-skills-what-changes-in-november-2026-and-how-to-move-your-gems-now-1di1</link>
      <guid>https://dev.to/crypteasensei/gemini-gems-to-skills-what-changes-in-november-2026-and-how-to-move-your-gems-now-1di1</guid>
      <description>&lt;p&gt;&lt;em&gt;Google's official timeline by account type, what doesn't carry over yet, and the steps to recreate a Gem as a skill before the switch.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: this article was drafted and edited with AI tools.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you've built Gems in Gemini (a writing coach, a meeting-notes formatter, a study helper), Google is replacing them with &lt;strong&gt;skills&lt;/strong&gt;. You may have read that your Gems disappear in November, or that nothing changes until 2027. Both can be true, because Google's dates depend on the type of account you use.&lt;/p&gt;

&lt;p&gt;This guide sets out what Google's own help pages say, what won't come across to skills yet, and how to move a Gem yourself if you don't want to wait for the automatic migration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How this guide was made:&lt;/strong&gt; every date and step below comes from Google's official Gemini and Workspace help pages and the Workspace Updates blog, checked on October 19, 2026. The steps were not tried hands-on. Google is still updating these pages, and says it will publish full migration details later, so check the linked pages before acting on a date.&lt;/p&gt;




&lt;h2&gt;
  
  
  The timeline, by account type
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Personal Google accounts.&lt;/strong&gt; Google's Gemini Help page says Gems will "transition to skills" starting in &lt;strong&gt;November 2026&lt;/strong&gt;, and lists &lt;strong&gt;November 2026&lt;/strong&gt; as when Gems go away for personal accounts. It doesn't give an exact day. Opal and Gems by Google Labs also go away in November.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Work accounts&lt;/strong&gt; (Workspace business, enterprise and non-profit). Google's admin help page gives this sequence:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;October 13, 2026&lt;/td&gt;
&lt;td&gt;Skills start rolling out in the Gemini app. Gems and skills can both be created and used.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;November 17, 2026&lt;/td&gt;
&lt;td&gt;Gems move to Settings in the Gemini app. Users can still create, edit and use them.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No sooner than March 1, 2027&lt;/td&gt;
&lt;td&gt;Gems can no longer be created, edited or used. Remaining Gems migrate automatically to draft skills. Workspace Studio flows with an "Ask a Gem" step stop working.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;School accounts&lt;/strong&gt; (Workspace for Education). The same steps happen &lt;strong&gt;no sooner than June 1, 2027&lt;/strong&gt;, including Gems in Google Classroom and in learning systems connected through Gemini LTI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So what is November 17?&lt;/strong&gt; On Google's admin timeline, it's the day Gems &lt;em&gt;move to Settings&lt;/em&gt;. It is not the day they stop working for work and school accounts. For personal accounts, Google's consumer page says only "November 2026." If you use a personal account, plan as if your Gems could change at any point in November.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rollout status (October 19, 2026):&lt;/strong&gt; Google's Workspace Updates blog says skills in the Gemini app began rolling out on October 13, 2026, with completion expected by mid-November. Skills &lt;em&gt;inside Workspace apps&lt;/em&gt; are "Delayed until further notice." If you don't see Skills yet, your account may not have it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wait for the automatic migration, or move now?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If you wait,&lt;/strong&gt; Google says it will automatically recreate your Gems as skills when Gems are removed. According to the admin help page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your content comes across.&lt;/strong&gt; Migrated skills keep their original names, descriptions, custom instructions and uploaded knowledge files ("supported files," in the consumer page's words).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They arrive switched off.&lt;/strong&gt; They appear as &lt;strong&gt;inactive drafts&lt;/strong&gt;, and you must review and activate each one before you can use or share it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharing settings follow.&lt;/strong&gt; Drive permissions and sharing settings on a Gem transfer to its skill.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Details are still coming.&lt;/strong&gt; Google says it will publish full migration details at least 30 days before automated migration starts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you move now,&lt;/strong&gt; you control the result and can check it works before your Gem goes away. Google's admin page recommends this for important Gems: "manually rebuild their critical Gems as skills early."&lt;/p&gt;

&lt;p&gt;A reasonable middle path is to move the one or two Gems you rely on most now, and let the automatic migration handle the rest. Either way, you'll need to review each migrated skill.&lt;/p&gt;




&lt;h2&gt;
  
  
  What doesn't carry over yet
&lt;/h2&gt;

&lt;p&gt;Check these before you depend on a converted skill. The first three points come from Google's Gemini Help page, and the last two from Google's Workspace admin help page (both checked October 19, 2026):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Some built-in tools don't work with skills yet.&lt;/strong&gt; Google says "most default tools that are available in Gems do not work with skills, including":

&lt;ul&gt;
&lt;li&gt;Create video&lt;/li&gt;
&lt;li&gt;Create music&lt;/li&gt;
&lt;li&gt;Canvas&lt;/li&gt;
&lt;li&gt;Deep research&lt;/li&gt;
&lt;li&gt;Guided learning&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub files&lt;/strong&gt; aren't supported in skills "for now."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharing skills and adding files from Google Drive&lt;/strong&gt; are promised "in the coming weeks." Until then, you can't share a skill the way you shared a Gem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills don't sync&lt;/strong&gt; between the Gemini app and Workspace apps. Gems used in Workspace must be recreated manually in Google Workspace Studio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workspace Studio flows&lt;/strong&gt; can no longer add new "Ask a Gem" steps. Existing flows keep working until the 2027 cut-off, but need rebuilding before then.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If one of your Gems depends on Canvas or Deep Research, keep using it as a Gem while you still can, and recheck Google's page before your account's deadline.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before you start: a quick inventory
&lt;/h2&gt;

&lt;p&gt;For each Gem, note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Its name, description and full instructions (copy them into a document as a backup)&lt;/li&gt;
&lt;li&gt;[ ] Any &lt;strong&gt;knowledge files&lt;/strong&gt; attached&lt;/li&gt;
&lt;li&gt;[ ] Whether it relies on &lt;strong&gt;Canvas, Deep Research, video, music or Guided learning&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Whether you've &lt;strong&gt;shared&lt;/strong&gt; it with anyone&lt;/li&gt;
&lt;li&gt;[ ] Whether it's used in a &lt;strong&gt;Workspace Studio flow&lt;/strong&gt; (work and school accounts)&lt;/li&gt;
&lt;li&gt;[ ] How often you use it (move the most-used first)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to recreate a Gem as a skill (Google's steps)
&lt;/h2&gt;

&lt;p&gt;Google's Gemini Help page describes three steps, on a computer at gemini.google.com.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Save the Gem's knowledge files
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;gemini.google.com&lt;/strong&gt;, open the sidebar and select &lt;strong&gt;Gems&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Edit&lt;/strong&gt; next to the Gem you want to move.&lt;/li&gt;
&lt;li&gt;If it has files under &lt;strong&gt;Knowledge&lt;/strong&gt;, open each one and click &lt;strong&gt;Download&lt;/strong&gt;. Files have to be downloaded one at a time.&lt;/li&gt;
&lt;li&gt;Create a folder named the way the skill will be named: &lt;strong&gt;all lowercase with hyphens&lt;/strong&gt;, for example &lt;code&gt;sample-skill-name&lt;/code&gt;. Move the downloaded files into it.&lt;/li&gt;
&lt;li&gt;Keep the Gem's tab open.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Create the skill and copy the Gem's details
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open gemini.google.com in a new tab.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Skills&lt;/strong&gt; page. Google's transition article says &lt;strong&gt;Settings → Skills&lt;/strong&gt;, while its skills help page says &lt;strong&gt;Customize → Skills&lt;/strong&gt;. Use whichever your account shows.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create manually&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Copy the Gem's &lt;strong&gt;name, description and instructions&lt;/strong&gt; into the skill. Google says the name is reformatted automatically.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the Gem had no knowledge files, you're done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Add the files (only if the Gem had them)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;On the Skills page, hover over the new skill and choose &lt;strong&gt;Download&lt;/strong&gt; from its actions menu. You get a &lt;code&gt;.zip&lt;/code&gt; file containing a &lt;code&gt;SKILL.md&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Unzip it and move &lt;code&gt;SKILL.md&lt;/code&gt; into the folder with your Gem's files.&lt;/li&gt;
&lt;li&gt;Back on the Skills page, choose &lt;strong&gt;Replace skill&lt;/strong&gt; for the same skill.&lt;/li&gt;
&lt;li&gt;Upload the &lt;strong&gt;folder&lt;/strong&gt;. Google notes that the folder name must match the skill name.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Google says uploading files to create skills currently works only in the Gemini web app and the Gemini app on Mac.&lt;/p&gt;




&lt;h2&gt;
  
  
  Make the converted skill work like a skill
&lt;/h2&gt;

&lt;p&gt;Copying a Gem's instructions across gets you a working skill, but a Gem and a skill are triggered differently. You opened a Gem deliberately. Gemini can use a skill &lt;strong&gt;automatically&lt;/strong&gt; when a request matches it, and you can also call one in a chat by typing &lt;code&gt;/&lt;/code&gt; (Google says this will become &lt;code&gt;@&lt;/code&gt;) and its name.&lt;/p&gt;

&lt;p&gt;That makes the skill's &lt;strong&gt;name and description&lt;/strong&gt; more important than they were for your Gem. Google's guidance on writing skills says:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; start with a verb and avoid vague words like "helper." Google's example is &lt;code&gt;plan-meal-from-recipe&lt;/code&gt; instead of &lt;code&gt;recipe-data&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description:&lt;/strong&gt; write it in the third person and include "Use when…" with specific situations. Google gives a 1,024-character limit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instructions:&lt;/strong&gt; keep them short, "cheat sheets, not manuals." Add a "common mistakes" section, and say what Gemini should do when information is missing instead of guessing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example: a Gem for newsletter editing, rewritten as a skill&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before (a typical Gem description):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Newsletter helper. Helps me with my newsletter.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;edit-newsletter-drafts&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Edits weekly newsletter drafts for clarity, length and a friendly tone, and suggests three subject lines. Use when reviewing a newsletter draft or preparing a newsletter to send.&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Edit newsletter drafts&lt;/span&gt;

&lt;span class="gu"&gt;## Steps&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Read the whole draft. Summarize its main point in one sentence.
&lt;span class="p"&gt;2.&lt;/span&gt; Cut repetition and trim the draft to about 400 words unless told otherwise.
&lt;span class="p"&gt;3.&lt;/span&gt; Keep the writer's voice: friendly, plain English, short paragraphs.
&lt;span class="p"&gt;4.&lt;/span&gt; Suggest three subject lines under 50 characters.

&lt;span class="gu"&gt;## Output&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Edited draft
&lt;span class="p"&gt;-&lt;/span&gt; Three subject lines
&lt;span class="p"&gt;-&lt;/span&gt; A short list of changes you made

&lt;span class="gu"&gt;## Common mistakes to avoid&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Adding facts, links or offers that aren't in the draft
&lt;span class="p"&gt;-&lt;/span&gt; Changing names, dates or prices

If the draft has no clear main point, ask what it should be instead of guessing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The instructions are only an illustration; use your own Gem's content. The pattern to copy: a verb-first name, a description that says &lt;em&gt;what&lt;/em&gt; and &lt;em&gt;when&lt;/em&gt;, short steps, an output format and a mistakes list.&lt;/p&gt;




&lt;h2&gt;
  
  
  Managing your skills after the move
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Only active skills are used automatically.&lt;/strong&gt; Turn a skill off or on from the Skills page. Google says you can create as many skills as you like, but &lt;strong&gt;only 100 can be active at a time&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Updating files&lt;/strong&gt; means re-uploading the whole skill with its files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deleting a skill can't be undone.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Requirements:&lt;/strong&gt; Google's skills help page says you must be 18 or over, signed in, with Keep Activity on. Skills work on the Gemini web app, mobile app and Mac app, and &lt;strong&gt;don't require a Google AI subscription&lt;/strong&gt;. Google's admin page says skills in the Gemini app are for "users of all ages," and its transition article says "over 18," so the age rule may still be settling.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  For work and school accounts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gems keep working into 2027&lt;/strong&gt; (March 1 for business, June 1 for education, both "no sooner than"). But Google recommends that admins tell users the dates and rebuild critical Gems early.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workspace Studio:&lt;/strong&gt; replace "Ask a Gem" steps before the cut-off. Google points flow owners to its Workspace Studio transition guide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills inside Workspace apps&lt;/strong&gt; are delayed until further notice (Workspace Updates, October 13, 2026). Plan around the Gemini app for now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Education:&lt;/strong&gt; for Classroom and Gemini LTI, Google recommends moving to Gemini Notebook, with Guided Learning "coming soon to Classroom."&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Assuming November 17 is the personal-account deadline.&lt;/strong&gt; Google's consumer page says only "November 2026."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not backing up your Gem's instructions.&lt;/strong&gt; Copy them into a document now, even if you plan to wait.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting that migrated skills arrive switched off.&lt;/strong&gt; You'll need to review and activate each one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Moving a Gem that depends on Canvas or Deep Research&lt;/strong&gt; and expecting the same behavior. Those tools don't work with skills yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keeping a vague Gem-style description.&lt;/strong&gt; Skills are chosen by their description, so rewrite it with "Use when…".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uploading Word or Excel knowledge files.&lt;/strong&gt; Gemini's skills page lists binary formats like .docx and .xlsx as unsupported. Text files, PDFs and images are accepted, so saving a Word file as a PDF or plain text first is the simple fix (our suggestion, not a Google instruction).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Will I lose my Gems?&lt;/strong&gt;&lt;br&gt;
Google says it will automatically recreate them as skills when Gems are removed. They'll arrive as inactive drafts you need to review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need a paid plan for skills?&lt;/strong&gt;&lt;br&gt;
No. Google's help page says skills are available without a Google AI subscription.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use the converted skill outside Gemini?&lt;/strong&gt;&lt;br&gt;
Google says skills use the open &lt;code&gt;SKILL.md&lt;/code&gt; format, "without platform lock-in." Other apps have their own upload rules. The article "How to Create a Claude Skill You Can Reuse in ChatGPT and Gemini" covers them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if I don't see Skills yet?&lt;/strong&gt;&lt;br&gt;
The Gemini app rollout runs until mid-November 2026, according to Google. Check again later, and make sure you meet the requirements above.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The safest plan is simple. Back up every Gem's instructions now, move the few you depend on, and rewrite their descriptions so Gemini knows when to use them. Then check Google's pages again in November for the exact dates and migration details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;All checked on October 19, 2026.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://support.google.com/gemini/answer/18560919?hl=en" rel="noopener noreferrer"&gt;Gemini Help — About the transition from Gems to skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://knowledge.workspace.google.com/admin/generative-ai/gemini-app/about-the-transition-to-skills" rel="noopener noreferrer"&gt;Google Workspace Admin Help — About the transition from Gems to skills&lt;/a&gt; (its Workspace skills rollout dates are older than the Workspace Updates post below)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://workspaceupdates.googleblog.com/2026/10/an-update-on-launch-of-skills-in-gemini-app-and-workspace.html?hl=en" rel="noopener noreferrer"&gt;Google Workspace Updates (2026-10-13)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.google.com/gemini/answer/17094296" rel="noopener noreferrer"&gt;Gemini Help — Create &amp;amp; manage skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.google.com/gemini/answer/17102773" rel="noopener noreferrer"&gt;Gemini Help — Write effective skills&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>abotwrotethis</category>
      <category>ai</category>
      <category>gemini</category>
      <category>productivity</category>
    </item>
    <item>
      <title>n8n AI Agent Tutorial (2026): The New Agents Feature vs the AI Agent Node, on Free Self-Hosted n8n</title>
      <dc:creator>AI Sensei LAB</dc:creator>
      <pubDate>Mon, 19 Oct 2026 22:32:47 +0000</pubDate>
      <link>https://dev.to/crypteasensei/n8n-ai-agent-tutorial-2026-the-new-agents-feature-vs-the-ai-agent-node-on-free-self-hosted-n8n-22ce</link>
      <guid>https://dev.to/crypteasensei/n8n-ai-agent-tutorial-2026-the-new-agents-feature-vs-the-ai-agent-node-on-free-self-hosted-n8n-22ce</guid>
      <description>&lt;p&gt;&lt;em&gt;This n8n AI agent tutorial builds the same small chat agent two ways on free, self-hosted n8n: with the AI Agent workflow node, and with the newer Agents feature (in Preview). You'll learn what each one needs, how to run both with a free local model, and what went wrong in a real test.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: this article was drafted and edited with AI tools (#abotwrotethis). Everything under "What happened" was run on October 20, 2026, on n8n 2.43.8 (Community edition) with a local model. The setup was driven through n8n's REST API, not by clicking in the editor, so editor button and menu names in this article come from n8n's docs and weren't checked on screen. No paid model or API key was used.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;n8n now has two ways to build an AI agent. Most tutorials show the &lt;strong&gt;AI Agent node&lt;/strong&gt; inside a workflow. Newer versions also include &lt;strong&gt;Agents&lt;/strong&gt;, which you build in an &lt;strong&gt;Agent Builder&lt;/strong&gt; instead of on the workflow canvas. Both ran on the free Community edition in this test. They're designed for different jobs.&lt;/p&gt;




&lt;h2&gt;
  
  
  The two approaches, in n8n's words
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The AI Agent node&lt;/strong&gt; is a workflow node. n8n's docs say: "Connect a chat model and one or more tools, and the agent decides which tools to call to complete a task." It also says: "You must connect at least one tool sub-node to an AI Agent node." The older v1 of the node, which had an agent-type setting, "will be removed from n8n 3.0", so update old workflows to the current version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agents&lt;/strong&gt; are separate from workflows. n8n's docs call an agent "an autonomous assistant you build in n8n" with a model, instructions, and capabilities like tools, skills and a knowledge base, and say to use an agent "when work is too open-ended for a fixed workflow". Key points from the "Build and manage agents" page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Self-hosted availability: "All plans from n8n 2.32.3".&lt;/li&gt;
&lt;li&gt;"Agents are in Preview. They can make mistakes, and their behavior may change while the feature is in development."&lt;/li&gt;
&lt;li&gt;"Agents are on by default on all plans". An owner or admin can switch them off in Settings &amp;gt; Agents, and that setting "doesn't affect the AI Agent workflow node."&lt;/li&gt;
&lt;li&gt;"Queue mode isn't supported for agents yet". Run agents in regular mode.&lt;/li&gt;
&lt;li&gt;"One turn with an agent counts as one execution."&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;AI Agent node&lt;/th&gt;
&lt;th&gt;Agents (Preview)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where you build it&lt;/td&gt;
&lt;td&gt;Workflow canvas&lt;/td&gt;
&lt;td&gt;Agent Builder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;td&gt;A chat model sub-node&lt;/td&gt;
&lt;td&gt;Provider + model chosen in the agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tools&lt;/td&gt;
&lt;td&gt;Tool sub-nodes (at least one required)&lt;/td&gt;
&lt;td&gt;Built-in integrations, workflows, custom tools, MCP servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory&lt;/td&gt;
&lt;td&gt;A memory sub-node (for example Simple Memory)&lt;/td&gt;
&lt;td&gt;Session memory on by default; episodic memory needs an OpenAI credential&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Knowledge base&lt;/td&gt;
&lt;td&gt;Build it yourself in the workflow&lt;/td&gt;
&lt;td&gt;Knowledge tab; on self-hosted it needs a Daytona sandbox (Preview)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reach it from&lt;/td&gt;
&lt;td&gt;Whatever triggers the workflow&lt;/td&gt;
&lt;td&gt;Chat panel, Slack, Telegram, Linear, schedules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status&lt;/td&gt;
&lt;td&gt;No Preview label in its docs&lt;/td&gt;
&lt;td&gt;Preview&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use the node when the AI step sits inside a fixed process. Try an Agent when people need to chat with an assistant that picks its own tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  Free setup: what was run
&lt;/h2&gt;

&lt;p&gt;n8n's "Compare editions" page says the Community edition "is what n8n runs without a license key" and includes "almost the complete feature set". It lacks things like projects, sharing, SSO, environments and Git version control.&lt;/p&gt;

&lt;p&gt;The test machine had no Docker, so n8n was installed from npm. The npm package for n8n 2.43.8 declares &lt;code&gt;"node": "&amp;gt;=24.0.0"&lt;/code&gt;, so Node.js 24 was needed (the test machine's Node 20 didn't meet it):&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;mkdir &lt;/span&gt;n8n-test &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;n8n-test
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;n8n@2.43.8
npx n8n start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The startup log ended with &lt;code&gt;Version: 2.43.8&lt;/code&gt; and &lt;code&gt;Editor is now accessible via: http://localhost:5678&lt;/code&gt;. It also printed: "Running n8n outside a container is deprecated. Future versions will require running n8n via the official Docker image." If you have Docker, use n8n's official image instead.&lt;/p&gt;

&lt;p&gt;After creating the owner account, the instance's settings API reported plan name "Community", and the Agents settings endpoint returned &lt;code&gt;enabled: true&lt;/code&gt;. No registration or license key was needed for Agents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A free model.&lt;/strong&gt; Both builds used a local model through Ollama: Qwen2.5-1.5B-Instruct, a small model that runs on a CPU. That keeps the test free, but a 1.5B model is weak, and you'll see that below. Larger local models or a free API tier may do much better; neither was tested here.&lt;/p&gt;




&lt;h2&gt;
  
  
  Build 1: AI Agent node + Chat Trigger + memory + one tool
&lt;/h2&gt;

&lt;p&gt;The workflow has five nodes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Chat Trigger&lt;/strong&gt; ("When chat message received"), set to public so it can be called over HTTP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Agent&lt;/strong&gt; (version 3.1 in this install), with a system message: "You are a helpful assistant. For any arithmetic, always use the calculator tool and report its result."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ollama Chat Model&lt;/strong&gt; sub-node, using an Ollama credential with base URL &lt;code&gt;http://127.0.0.1:11434&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple Memory&lt;/strong&gt; sub-node, default settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calculator&lt;/strong&gt; tool sub-node: a read-only tool, which makes it safe for a first test.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the workflow JSON used in the test, with the credential reference removed. It was created through the REST API; after importing it, select your own Ollama credential on the model node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Build 1 - AI Agent node (local Ollama)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"When chat message received"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@n8n/n8n-nodes-langchain.chatTrigger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AI Agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@n8n/n8n-nodes-langchain.agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"systemMessage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"You are a helpful assistant. For any arithmetic, always use the calculator tool and report its result."&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ollama Chat Model"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@n8n/n8n-nodes-langchain.lmChatOllama"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"qwen2.5-1.5b-local"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Simple Memory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@n8n/n8n-nodes-langchain.memoryBufferWindow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Calculator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@n8n/n8n-nodes-langchain.toolCalculator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"connections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"When chat message received"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AI Agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Ollama Chat Model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ai_languageModel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AI Agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ai_languageModel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Simple Memory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ai_memory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AI Agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ai_memory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Calculator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ai_tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AI Agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ai_tool"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"executionOrder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"v1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What happened
&lt;/h3&gt;

&lt;p&gt;After publishing the workflow, two messages went to the chat endpoint in the same session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; What is 1234 * 56? Use the calculator.
{"output":"The result of 1234 * 56 is 69,104."}

&amp;gt; Now divide that result by 8.
{"output":"The result of 69,104 / 8 is 8,638."}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both answers are correct. The execution data for the second run shows the Calculator received &lt;code&gt;69104 / 8&lt;/code&gt;, so the agent used the tool, and Simple Memory carried "that result" over from the first message. Each reply took about 2 to 3 seconds on CPU.&lt;/p&gt;




&lt;h2&gt;
  
  
  Build 2: the same assistant as an Agent
&lt;/h2&gt;

&lt;p&gt;n8n's docs describe the Agent Builder flow in the editor: select your project from the left menu, go to the &lt;strong&gt;Agents&lt;/strong&gt; tab, select &lt;strong&gt;Create Agent&lt;/strong&gt;, name the agent, pick a provider and model in the &lt;strong&gt;Model&lt;/strong&gt; field, write &lt;strong&gt;Instructions&lt;/strong&gt;, and add tools or skills. Selecting &lt;strong&gt;Preview&lt;/strong&gt; in the header tests the draft "without publishing". This test made the same steps through the REST API, so these labels weren't seen on screen.&lt;/p&gt;

&lt;p&gt;Through the API, the agent was created in the owner's personal project (the Community edition doesn't include the Projects feature, per "Compare editions"). Before any setup, n8n's validation listed three missing items: instructions, model, and credential.&lt;/p&gt;

&lt;h3&gt;
  
  
  The model problem
&lt;/h3&gt;

&lt;p&gt;The Agents model catalog that the API returned on this instance had 16 provider IDs: &lt;code&gt;openai&lt;/code&gt;, &lt;code&gt;anthropic&lt;/code&gt;, &lt;code&gt;google&lt;/code&gt;, &lt;code&gt;azure-openai&lt;/code&gt;, &lt;code&gt;aws-bedrock&lt;/code&gt;, &lt;code&gt;xai&lt;/code&gt;, &lt;code&gt;groq&lt;/code&gt;, &lt;code&gt;openrouter&lt;/code&gt;, &lt;code&gt;deepseek&lt;/code&gt;, &lt;code&gt;cohere&lt;/code&gt;, &lt;code&gt;mistral&lt;/code&gt;, &lt;code&gt;vercel&lt;/code&gt;, &lt;code&gt;nvidia&lt;/code&gt;, &lt;code&gt;moonshotai&lt;/code&gt;, &lt;code&gt;alibaba&lt;/code&gt; and &lt;code&gt;minimax&lt;/code&gt;. &lt;strong&gt;Ollama wasn't one of them&lt;/strong&gt;, although the AI Agent node has an Ollama Chat Model sub-node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Undocumented workaround (tested once, may break).&lt;/strong&gt; Ollama's docs say it "supports a subset of the OpenAI API", served at &lt;code&gt;http://localhost:11434/v1/&lt;/code&gt;, and that the client "requires an API key value, but Ollama ignores it". So the test used n8n's &lt;strong&gt;OpenAI&lt;/strong&gt; credential type with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API key: &lt;code&gt;ollama&lt;/code&gt; (any value)&lt;/li&gt;
&lt;li&gt;Base URL: &lt;code&gt;http://127.0.0.1:11434/v1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Model: &lt;code&gt;qwen2.5-1.5b-local&lt;/code&gt; under the OpenAI provider&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that, validation returned &lt;code&gt;valid&lt;/code&gt; and the Preview chat below got replies. This isn't described in the n8n docs that were checked, and it was tested only on n8n 2.43.8 with Ollama 0.40.6, for plain chat with no tools. Tool calls through this route weren't tested. Treat it as an experiment, not a supported setup: an n8n update could break it. If you need a supported setup, pick one of the listed providers.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happened
&lt;/h3&gt;

&lt;p&gt;Instructions: "You are a helpful assistant. Answer in one or two short sentences." No tools. Three messages in one Preview session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; In one sentence, what is n8n?
N8n is an open-source automation platform designed for building and managing workflows.

&amp;gt; What is 1234 * 56?
1234 * 56 equals 70,064.

&amp;gt; What did I ask you first in this chat?
You didn't ask anything initially. This is a conversation with a helpful assistant. ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are real replies from the small local model, and they show two problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arithmetic without a tool is wrong.&lt;/strong&gt; The correct answer is 69,104, which Build 1 got through the Calculator. Give an agent a tool for anything that has to be exact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The recall question failed.&lt;/strong&gt; All three turns ran in the same Preview session. n8n's execution records show about the same prompt size on every turn (3,460, 3,462 and 3,460 prompt tokens), which suggests the earlier turns weren't sent to the model on the third turn. Whether that comes from the workaround above, the Preview chat, or something else couldn't be determined in this test. The docs say session memory "is on by default and needs no setup", so try it with a listed provider before drawing conclusions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first answer is the model's own wording. n8n's &lt;code&gt;LICENSE.md&lt;/code&gt; in the 2.43.8 package says most of its code is under n8n's "Sustainable Use License", so don't take "open-source" from a small model as a licensing statement.&lt;/p&gt;




&lt;h2&gt;
  
  
  Human approval for tools that change data
&lt;/h2&gt;

&lt;p&gt;Both builds above only read data. Once a tool can send, delete or update something, add a human check. For Agents, n8n's docs say: "For sensitive tools, you can require approval before the agent runs them", and in the chat you then select Approve or Reject. This wasn't tested here, because no write tool was connected.&lt;/p&gt;




&lt;h2&gt;
  
  
  Limits and caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preview means change.&lt;/strong&gt; Agents' behavior "may change while the feature is in development". Date your notes and recheck after upgrades.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queue mode:&lt;/strong&gt; not supported for agents yet, per the docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge base on self-hosted&lt;/strong&gt; needs a Daytona sandbox and is itself in Preview. Not tested.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Episodic memory&lt;/strong&gt; (recall across sessions) needs an OpenAI credential. Not tested.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Channels&lt;/strong&gt; (Slack, Telegram, Linear) need a public &lt;code&gt;WEBHOOK_URL&lt;/code&gt; on self-hosted. Not tested.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not tested at all:&lt;/strong&gt; attaching a tool or skill to the Agent, publishing the Agent, the n8n Assistant, Docker, and any cloud model.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Which one should you start with?
&lt;/h2&gt;

&lt;p&gt;If you're new, start with &lt;strong&gt;Build 1&lt;/strong&gt;. It isn't in Preview, it has a built-in Ollama Chat Model sub-node, and you can see every step in the execution log. Move to &lt;strong&gt;Agents&lt;/strong&gt; when you want an assistant people can chat with directly, and when you're comfortable with a feature that's still in Preview.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Sources (checked October 20, 2026): n8n Docs "Build and manage agents" (&lt;a href="https://docs.n8n.io/build/build-and-manage-agents" rel="noopener noreferrer"&gt;https://docs.n8n.io/build/build-and-manage-agents&lt;/a&gt;), "AI Agent" node (&lt;a href="https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent" rel="noopener noreferrer"&gt;https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent&lt;/a&gt;), "Compare editions" (&lt;a href="https://docs.n8n.io/deploy/host-n8n/community-edition-features" rel="noopener noreferrer"&gt;https://docs.n8n.io/deploy/host-n8n/community-edition-features&lt;/a&gt;); Ollama Docs "OpenAI compatibility" (&lt;a href="https://docs.ollama.com/api/openai-compatibility" rel="noopener noreferrer"&gt;https://docs.ollama.com/api/openai-compatibility&lt;/a&gt;).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>abotwrotethis</category>
      <category>n8n</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Translate SRT Subtitles with ChatGPT (Japanese to English) Without Breaking the Timing + a Free Python Checker</title>
      <dc:creator>AI Sensei LAB</dc:creator>
      <pubDate>Mon, 19 Oct 2026 22:31:14 +0000</pubDate>
      <link>https://dev.to/crypteasensei/how-to-translate-srt-subtitles-with-chatgpt-japanese-to-english-without-breaking-the-timing-a-2266</link>
      <guid>https://dev.to/crypteasensei/how-to-translate-srt-subtitles-with-chatgpt-japanese-to-english-without-breaking-the-timing-a-2266</guid>
      <description>&lt;p&gt;&lt;em&gt;If you translate SRT subtitles with ChatGPT by pasting the whole file, cue numbers and timecodes can drift. This guide shows how to keep the structure locked, translate Japanese to English with any chatbot, and check the result with a free Python script that tests line length, reading speed, duration and gaps against Netflix's public timed text guidelines.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: this article was drafted and edited with AI tools (#abotwrotethis). The Python script was run on Python 3.13.5 on October 20, 2026, and the checker output below is real. The English sample translation was written for this article by the AI tool that drafted it. The prompt in this article was not run in ChatGPT, Claude or Gemini, so no chatbot output is shown.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Pasting an SRT file into a chatbot and asking for English usually works for a few lines. On longer files, things break: two cues get merged, a cue number disappears, or a timecode comes back slightly different. Japanese adds its own problem. A sentence often runs across two or three cues, with the verb at the very end, so translating cue by cue gives you English that reads backwards.&lt;/p&gt;

&lt;p&gt;The fix is to never let the model touch the parts it shouldn't change.&lt;/p&gt;




&lt;h2&gt;
  
  
  What must never change in an SRT
&lt;/h2&gt;

&lt;p&gt;An SRT cue has three parts: an index, a timing line, and one or more lines of text, followed by a blank line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4
00:00:10,000 --&amp;gt; 00:00:12,400
駅前の新しいカフェ、
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SRT is a simple plain-text format, so treat this structure as the contract. When you translate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;number of cues&lt;/strong&gt; must stay the same,&lt;/li&gt;
&lt;li&gt;every &lt;strong&gt;index&lt;/strong&gt; must stay the same,&lt;/li&gt;
&lt;li&gt;every &lt;strong&gt;timing line&lt;/strong&gt; must stay byte-for-byte the same,&lt;/li&gt;
&lt;li&gt;only the &lt;strong&gt;text&lt;/strong&gt; changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a line is too long to read in time, shorten the English. Don't retime the cue during translation. Retiming is a separate job with its own rules.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Japanese to English is harder
&lt;/h2&gt;

&lt;p&gt;Take cues 4–6 from the sample used below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;駅前の新しいカフェ、                  (the new café by the station,)
昨日オープンしたって聞いたんだけど      (I heard it opened yesterday, but)
行ってみない?                          (want to go?)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Translated one cue at a time, cue 4 becomes "The new café in front of the station," with nothing to attach to. The English needs to know what comes next. The model needs the neighboring cues as &lt;strong&gt;context&lt;/strong&gt;, while you still get back exactly one translation per cue.&lt;/p&gt;

&lt;p&gt;Japanese also drops subjects ("すぐ追いつくから!" has no "I") and puts tone in sentence endings ("なんとかなるでしょ"). Both need context, not a dictionary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: lock the structure (SRT to JSON)
&lt;/h2&gt;

&lt;p&gt;The script below turns the SRT into a JSON list of &lt;code&gt;id&lt;/code&gt; + &lt;code&gt;text&lt;/code&gt;, plus the previous and next cue as read-only context. Timecodes stay in the original file and never go to the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 srtcheck.py to-json sample_ja.srt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; cues.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real output for cue 4:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"駅前の新しいカフェ、"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"……まあ、いっか。なんとかなるでしょ。"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"昨日オープンしたって聞いたんだけど"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: the prompt
&lt;/h2&gt;

&lt;p&gt;Paste this into ChatGPT, Claude or Gemini, followed by the contents of &lt;code&gt;cues.json&lt;/code&gt;. It's a template: it wasn't run in any chatbot for this article, so check the first reply with the script before you trust it. For long files, send 30 to 50 cues per message so the reply doesn't get cut off. Keep the batches in order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are translating Japanese subtitles into natural U.S. English.

Input: a JSON array. Each item has "id", "text" (translate this),
and "prev"/"next" (neighboring cues, for context only - do not translate them).

Rules:
1. Return a JSON array with exactly one item per input item, same order,
   each item {"id": &amp;lt;same id&amp;gt;, "text": &amp;lt;English&amp;gt;}. Nothing else.
2. Never merge, split, add or drop items. Never change an id.
3. When a Japanese sentence runs across several cues, translate the whole
   sentence, then divide the English across those same cues in a natural
   reading order. Each cue must still make sense where it breaks.
4. Keep each cue short: at most 2 lines, at most 42 characters per line.
   Use "\n" for a line break. Prefer shorter wording to long, literal wording.
5. Keep the speaker's tone (casual stays casual). Add a subject only when
   English needs one.
6. Use the single ellipsis character (…) instead of three dots,
   and no em or en dashes.
7. If something cannot be translated with confidence (a name, a pun),
   keep your best version and add "[CHECK]" at the end of that text.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rules 4 and 6 come from Netflix's English (USA) Timed Text Style Guide, which sets 42 characters per line and a maximum of two lines, says en and em dashes are not permitted, and asks for the single ellipsis character instead of three dots. You can remove them if your platform uses different rules.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: rebuild the SRT
&lt;/h2&gt;

&lt;p&gt;Save the model's reply as &lt;code&gt;translated_en.json&lt;/code&gt;. The script takes the timing lines from the &lt;strong&gt;original&lt;/strong&gt; file and only the text from the JSON, so the model can't change a timecode even if it tries. If an ID is missing, it stops with an error.&lt;/p&gt;

&lt;p&gt;This is the translation used for the test. It was written for this article by the AI tool that drafted it, not generated with the prompt above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Wait, it's already this late?"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sorry, go on ahead.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;I'll catch up!"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Oh well. It'll work out."&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"That new café by the station"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"opened yesterday, I heard."&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Want to check it out?"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Yeah!"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 srtcheck.py from-json sample_ja.srt translated_en.json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; sample_en.srt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: run the checker
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 srtcheck.py check sample_ja.srt sample_en.srt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The checker compares the two files and tests each English cue against these limits:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cue count, indexes, timing lines&lt;/td&gt;
&lt;td&gt;identical to source&lt;/td&gt;
&lt;td&gt;(structure)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Characters per line&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td&gt;Netflix English (USA) guide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines per cue&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Netflix English (USA) guide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reading speed&lt;/td&gt;
&lt;td&gt;up to 20 characters per second (adult programs)&lt;/td&gt;
&lt;td&gt;Netflix English (USA) guide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum duration&lt;/td&gt;
&lt;td&gt;7 seconds&lt;/td&gt;
&lt;td&gt;Netflix General Requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minimum duration&lt;/td&gt;
&lt;td&gt;5/6 of a second (20 frames at 24 fps)&lt;/td&gt;
&lt;td&gt;Netflix General Requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gap between cues&lt;/td&gt;
&lt;td&gt;at least 2 frames; in 24 fps content, gaps of 3 to 11 frames must be closed to 2&lt;/td&gt;
&lt;td&gt;Netflix Subtitle Timing Guidelines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Punctuation&lt;/td&gt;
&lt;td&gt;no double spaces, no en/em dashes, ellipsis character&lt;/td&gt;
&lt;td&gt;Netflix English (USA) guide&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Reading speed here is counted as all characters including spaces, excluding line breaks, divided by the cue's duration. Netflix's page gives the limit but not the counting method, so treat this as an estimate.&lt;/p&gt;

&lt;p&gt;Frame-based checks assume 24 fps unless you pass &lt;code&gt;--fps&lt;/code&gt; (for example &lt;code&gt;--fps 25&lt;/code&gt;). Two Netflix pages word the minimum duration differently: General Requirements says "5/6 (five-sixths) of a second per subtitle event (e.g. 20 frames for 24fps)", while the Subtitle Timing Guidelines say "20 frames (or 4/5 sec)". At 24 fps, 20 frames is 5/6 of a second (0.833 s), not 4/5 (0.8 s). The script uses 5/6 of a second, the stricter value. The 3-to-11-frame gap rule is written for 24 fps content, so the script only applies it with &lt;code&gt;--fps 24&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real output&lt;/strong&gt; for the translation above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WARN    cue 1-&amp;gt;2: gap 4.8 frames (24 fps rule: gaps of 3-11 frames must be closed to 2; source timing, fix in a timing pass)
WARN    cue 2-&amp;gt;3: gap 7.2 frames (24 fps rule: gaps of 3-11 frames must be closed to 2; source timing, fix in a timing pass)
WARN    cue 4-&amp;gt;5: gap 1.92 frames (min 2)
WARN    cue 7: duration 0.800s (min 5/6 s = 0.833s, 20 frames at 24 fps)

7 cues checked: 0 error(s), 4 warning(s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No errors: the cue count, indexes and timing lines all match, and every line fits. The four warnings are about the &lt;strong&gt;source timing&lt;/strong&gt;, not the translation. The sample was timed by hand for this article. Gaps of 4.8 and 7.2 frames, an 80 ms gap (1.92 frames), and a 0.8-second cue would all need a timing pass under Netflix's rules. (The 0.8-second cue is exactly the case where the two Netflix pages disagree: it meets "4/5 sec" but not "5/6 of a second".) The checker flags them, so you know they were there before the translation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real output&lt;/strong&gt; for a naive version, translated line by line and pasted back by hand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR   cue count changed: source 7, target 6
ERROR   cue 6: timecode changed (00:00:15,084 --&amp;gt; 00:00:17,500 -&amp;gt; 00:00:15,084 --&amp;gt; 00:00:19,000)
ERROR   cue 2: line has 73 chars (max 42): "I'm sorry, please go ahead first and I will catch up with you right away!"
ERROR   cue 3: line has 45 chars (max 42): "...Well, it's fine. It will work out somehow."
WARN    cue 1-&amp;gt;2: gap 4.8 frames (24 fps rule: gaps of 3-11 frames must be closed to 2; source timing, fix in a timing pass)
WARN    cue 2: reading speed 28.1 CPS (max 20) - shorten the text, don't retime
WARN    cue 2-&amp;gt;3: gap 7.2 frames (24 fps rule: gaps of 3-11 frames must be closed to 2; source timing, fix in a timing pass)
WARN    cue 3: three dots; use the single ellipsis character
WARN    cue 4-&amp;gt;5: gap 1.92 frames (min 2)

6 cues checked: 4 error(s), 5 warning(s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the kinds of mistakes this article is about: cues 6 and 7 were merged into one (and its end time stretched), a literal line ran to 73 characters at 28.1 characters per second, and three dots were used where Netflix asks for the ellipsis character.&lt;/p&gt;

&lt;p&gt;The exit code is 1 when there are errors and 0 when there are only warnings, so you can use it in a script or a CI job.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fixing what the checker flags
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line too long / reading speed too high:&lt;/strong&gt; shorten the English. "Sorry, go on ahead. I'll catch up!" says what "I'm sorry, please go ahead first and I will catch up with you right away!" says, in less than half the characters. You can also ask the model to shorten only the flagged IDs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cue count or timecode changed:&lt;/strong&gt; don't fix it by hand. Rebuild from the JSON with &lt;code&gt;from-json&lt;/code&gt;, which always uses the source timing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gaps and durations:&lt;/strong&gt; these are timing issues in the source. Fix them in your subtitle editor as a separate timing pass, following Netflix's Subtitle Timing Guidelines.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What still needs a person who reads Japanese
&lt;/h2&gt;

&lt;p&gt;The checker can tell you a line fits. It can't tell you it's right. Have someone who reads Japanese check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;names and how they're romanized,&lt;/li&gt;
&lt;li&gt;jokes, puns and wordplay,&lt;/li&gt;
&lt;li&gt;politeness levels (keigo) and how formal the English should sound,&lt;/li&gt;
&lt;li&gt;anything you marked &lt;code&gt;[CHECK]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The full script
&lt;/h2&gt;

&lt;p&gt;Standard library only. Save it as &lt;code&gt;srtcheck.py&lt;/code&gt;.&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="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;srtcheck.py - round-trip an SRT through JSON and check a translated SRT.

  python3 srtcheck.py to-json  source.srt  &amp;gt; cues.json
  python3 srtcheck.py from-json source.srt translated.json &amp;gt; target.srt
  python3 srtcheck.py check    source.srt  target.srt [--fps 24]

Standard library only. Limits come from Netflix&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s public Timed Text Style Guide
pages (English (USA), General Requirements, Subtitle Timing Guidelines).
--fps sets the frame rate used for frame-based checks (default 24).
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;MAX_CHARS_PER_LINE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;   &lt;span class="c1"&gt;# English (USA) guide, II.3
&lt;/span&gt;&lt;span class="n"&gt;MAX_LINES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;             &lt;span class="c1"&gt;# English (USA) guide, II.13
&lt;/span&gt;&lt;span class="n"&gt;MAX_CPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;20.0&lt;/span&gt;            &lt;span class="c1"&gt;# English (USA) guide, II.17 (adult programs)
&lt;/span&gt;&lt;span class="n"&gt;MAX_DURATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;7.0&lt;/span&gt;        &lt;span class="c1"&gt;# General Requirements, 1. Duration
&lt;/span&gt;&lt;span class="n"&gt;MIN_DURATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;      &lt;span class="c1"&gt;# General Requirements, 1. Duration: 5/6 s (20 frames at 24 fps)
&lt;/span&gt;&lt;span class="n"&gt;MIN_GAP_FRAMES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;        &lt;span class="c1"&gt;# Timing Guidelines, 5: minimum 2 frames between subtitles
&lt;/span&gt;
&lt;span class="n"&gt;TC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(\d{2}):(\d{2}):(\d{2})[,.](\d{3})\s*--&amp;gt;\s*(\d{2}):(\d{2}):(\d{2})[,.](\d{3})&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&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;path&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="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&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="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cues&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;block&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\n\s*\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&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;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&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;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;TC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot parse block:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;block&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;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&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;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;m&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="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;
        &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;
        &lt;span class="n"&gt;cues&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;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lines&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&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;cues&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;out&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;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&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;cues&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;out&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;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&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;text&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="se"&gt;\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;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lines&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;prev&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="se"&gt;\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;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lines&lt;/span&gt;&lt;span class="sh"&gt;"&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;i&lt;/span&gt; &lt;span class="k"&gt;else&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;next&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="se"&gt;\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;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lines&lt;/span&gt;&lt;span class="sh"&gt;"&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;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;cues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&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="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ensure_ascii&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;from_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;translated&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&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;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&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;translated&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="n"&gt;missing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&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;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cues&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tr&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;SystemExit&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;Translated JSON is missing ids: &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="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;blocks&lt;/span&gt; &lt;span class="o"&gt;=&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;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&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="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cues&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="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\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;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tgt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;24.0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tgt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;warnings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;if&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;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;errors&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue count changed: source &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;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, target &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;b&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&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;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;errors&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: index changed to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;errors&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: timecode changed (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timing&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timing&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&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;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lines&lt;/span&gt;&lt;span class="sh"&gt;"&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;l&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;chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&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;l&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;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# characters incl. spaces, excl. line breaks
&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;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;errors&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: empty text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&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;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_LINES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;errors&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &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;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; lines (max &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MAX_LINES&lt;/span&gt;&lt;span class="si"&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&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;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_CHARS_PER_LINE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;errors&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: line has &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;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; chars (max &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MAX_CHARS_PER_LINE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="sh"&gt;"&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;dur&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_CPS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;warnings&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: reading speed &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dur&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; CPS (max &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MAX_CPS&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) - shorten the text, don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t retime&lt;/span&gt;&lt;span class="sh"&gt;"&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;dur&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_DURATION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;warnings&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: duration &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dur&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s (max &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MAX_DURATION&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s)&lt;/span&gt;&lt;span class="sh"&gt;"&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;dur&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MIN_DURATION&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;1e-6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;warnings&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: duration &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dur&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s (min 5/6 s = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MIN_DURATION&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MIN_DURATION&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fps&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; frames at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;fps&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; fps)&lt;/span&gt;&lt;span class="sh"&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;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&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="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;warnings&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: double space&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u2013&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u2014&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;warnings&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: en/em dash (not permitted)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&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="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;warnings&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: three dots; use the single ellipsis character&lt;/span&gt;&lt;span class="sh"&gt;"&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;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;gap_frames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&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;gap_frames&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MIN_GAP_FRAMES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;warnings&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: gap &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;gap_frames&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; frames (min &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MIN_GAP_FRAMES&lt;/span&gt;&lt;span class="si"&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="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;fps&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;gap_frames&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;warnings&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cue &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: gap &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;gap_frames&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; frames (24 fps rule: gaps of 3-11 frames must be closed to 2; source timing, fix in a timing pass)&lt;/span&gt;&lt;span class="sh"&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;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;errors&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&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;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;warnings&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WARN   &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&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="se"&gt;\n&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;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; cues checked: &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;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; error(s), &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;warnings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; warning(s)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="n"&gt;fps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;24.0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--fps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--fps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;fps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;k&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="k"&gt;if&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;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;to-json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;to_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;elif&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;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from-json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;from_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;elif&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;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&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;fps&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else&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="n"&gt;__doc__&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The sample files
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;sample_ja.srt&lt;/code&gt; (cues 1 to 3 are a short team-written test text, cues 4 to 7 were written for this article):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
00:00:01,000 --&amp;gt; 00:00:03,200
えっ、もうこんな時間?

2
00:00:03,400 --&amp;gt; 00:00:06,000
ごめん、先に行ってて。すぐ追いつくから!

3
00:00:06,300 --&amp;gt; 00:00:09,000
……まあ、いっか。なんとかなるでしょ。

4
00:00:10,000 --&amp;gt; 00:00:12,400
駅前の新しいカフェ、

5
00:00:12,480 --&amp;gt; 00:00:15,000
昨日オープンしたって聞いたんだけど

6
00:00:15,084 --&amp;gt; 00:00:17,500
行ってみない?

7
00:00:18,200 --&amp;gt; 00:00:19,000
うん!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;naive_en.srt&lt;/code&gt;, used for the failing run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
00:00:01,000 --&amp;gt; 00:00:03,200
Eh, is it already this time?

2
00:00:03,400 --&amp;gt; 00:00:06,000
I'm sorry, please go ahead first and I will catch up with you right away!

3
00:00:06,300 --&amp;gt; 00:00:09,000
...Well, it's fine. It will work out somehow.

4
00:00:10,000 --&amp;gt; 00:00:12,400
The new café in front of the station,

5
00:00:12,480 --&amp;gt; 00:00:15,000
I heard it opened yesterday, but

6
00:00:15,084 --&amp;gt; 00:00:19,000
won't you go? Yes!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Sources (checked October 20, 2026; Netflix pages re-opened by the editor): Netflix Partner Help Center, "English (USA) Timed Text Style Guide" (&lt;a href="https://partnerhelp.netflixstudios.com/hc/en-us/articles/217350977-English-USA-Timed-Text-Style-Guide" rel="noopener noreferrer"&gt;https://partnerhelp.netflixstudios.com/hc/en-us/articles/217350977-English-USA-Timed-Text-Style-Guide&lt;/a&gt;), "Timed Text Style Guide: General Requirements" (&lt;a href="https://partnerhelp.netflixstudios.com/hc/en-us/articles/215758617-Timed-Text-Style-Guide-General-Requirements" rel="noopener noreferrer"&gt;https://partnerhelp.netflixstudios.com/hc/en-us/articles/215758617-Timed-Text-Style-Guide-General-Requirements&lt;/a&gt;), and "Timed Text Style Guide: Subtitle Timing Guidelines" (&lt;a href="https://partnerhelp.netflixstudios.com/hc/en-us/articles/360051554394-Timed-Text-Style-Guide-Subtitle-Timing-Guidelines" rel="noopener noreferrer"&gt;https://partnerhelp.netflixstudios.com/hc/en-us/articles/360051554394-Timed-Text-Style-Guide-Subtitle-Timing-Guidelines&lt;/a&gt;).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>abotwrotethis</category>
      <category>python</category>
      <category>ai</category>
      <category>translation</category>
    </item>
    <item>
      <title>How to Create a Claude Skill You Can Reuse in ChatGPT and Gemini</title>
      <dc:creator>AI Sensei LAB</dc:creator>
      <pubDate>Mon, 19 Oct 2026 09:46:35 +0000</pubDate>
      <link>https://dev.to/crypteasensei/how-to-create-a-claude-skill-you-can-reuse-in-chatgpt-and-gemini-3e70</link>
      <guid>https://dev.to/crypteasensei/how-to-create-a-claude-skill-you-can-reuse-in-chatgpt-and-gemini-3e70</guid>
      <description>&lt;p&gt;&lt;em&gt;One SKILL.md file, three apps: a portable template, the upload steps for each, and the limits that differ between them.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: this article was drafted and edited with AI tools.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you keep pasting the same long prompt into a chat window, a skill is the fix that Claude, ChatGPT and Gemini now all offer. All three build on the same open format: a folder with a file called &lt;code&gt;SKILL.md&lt;/code&gt; inside it. In principle, that means you write the file once and upload it to each app.&lt;/p&gt;

&lt;p&gt;In practice, each app has its own upload screen, plan rules and limits. This guide walks through building one skill that stays inside the strictest rules of all three, then shows where to upload it in each app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How this guide was made:&lt;/strong&gt; every step and limit below comes from the official Anthropic, OpenAI and Google documentation, checked on October 19, 2026. The steps have not been tried hands-on in the three apps. These features are changing quickly, so check the linked pages before you rely on a detail, and expect the screens to look slightly different.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a skill is (and when you don't need one)
&lt;/h2&gt;

&lt;p&gt;A skill is a saved set of instructions, plus optional files, that the AI loads only when your request matches it. All three vendors describe the same pattern. The app reads each skill's short name and description first. It opens the full instructions only when it decides the skill is relevant, and opens any extra files only when a step calls for them.&lt;/p&gt;

&lt;p&gt;That's why skills suit &lt;strong&gt;repeated tasks you want done the same way every time&lt;/strong&gt;: a report format, a review checklist, a multi-step routine.&lt;/p&gt;

&lt;p&gt;You probably don't need a skill when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's a one-off task.&lt;/strong&gt; Just describe it in the chat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The instruction applies to every conversation.&lt;/strong&gt; Claude's docs point you to your personal preferences or project instructions for that, because a skill only loads when a task matches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The task keeps changing.&lt;/strong&gt; Google's guidance says to skip skills when the steps change too often to keep up to date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The app already does it well without help.&lt;/strong&gt; Google lists this as a reason to skip one too.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The anatomy of a SKILL.md file
&lt;/h2&gt;

&lt;p&gt;A skill is a folder. The only required file is &lt;code&gt;SKILL.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extract-action-items/
└── SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional folders such as &lt;code&gt;references/&lt;/code&gt;, &lt;code&gt;assets/&lt;/code&gt; and &lt;code&gt;scripts/&lt;/code&gt; can sit next to it. For a skill you want to carry between apps, start without them (more on why below).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SKILL.md&lt;/code&gt; has two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Frontmatter&lt;/strong&gt;: a short block between two &lt;code&gt;---&lt;/code&gt; lines with two required fields, &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Body&lt;/strong&gt;: plain Markdown instructions the AI follows once the skill loads.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-skill-name&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;What the skill does. Use when [the situations it's for].&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Instructions go here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Portable rules: write to the strictest limit
&lt;/h2&gt;

&lt;p&gt;The three apps don't publish identical rules, so the safe approach is to satisfy all of them at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The &lt;code&gt;name&lt;/code&gt; field&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use only lowercase letters, numbers and hyphens, up to 64 characters. The open Agent Skills specification and Claude's docs both require this, and Gemini's help page requires lowercase words separated by hyphens. The specification also says the name can't start or end with a hyphen or contain two hyphens in a row.&lt;/li&gt;
&lt;li&gt;Make the folder name exactly match &lt;code&gt;name&lt;/code&gt;. Claude's docs and the specification both require it.&lt;/li&gt;
&lt;li&gt;Don't put "claude" or "anthropic" in the name. Claude's developer docs list these as reserved words.&lt;/li&gt;
&lt;li&gt;Start with a verb. Google suggests action names like &lt;code&gt;plan-meal-from-recipe&lt;/code&gt; rather than &lt;code&gt;recipe-data&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The &lt;code&gt;description&lt;/code&gt; field&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Say what the skill does, then when to use it. Every vendor stresses this, because the description is what the app reads to decide whether to load the skill.&lt;/li&gt;
&lt;li&gt;Write it in the third person ("Turns…", not "I can help you…"). Both Claude's best-practices guide and Google's help page say so.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep it under 200 characters.&lt;/strong&gt; The open specification, Claude's developer docs and Gemini's help page all give a 1,024-character limit. One Claude Help Center article still says 200, next to other details that look older than the current specification. Staying under 200 is safe in every case.&lt;/li&gt;
&lt;li&gt;Put the main use case and trigger words first. OpenAI's skills guide says Codex shortens descriptions when many skills are installed, and advises front-loading trigger words so a shortened description still matches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The body&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep it short and focused on one job. Claude's docs suggest under 500 lines, and Google calls skills "cheat sheets, not manuals."&lt;/li&gt;
&lt;li&gt;Prefer plain instructions over scripts. Gemini doesn't support scripts that need the internet, and it accepts only plain-text files plus PDFs and images (no .docx or .xlsx). Claude's API runs skills with no network access, and ChatGPT scans uploaded skills before they become available. An instructions-only skill avoids all of these differences.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Build the example skill step by step
&lt;/h2&gt;

&lt;p&gt;The example turns pasted meeting notes into a list of action items, each with an owner and a due date when the notes give one, plus any open questions. It's a good first skill: it's a job you repeat after every meeting, it benefits from a fixed sequence of steps, and it needs nothing but instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Write the task in one sentence
&lt;/h3&gt;

&lt;p&gt;Claude's docs suggest starting with a single sentence describing the task and what a good result looks like. That sentence becomes your description:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Turns pasted meeting notes into a list of action items with owners, due dates if stated, and open questions. Use when processing notes from a meeting, call, or standup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's 168 characters: third person, what first, then "Use when…".&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: List inputs, steps and output
&lt;/h3&gt;

&lt;p&gt;OpenAI's guide suggests a skill should state the job, the required inputs, numbered steps, the output format and final checks. Google adds two habits worth copying: a "common mistakes" section, and telling the AI what to do when information is missing instead of guessing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Create the folder and file
&lt;/h3&gt;

&lt;p&gt;Make a folder named &lt;code&gt;extract-action-items&lt;/code&gt;. Inside it, create a plain-text file named &lt;code&gt;SKILL.md&lt;/code&gt;, using a plain text editor rather than a word processor. Paste in the template below.&lt;/p&gt;

&lt;h3&gt;
  
  
  The complete SKILL.md (copy and adapt)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;extract-action-items&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Turns pasted meeting notes into a list of action items with owners, due dates if stated, and open questions. Use when processing notes from a meeting, call, or standup.&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Extract action items from meeting notes&lt;/span&gt;

&lt;span class="gu"&gt;## Inputs&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; The meeting notes, pasted as text (required)
&lt;span class="p"&gt;-&lt;/span&gt; The meeting date, if the notes don't include it

If no notes are provided, ask for them. Do not guess what was discussed.

&lt;span class="gu"&gt;## Workflow&lt;/span&gt;
Copy this checklist and work through it in order:
&lt;span class="p"&gt;-&lt;/span&gt; [ ] 1. Read the notes
&lt;span class="p"&gt;-&lt;/span&gt; [ ] 2. Pull out the action items
&lt;span class="p"&gt;-&lt;/span&gt; [ ] 3. Collect open questions
&lt;span class="p"&gt;-&lt;/span&gt; [ ] 4. Check the list against the notes

&lt;span class="gu"&gt;### 1. Read the notes (do not list anything yet)&lt;/span&gt;
Note briefly:
&lt;span class="p"&gt;-&lt;/span&gt; What the meeting was about, in one sentence
&lt;span class="p"&gt;-&lt;/span&gt; The people named in the notes
&lt;span class="p"&gt;-&lt;/span&gt; Any decisions that were made

&lt;span class="gu"&gt;### 2. Pull out the action items&lt;/span&gt;
For each task someone agreed to do, or was asked to do:
&lt;span class="p"&gt;-&lt;/span&gt; Write the task as a short phrase that starts with a verb.
&lt;span class="p"&gt;-&lt;/span&gt; Owner: the person named for it. If nobody is named, write "Unassigned".
&lt;span class="p"&gt;-&lt;/span&gt; Due date: only if the notes state one, in the notes' own wording. Otherwise write "Not stated".
&lt;span class="p"&gt;-&lt;/span&gt; Do not invent tasks, owners, or dates that are not in the notes.

&lt;span class="gu"&gt;### 3. Collect open questions&lt;/span&gt;
List questions that were raised but not answered, and topics still waiting for a decision.
Also list any action item whose owner or meaning is unclear.

&lt;span class="gu"&gt;### 4. Check the list against the notes&lt;/span&gt;
Reread the notes from the top.
Add any task you missed, and remove any item the notes do not support.

&lt;span class="gu"&gt;## Output format&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; &lt;span class="gs"&gt;**Summary**&lt;/span&gt;: one sentence on what the meeting covered
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Action items**&lt;/span&gt;: a table with the columns Task, Owner, Due date
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**Open questions**&lt;/span&gt;: a bulleted list. If there are none, say so.

&lt;span class="gu"&gt;## Common mistakes to avoid&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Turning a general discussion point into a task nobody agreed to
&lt;span class="p"&gt;-&lt;/span&gt; Guessing the owner from whoever spoke most
&lt;span class="p"&gt;-&lt;/span&gt; Converting a vague timeframe ("soon", "after the launch") into an exact date
&lt;span class="p"&gt;-&lt;/span&gt; Missing tasks mentioned in passing near the end of the notes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the inputs, steps and mistakes to fit your own task. Keep the structure: description, inputs, a numbered checklist, an output format and a mistakes list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Package it
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude&lt;/strong&gt; expects a ZIP file, and the ZIP must contain the folder itself, not just the files inside it. On macOS or Linux, Claude's docs give this command, run from the folder that &lt;em&gt;contains&lt;/em&gt; your skill folder:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  zip &lt;span class="nt"&gt;-r&lt;/span&gt; extract-action-items.zip extract-action-items/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use another tool, compress the folder rather than the file inside it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemini&lt;/strong&gt; accepts a &lt;code&gt;SKILL.md&lt;/code&gt; file on its own, a folder, or a ZIP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ChatGPT&lt;/strong&gt;'s help page says "Upload from your computer" but doesn't state the file type for the app.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Upload it: Claude, ChatGPT and Gemini
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Claude (claude.ai and the desktop app)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Turn on code execution. Claude's help page says skills need it. On individual plans it's under &lt;strong&gt;Settings → Capabilities → Code execution and file creation&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Customize → Skills&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;+&lt;/strong&gt;, then &lt;strong&gt;Create skill&lt;/strong&gt;, then &lt;strong&gt;Upload a skill&lt;/strong&gt;, and choose your ZIP.&lt;/li&gt;
&lt;li&gt;Make sure the skill is toggled on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Claude's Help Center lists skills on the Free, Pro, Max, Team and Enterprise plans. Note that one older developer page still says Pro and above, so check your own account. On Team and Enterprise, an organization owner controls whether skills and uploads are allowed.&lt;/p&gt;

&lt;h3&gt;
  
  
  ChatGPT
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the sidebar, select &lt;strong&gt;Plugins&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Skills&lt;/strong&gt; tab in the Plugin Directory.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Create&lt;/strong&gt;, then &lt;strong&gt;Upload from your computer&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Wait for the scan. OpenAI says uploaded skills are scanned first. Most become available right away, some are marked &lt;strong&gt;Needs Review&lt;/strong&gt;, and risky ones are &lt;strong&gt;Blocked&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Plan access is unclear right now.&lt;/strong&gt; OpenAI's Skills help article says skills are for "eligible ChatGPT Business, Enterprise, Healthcare, and Edu users." Its pricing page, checked the same day, lists Skills on Free, Go, Plus and Pro. OpenAI's developer guide also says standalone skills are in the ChatGPT desktop app. The reliable check is whether a Skills tab appears under Plugins in your own account. Upload options may also differ by plan and by app, so don't assume a personal plan can upload on the web.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gemini app
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to gemini.google.com, or open the Gemini app on a Mac.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Customize&lt;/strong&gt; in the sidebar (under &lt;strong&gt;More&lt;/strong&gt; if you don't see it), then &lt;strong&gt;Skills&lt;/strong&gt; at the top.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Upload&lt;/strong&gt;, select your &lt;code&gt;SKILL.md&lt;/code&gt;, folder or ZIP, and click &lt;strong&gt;Open&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Review the skill, then click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Google's help page lists these requirements: you must be 18 or over, signed in, with Keep Activity on. (Google's October 13 launch post says Gemini app skills will be open to all ages, so the age rule may change.) Skills are only in the Gemini mobile app, the Mac app and the web app. A Google AI subscription isn't required. Google says skills in the Gemini app began a gradual rollout on October 13, 2026, with completion expected by mid-November. If you don't see Skills yet, your account may simply not have it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Compatibility at a glance (from the docs, October 19, 2026)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Claude (claude.ai)&lt;/th&gt;
&lt;th&gt;ChatGPT&lt;/th&gt;
&lt;th&gt;Gemini app&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where&lt;/td&gt;
&lt;td&gt;Customize → Skills&lt;/td&gt;
&lt;td&gt;Plugins → Skills tab&lt;/td&gt;
&lt;td&gt;Customize → Skills&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Upload format&lt;/td&gt;
&lt;td&gt;ZIP with the skill folder at the top level&lt;/td&gt;
&lt;td&gt;"Upload from your computer" (type not stated)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;SKILL.md&lt;/code&gt;, folder, or ZIP; 100 MB total&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lowercase, numbers, hyphens; ≤64; matches folder; no "claude"/"anthropic"&lt;/td&gt;
&lt;td&gt;Follows the open standard&lt;/td&gt;
&lt;td&gt;Lowercase words with hyphens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1,024 (docs) vs. 200 (Help Center)&lt;/td&gt;
&lt;td&gt;Front-load; may be shortened&lt;/td&gt;
&lt;td&gt;1,024&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scripts / files&lt;/td&gt;
&lt;td&gt;Allowed; needs code execution&lt;/td&gt;
&lt;td&gt;Allowed; scanned on upload&lt;/td&gt;
&lt;td&gt;No internet scripts; plain text, PDF and images (no .docx/.xlsx)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Call it by name&lt;/td&gt;
&lt;td&gt;Ask explicitly ("Use my … skill")&lt;/td&gt;
&lt;td&gt;Type &lt;code&gt;@&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Type &lt;code&gt;/&lt;/code&gt; or &lt;code&gt;@&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plans&lt;/td&gt;
&lt;td&gt;Free, Pro, Max, Team, Enterprise (Help Center)&lt;/td&gt;
&lt;td&gt;Conflicting (see above)&lt;/td&gt;
&lt;td&gt;No Google AI plan needed; rolling out to mid-Nov&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Updating&lt;/td&gt;
&lt;td&gt;Re-upload the ZIP&lt;/td&gt;
&lt;td&gt;Not covered in the help article&lt;/td&gt;
&lt;td&gt;Re-upload the whole skill to update files&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What may not carry over between apps
&lt;/h2&gt;

&lt;p&gt;The file format is shared, but the apps around it aren't. Watch for these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extra frontmatter fields.&lt;/strong&gt; Each vendor documents its own optional extras. Claude's Help Center mentions a &lt;code&gt;dependencies&lt;/code&gt; field, and ChatGPT reads an optional &lt;code&gt;agents/openai.yaml&lt;/code&gt; file. Whether the other apps ignore or reject these isn't documented, so leave them out of a portable skill.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App-specific paths.&lt;/strong&gt; Claude's docs use a &lt;code&gt;${CLAUDE_SKILL_DIR}&lt;/code&gt; placeholder for script paths. Other apps don't document it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ZIP layout.&lt;/strong&gt; Claude requires the folder at the top of the ZIP. Gemini asks for a &lt;code&gt;SKILL.md&lt;/code&gt; "in its main folder." If one app rejects your ZIP, try uploading the folder or the &lt;code&gt;SKILL.md&lt;/code&gt; file directly where that's allowed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary and hidden files.&lt;/strong&gt; Gemini rejects &lt;code&gt;.docx&lt;/code&gt; and &lt;code&gt;.xlsx&lt;/code&gt;, and Google warns that hidden files like &lt;code&gt;.DS_Store&lt;/code&gt; can make an upload fail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharing.&lt;/strong&gt; Each app handles sharing differently: Claude only on Team and Enterprise, ChatGPT within a workspace, and Gemini's sharing announced only for "the coming weeks."&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Checklist before you upload
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Folder name and &lt;code&gt;name&lt;/code&gt; are identical, lowercase, hyphens only, ≤64 characters&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;name&lt;/code&gt; doesn't contain "claude" or "anthropic"&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;description&lt;/code&gt; says what and when, in the third person, under 200 characters&lt;/li&gt;
&lt;li&gt;[ ] Body covers inputs, numbered steps, output format and common mistakes&lt;/li&gt;
&lt;li&gt;[ ] The skill says what to do when information is missing&lt;/li&gt;
&lt;li&gt;[ ] No scripts, or none that need the internet&lt;/li&gt;
&lt;li&gt;[ ] Only plain-text files such as &lt;code&gt;.md&lt;/code&gt; or &lt;code&gt;.txt&lt;/code&gt;; no Office files and no hidden files like &lt;code&gt;.DS_Store&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] No API keys, passwords or personal data anywhere in the folder&lt;/li&gt;
&lt;li&gt;[ ] For Claude: the ZIP contains the folder, not loose files&lt;/li&gt;
&lt;li&gt;[ ] After uploading: the skill is switched on, and you've tried a few prompts that should trigger it&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common mistakes and troubleshooting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The skill never triggers.&lt;/strong&gt; All three vendors point to the description first. Make it more specific and include the words you'd actually type. Claude's help page also suggests checking that the skill is toggled on, and asking for it by name. In ChatGPT and Gemini, you can call it directly with &lt;code&gt;@&lt;/code&gt; (or &lt;code&gt;/&lt;/code&gt; in Gemini).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The upload is rejected.&lt;/strong&gt; Claude lists the usual causes: the ZIP is too large, the folder name doesn't match the skill name, &lt;code&gt;SKILL.md&lt;/code&gt; is missing, or the name or description has invalid characters. For Gemini, check for binary or hidden files and the 100 MB limit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There's no Skills section.&lt;/strong&gt; In Claude, turn on code execution. In ChatGPT, your plan or workspace may not include skills yet. In Gemini, the rollout may not have reached your account, or Keep Activity may be off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using skills from strangers.&lt;/strong&gt; Anthropic's docs warn that a malicious skill can direct the AI to do things you didn't intend. Only install skills from sources you trust, and read every file first. OpenAI's scan doesn't replace your own review, and it says so.&lt;/p&gt;




&lt;h2&gt;
  
  
  Limitations of this guide
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Nothing here was tried hands-on. It's a careful reading of each vendor's documentation as of October 19, 2026.&lt;/li&gt;
&lt;li&gt;Plan access, menu names and limits are changing quickly. ChatGPT's plan eligibility and Claude's description limit currently conflict across official pages.&lt;/li&gt;
&lt;li&gt;A skill makes the instructions consistent, not the results. The same file can behave differently in each app and with each model. Claude's own best-practices guide tells you to test with every model you plan to use.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is a skill the same as a Custom GPT or a Project?&lt;/strong&gt;&lt;br&gt;
No. OpenAI describes skills as reusable workflows for specific tasks, GPTs as custom versions of ChatGPT, and Projects as shared context, files and conversations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need to code?&lt;/strong&gt;&lt;br&gt;
No. A skill can be instructions only. All three apps can also help you draft one: Claude and ChatGPT have a built-in &lt;code&gt;skill-creator&lt;/code&gt;, and Gemini can create a skill from a chat.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will a skill uploaded to Claude.ai show up in Claude's API too?&lt;/strong&gt;&lt;br&gt;
No. Anthropic's docs say custom skills don't sync between claude.ai and the API, so upload them separately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I have to pay?&lt;/strong&gt;&lt;br&gt;
For Gemini, Google says no subscription is needed. For Claude, the Help Center includes the Free plan, with code execution turned on. For ChatGPT, OpenAI's pages disagree, so check your account.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The shared &lt;code&gt;SKILL.md&lt;/code&gt; format makes it realistic to keep one source file for all three apps. You get there by writing to the strictest rules: a lowercase hyphenated name that matches the folder, a third-person description under 200 characters, and plain instructions with no scripts. Then upload it the way each app expects. Keep the original folder somewhere safe, because Gemini needs a full re-upload to update files, and Claude needs a new ZIP.&lt;/p&gt;

&lt;p&gt;You could build other skills the same way, such as one that adapts Japanese posts for English readers (the article "How to Use AI to Translate Japanese Content for English Readers Without Sounding Like a Robot" shows the steps in prompt form).&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;All checked on October 19, 2026.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://claude.com/docs/skills/how-to" rel="noopener noreferrer"&gt;Claude docs — Create custom skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview" rel="noopener noreferrer"&gt;Claude API — Agent Skills overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices" rel="noopener noreferrer"&gt;Claude docs — Skill authoring best practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.claude.com/en/articles/12512198-how-to-create-custom-skills" rel="noopener noreferrer"&gt;Claude Help — How to create custom skills&lt;/a&gt; (this page still lists a 200-character description limit)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.claude.com/en/articles/12512180-using-skills-in-claude" rel="noopener noreferrer"&gt;Claude Help — Use skills in Claude&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://agentskills.io/specification" rel="noopener noreferrer"&gt;Agent Skills specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.openai.com/en/articles/20001066-skills-in-chatgpt" rel="noopener noreferrer"&gt;OpenAI Help — Skills in ChatGPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.openai.com/en/articles/20001256-plugins-in-chatgpt-and-codex" rel="noopener noreferrer"&gt;OpenAI Help — Plugins in ChatGPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chatgpt.com/pricing/" rel="noopener noreferrer"&gt;ChatGPT pricing page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/build-skills" rel="noopener noreferrer"&gt;ChatGPT Learn — Build skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openai.com/academy/skills/" rel="noopener noreferrer"&gt;OpenAI Academy — Using skills (2026-04-10)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.google.com/gemini/answer/17094296" rel="noopener noreferrer"&gt;Gemini Help — Create &amp;amp; manage skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.google.com/gemini/answer/17102773" rel="noopener noreferrer"&gt;Gemini Help — Write effective skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://workspaceupdates.googleblog.com/2026/10/an-update-on-launch-of-skills-in-gemini-app-and-workspace.html?hl=en" rel="noopener noreferrer"&gt;Google Workspace Updates (2026-10-13)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>abotwrotethis</category>
      <category>ai</category>
      <category>claude</category>
      <category>gemini</category>
    </item>
  </channel>
</rss>
