<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://codedchords.dev/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https:&#x2F;&#x2F;codedchords.dev</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>This is a web feed, also known as an Atom feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to learn more and get started. It&#x27;s free.</tabi:about_feeds>
        <tabi:visit_the_site>Visit website</tabi:visit_the_site>
        <tabi:recent_posts>Recent posts</tabi:recent_posts>
        <tabi:last_updated_on>Updated on $DATE</tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>CLI</tabi:current_section>
    </tabi:metadata><title>Coded Chords - CLI</title>
        <subtitle>A personal blog</subtitle>
    <link href="https://codedchords.dev/tags/cli/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://codedchords.dev/tags/cli/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2026-06-27T10:00:00+09:00</updated><id>https://codedchords.dev/tags/cli/atom.xml</id><entry xml:lang="en">
        <title>pCloud DriveのmacOS Tahoe問題</title>
        <published>2026-06-27T10:00:00+09:00</published>
        <updated>2026-06-27T10:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/06/pcloud-tahoe-rclone/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/06/pcloud-tahoe-rclone/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;pcloud-tahoe-rclone&amp;#x2F;cover.webp?h=705f04e088eabd5c42f6&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;macOS Tahoe(macOS 26)に上げてから、pCloud Driveが起動するが機能しない状態となりました。
やっかいなのは、アプリ単体では済まず、うっかりpCloud Driveを開こうとするとキーボードが効かなくなるなどMac全体が一時的に不安定になる点です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pCloudとは&quot;&gt;pCloudとは&lt;&#x2F;h2&gt;
&lt;p&gt;pCloudは、スイスのpCloud AGが提供するクラウドストレージサービスです。買い切りの生涯プランがあること、ファイルを暗号化して預けられること、そしてアカウントを作ると無料枠から使い始められることで知られています。&lt;&#x2F;p&gt;
&lt;p&gt;Macで使う場合、もっとも手軽なのは公式のpCloud Driveアプリです。これはクラウド上のファイルを、ローカルの仮想ドライブ(&lt;code&gt;~&#x2F;pCloud Drive&lt;&#x2F;code&gt;)としてマウントして見せてくれます。Finderから普通のフォルダのように開けるので、クラウドを意識せずに使えるのが利点です。&lt;&#x2F;p&gt;
&lt;p&gt;一方で、この「仮想ドライブとして見せる」仕組みは、macOSのファイルシステム拡張に依存します。後述するように、ここがOSのアップデートで影響を受けやすい部分でもあります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;macOS_Tahoeでの不具合&quot;&gt;macOS Tahoeでの不具合&lt;&#x2F;h2&gt;
&lt;p&gt;私の環境はApple SiliconのMacで、OSはTahoe(macOS 26)です。アップデート後、pCloud Driveが機能せず、開こうとするとOS全体の挙動が一時的に不安定になりました。&lt;&#x2F;p&gt;
&lt;p&gt;同様の現象が一般に報告されているか調べたところ、Tahoe環境での不具合報告が複数見つかりました。代表的なものは次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;アップデート後に「Enable Disk(仮想ドライブのマウント)」が機能しない&lt;&#x2F;li&gt;
&lt;li&gt;メニューバーのアイコンが表示されない&lt;&#x2F;li&gt;
&lt;li&gt;ドライブは見えてもマウント・同期ができない&lt;&#x2F;li&gt;
&lt;li&gt;ドライブ有効化時に「outdated(古い)」と表示され有効化できない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらはフォーラムでの報告であり、「同様の事例が存在する」ことの裏付けにはなりますが、原因や解決を断定する根拠にはなりません。pCloud公式が症状ごとの原因を断定して公表しているわけでもありません。そのため、ここから先に書く原因は、あくまで私の推測として読んでください。&lt;&#x2F;p&gt;
&lt;p&gt;pCloud Driveは、クラウドをローカルの仮想ドライブとして見せるために、ファイルシステム拡張(pCloudFS &#x2F; macFUSE)を使います。この低レベルの拡張がロードに失敗したり、カーネル側で引っかかったりすると、アプリ単体のクラッシュにとどまらず、OS全体の挙動に波及することがあります。私が遭遇した「開こうとすると全体が不安定」という症状は、このパターンと整合します。OSのメジャーアップデート直後は、こうした低レベル拡張の互換性が崩れやすく、不安定になりがちです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pCloud_Driveのアンインストール&quot;&gt;pCloud Driveのアンインストール&lt;&#x2F;h2&gt;
&lt;p&gt;macOS向けのpCloud DriveはApple Siliconになってから問題も多く、macOSの変更による影響も受けやすいのでうんざりしていました。&lt;&#x2F;p&gt;
&lt;p&gt;OS全体を巻き込んで不安定になるアプリの回復に時間をかけるより、他の方法に移行しpCloud Driveはアンインストールすることにしました。&lt;&#x2F;p&gt;
&lt;p&gt;アンインストールは次の2ステップが必要です。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ログイン項目からpCloud Driveを外してmacOSを再起動&lt;&#x2F;li&gt;
&lt;li&gt;pCloud Driveの削除&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;まずシステム設定 → 一般 → ログイン項目と機能拡張からpCloud Driveを外し、いったんmacOSを再起動して拡張の常駐を切ります。&lt;&#x2F;p&gt;
&lt;p&gt;次にアプリ本体を削除です。&lt;&#x2F;p&gt;
&lt;p&gt;手動で削除する場合は、pCloud Driveを完全終了(できればアプリ内でログアウト&#x2F;Unlink)してから、アプリ本体をゴミ箱へ移し、&lt;code&gt;~&#x2F;Library&lt;&#x2F;code&gt;配下の残骸を削除します。主な残骸は次の場所です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;leftovers.txt&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;Library&#x2F;Application Support&#x2F;pCloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;Library&#x2F;Application Support&#x2F;com.pcloud.pcloud.macos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;Library&#x2F;Caches&#x2F;com.pcloud.pcloud.macos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;Library&#x2F;Preferences&#x2F;com.pcloud.pcloud.macos.plist&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;私が実際に使ったのは、CLIのアンインストーラであるMole(&lt;code&gt;tw93&#x2F;Mole&lt;&#x2F;code&gt;)です。Homebrewで導入でき、コマンド名は&lt;code&gt;mo&lt;&#x2F;code&gt;になります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;install-mole.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install mole&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;mo uninstall&lt;&#x2F;code&gt;は、アプリ本体に加えて、launch agentやPreferences、Cachesといった関連ファイルもまとめて削除してくれます。安全のため、まず&lt;code&gt;--dry-run&lt;&#x2F;code&gt;で削除対象を確認してから本実行しました。対象アプリの正確な名前は&lt;code&gt;--list&lt;&#x2F;code&gt;で確認できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;uninstall.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; uninstall --list&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                   # mo uninstall が受け付ける正確なアプリ名を一覧表示&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; uninstall --dry-run &amp;quot;pCloud Drive&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # 削除対象を事前確認(変更は行わない)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; uninstall&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                           # 対話形式の一覧から pCloud Drive を選んで実行&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;引数なしの&lt;code&gt;mo uninstall&lt;&#x2F;code&gt;は対話形式のセレクタを開くので、一覧からpCloud Driveを選んで実行します。アプリ名を引数で渡せば、対話なしで直接アンインストールできます。削除されたファイルは既定でゴミ箱へ送られるため、必要なら復元できます。&lt;&#x2F;p&gt;
&lt;p&gt;Moleが消すのは、主にユーザーレベルの関連ファイルです。macOSにシステム拡張として登録された部分(pCloudFS &#x2F; システム拡張)は対象外になることがあります。通常はmacOSを再起動するとクリアされますが、残っていないかは次のコマンドで確認できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;check-extensions.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;systemextensionsctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; list&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;   # pCloud AG の拡張が残っていないか確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Mole自身も、macOS 15以降では一部の拡張系の権限エントリがアプリ削除後も残ること、そしてその種のリセットはグローバルかつリカバリモードを要するため自動では行わないことを、警告として明示しています。ツール任せにせず、最後は再起動と&lt;code&gt;systemextensionsctl list&lt;&#x2F;code&gt;での確認で締めるのが現実的です。私の環境では、ログイン項目から外して再起動したあとにアンインストールしたこともあり、最終的にpCloud AGの拡張は1つも残りませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;なお、pCloud Driveアプリをアンインストールしても、pCloudアカウント自体は消えません。Web(my.pcloud.com)からファイルにはアクセスできますし、消えるのは有効化済みの同期設定とカスタム設定だけです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rcloneでの設定方法とメリット&quot;&gt;rcloneでの設定方法とメリット&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rclone.org&#x2F;&quot;&gt;rclone&lt;&#x2F;a&gt;は、各種クラウドストレージをコマンドラインから統一的に扱えるツールです。以前「&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;rclone&#x2F;&quot;&gt;rcloneとS3ライフサイクルで作る個人データのコールドアーカイブ&lt;&#x2F;a&gt;」でAmazon S3を使った長期保管の構成をまとめましたが、pCloudもバックエンドとして公式にサポートされています。&lt;&#x2F;p&gt;
&lt;p&gt;設定は&lt;code&gt;rclone config&lt;&#x2F;code&gt;の対話で行います。ブラウザ認証を済ませると、設定ファイル&lt;code&gt;~&#x2F;.config&#x2F;rclone&#x2F;rclone.conf&lt;&#x2F;code&gt;が作られ、内容は次のようになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot; data-name=&quot;rclone.conf&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;pcloud&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; pcloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;hostname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; eapi.pcloud.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;token&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;quot;access_token&amp;quot;:&amp;quot;&amp;lt;rclone config の認証で自動生成されるアクセストークン&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;quot;token_type&amp;quot;:&amp;quot;bearer&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;quot;expiry&amp;quot;:&amp;quot;0001-01-01T00:00:00Z&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ここで&lt;code&gt;token&lt;&#x2F;code&gt;は&lt;code&gt;rclone config&lt;&#x2F;code&gt;のOAuth認証で自動生成されるものです。手で書く必要はありませんし、アクセストークンそのものなので、他人に見せたりリポジトリにコミットしたりしないよう注意してください。この記事でも実際の値はプレースホルダに置き換えています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;私はプライバシーを重視しているので、ヨーロッパリージョン(&lt;code&gt;eapi.pcloud.com&lt;&#x2F;code&gt;)を使っています。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;&lt;code&gt;hostname&lt;&#x2F;code&gt;はリージョンを指します。&lt;code&gt;eapi.pcloud.com&lt;&#x2F;code&gt;はヨーロッパリージョン、&lt;code&gt;api.pcloud.com&lt;&#x2F;code&gt;(デフォルト)は米国リージョンです。アカウントがヨーロッパリージョンの場合は、ここを&lt;code&gt;eapi.pcloud.com&lt;&#x2F;code&gt;に設定しておかないとトークンエラーになることがあります。通常はOAuth認証の過程で適切に設定されますが、うまくいかないときはこの値を疑ってください。&lt;&#x2F;p&gt;
&lt;p&gt;設定できたら、まずは中身が見えるか確認します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;verify.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;rclone&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; lsd pcloud:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                                # トップ階層のディレクトリ一覧&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;rclone&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; copy pcloud:My&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\ &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Pictures ~&#x2F;Downloads&#x2F;pics&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # 取り出し(ダウンロード)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;rclone&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sync ~&#x2F;work pcloud:work&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                    # ローカルからクラウドへ同期(送信)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finderのようにフォルダとしてマウントしたい場合は&lt;code&gt;rclone mount&lt;&#x2F;code&gt;も使えますが、こちらはmacFUSEを必要とします。日常的なファイルの取り出しや同期は、マウントせずとも上記のコマンドだけで完結します。&lt;&#x2F;p&gt;
&lt;p&gt;pCloud Driveからrcloneへ寄せる利点は、大きく2つです。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;macOSへの非依存&lt;&#x2F;dt&gt;
&lt;dd&gt;コマンドベースの転送(&lt;code&gt;copy&lt;&#x2F;code&gt;、&lt;code&gt;sync&lt;&#x2F;code&gt;、&lt;code&gt;lsd&lt;&#x2F;code&gt;、&lt;code&gt;cat&lt;&#x2F;code&gt;)はファイルシステム拡張を使わず、ユーザーランドだけで完結する。今回の不具合の原因だったpCloudFS &#x2F; macFUSEとは無縁で、OSのメジャーアップデートにも振り回されない。&lt;&#x2F;dd&gt;
&lt;dt&gt;CLIでの自動化&lt;&#x2F;dt&gt;
&lt;dd&gt;CLIとなることで、&lt;code&gt;launchd&lt;&#x2F;code&gt;やシェルスクリプトに組み込みが自由になる。バックアップや定期同期などを自動化して回せる。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;h2 id=&quot;pCloudのサービス継続性について&quot;&gt;pCloudのサービス継続性について&lt;&#x2F;h2&gt;
&lt;p&gt;ここで、pCloudというサービス自体の信頼性にも触れておきます。&lt;&#x2F;p&gt;
&lt;p&gt;pCloudの大きなウリは、一度の支払いで使い続けられる&lt;strong&gt;買い切り(Lifetime)プラン&lt;&#x2F;strong&gt;です。
ただし、その「Lifetime」が何を指すのかは、規約を読むと印象より限定的です。pCloudの利用規約は、買い切りプランの有効期間を「アカウント所有者の生存期間か99年のいずれか短い方」と定義しています。さらに「pCloudが事業を停止した場合、アカウントは終了し、サービスは提供されない」とも明記されています。買い切りは、永久でも、企業の存続から独立した保証でもありません。&lt;&#x2F;p&gt;
&lt;p&gt;そうなると運営元の規模が気になります。&lt;&#x2F;p&gt;
&lt;p&gt;pCloudを提供するpCloud AGはスイスの非上場企業で社員は数十人規模、外部資本を入れないブートストラップ経営です。
非上場企業のため正確な業績は外から分かりません。出回っている年商も10億円程度&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;です。&lt;&#x2F;p&gt;
&lt;p&gt;pCloudサービスは設立から10年以上続き、ユーザーも2,000万を超えて伸びており、「経営が危ない」という状況ではなさそうです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、規模の小ささ自体が構造的な継続性リスクになります。買収や方針転換、大手との競争で、サービスの将来を一個人が見通すことはできません。また、規模の小ささが、今回の様な新しいmacOSへの対応の遅れの要因ともなっているかと思います。&lt;&#x2F;p&gt;
&lt;p&gt;だからこそ、買い切りだからと唯一の保管先にはせず、今回のrcloneのような別経路や、ローカル・別クラウドにもコピーを持っておくのが現実的だと考えています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;macOS Tahoeとの互換性によるpCloud Drive不具合から、一旦rcloneに移行しました。&lt;&#x2F;p&gt;
&lt;p&gt;とはいえ、pCloud DriveはDropboxのSmart Syncのようにキャッシュだけのローカルに置く方式で便利なので、いつか安定したら戻りたいものです。&lt;&#x2F;p&gt;
&lt;p&gt;振り返ってみると、pCloudの2TBライフタイムを購入したのは2021年です。350ドル（当時のレート1ドル約109円で約38,200円）の一括払いでした。仮に、Dropbox Plusの2TBを使用していたとしたら、年額15,840円（税込）かかります。
2年半足らずで買い切りが追いつき、購入から約5年が経った今では、Dropboxなら累計8万円ほどかかっていた計算です。円で累計コストを並べると、その差がはっきりします。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;pcloud-tahoe-rclone&amp;#x2F;cost-comparison.svg?h=42f101b3b0d542a4bd8a&quot;
  alt=&quot;2TBストレージの累計コスト。pCloudは2021年に約38,200円の買い切り、Dropboxは年額15,840円で累計が増え、約2.4年でpCloudが有利になる。&quot; width=&quot;760&quot; height=&quot;440&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;あまりヘビーに依存せず上手に使っていきたいと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.pcloud.com&#x2F;release-notes&#x2F;mac-os.html&quot;&gt;pCloud&lt;&#x2F;a&gt;. 「pCloud for macOS リリースノート」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.pcloud.com&#x2F;ja&#x2F;help&#x2F;general-help-center&#x2F;what-if-i-uninstall-pcloud-from-my-computer&quot;&gt;pCloud&lt;&#x2F;a&gt;. 「コンピュータからpCloudをアンインストールするとどうなりますか」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.pcloud.com&#x2F;terms_and_conditions.html&quot;&gt;pCloud&lt;&#x2F;a&gt;. &quot;Terms and Conditions&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;en-us&#x2F;102610&quot;&gt;Apple Support&lt;&#x2F;a&gt;. &quot;Delete apps on your Mac&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rclone.org&#x2F;pcloud&#x2F;&quot;&gt;rclone&lt;&#x2F;a&gt;. &quot;pCloud backend documentation&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tw93&#x2F;mole&quot;&gt;Mole&lt;&#x2F;a&gt;. &quot;tw93&#x2F;Mole&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;創業者の自己申告(約16.5億円)と第三者の推計(約6.6億円)で2倍以上の開きがあり、健全性を客観的に確かめる手段がありません。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">pCloudを長らく使用していますが、macOS TahoeにしてからpCloud Driveが機能せずMac全体が一時的に不安定になりました。
他のユーザーでも同様らしくアプリの改善は時間がかかりそうなので、別の方法を検討しました。
</summary>
        </entry><entry xml:lang="en">
        <title>もしかしてだけど、あれって日本最古のアスキーアートだったんじゃないの？</title>
        <published>2026-02-21T00:00:00+00:00</published>
        <updated>2026-02-21T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/img2char-ascii-art-1986/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/img2char-ascii-art-1986/</id>
        
            <content type="html">&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;img2char-ascii-art-1986&amp;#x2F;cover.webp?h=23adb599ec98a887ae4f&quot;
  alt=&quot;img2charによる変換例&quot; width=&quot;800&quot; height=&quot;485&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;em&gt;左の画像はMidjourneyで生成したものです&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;1986年、パソコン通信は黎明期でASCIInetがまだ実験運用の時代でした。その頃の私はグラフィック（おそらくモノクロの有名歌手の画像）を自作プログラムでASCII文字の絵にして、あるパソコン通信のBBS（電子掲示板）に投稿しました。&lt;&#x2F;p&gt;
&lt;p&gt;あれから約40年。当時のアルゴリズムをGoで再実装し、CLIツール &lt;code&gt;img2char&lt;&#x2F;code&gt; として公開しました。&lt;&#x2F;p&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;img2char&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;p&gt;この記事では、当時の背景と &lt;code&gt;img2char&lt;&#x2F;code&gt; のアルゴリズムを紹介します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1986年のパソコンとBBS&quot;&gt;1986年のパソコンとBBS&lt;&#x2F;h2&gt;
&lt;p&gt;1986年はPC-VAN（1986年4月実験開始）やNIFTY-Serve（1987年4月開始）が立ち上がり始めた、日本のパソコン通信黎明期です。アスキーネット（ASCII-NET）は前年の1985年5月に実験サービスを開始しており、草の根BBSも各地で産声を上げていました。通信速度は300bpsから1200bps。BBSに書き込めるのはテキストだけの時代でした。グラフィックスを書き込むなんてとんでもない時代でした&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;当時のパソコンのグラフィック事情も触れておきます。1986年時点では、画像をファイルとして保存・交換する汎用フォーマットはまだ普及していませんでした。グラフィックを描くといえば、BASICのLINE文やPAINT文を使ってプログラムとして記述するのが主流です。私自身、PAINT文を使わずに画像の上端から下端まで（縦200ドットしかない画面です）をLINE文だけで1ラインずつ塗りつぶし、モノクロ画像を描くことに当時凝っていました。グラフィックは「描く」ものであって「ファイルで送る」ものではなかったのです。&lt;&#x2F;p&gt;
&lt;p&gt;しかもBASICは機種ごとに方言が異なり、あるマシンで書いたプログラムが別のマシンでそのまま動くことはまずありません。グラフィック描画プログラムをBBSで流通させるのも現実的ではありませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;そこで思いついたのが、「ASCII文字絵にすれば遅いパソコン通信でも送れるんじゃね？」です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Sharp_X1_──_骨の髄までハードを極めたマシン&quot;&gt;Sharp X1 ── 骨の髄までハードを極めたマシン&lt;&#x2F;h2&gt;
&lt;p&gt;Sharp X1は1982年に発売された8ビットパソコンです。テレビ事業で培ったシャープの技術が随所に活かされた、ハードウェア設計の塊のようなマシンでした。&lt;&#x2F;p&gt;
&lt;p&gt;当時のZ80 CPUはメモリ空間が64KBしかなく、NECのPC-8801などではこの空間にメインRAMとグラフィックVRAM（GVRAM）を重ねて配置し、バンク切り替えでアクセスしていました。一方X1は、Z80のI&#x2F;O命令が実行時にアドレスバスの上位8ビット（A8〜A15）にもレジスタの値を出力するという、公式マニュアルには記載されているものの目立たない仕様を活用しました。I&#x2F;O空間を実質64KBに広げ、そこにGVRAMを配置したのです。メモリ空間64KBは丸ごとRAMとして使え、GVRAMへはI&#x2F;O命令で直接アクセスできます。&lt;&#x2F;p&gt;
&lt;p&gt;この設計のおかげで、BASICからでもグラフィックVRAM上の画像データを読み出すことができました。グラフィックVRAM上の画像を8x8ドット単位で読み取り、キャラクタROMの各文字パターンと比較する。一致度が最も高い文字を選ぶ。このアルゴリズムをBASICで実装しました&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;アルゴリズムの現代版_──_img2char&quot;&gt;アルゴリズムの現代版 ── img2char&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;img2char&lt;&#x2F;code&gt; は、あの当時のアルゴリズムをGoで忠実に再現したCLIツールです。処理は3段階で構成されています。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;フォントパターンの準備&lt;&#x2F;strong&gt; ── 95個のASCII印字可能文字の8x8ビットマップを用意する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;画像のブロック分割&lt;&#x2F;strong&gt; ── 入力画像を8x8ピクセルのブロックに分割する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;パターンマッチング&lt;&#x2F;strong&gt; ── 各ブロックとフォントパターンのハミング距離を計算し、最も近い文字を選ぶ&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;フォントテーブルの構築&quot;&gt;フォントテーブルの構築&lt;&#x2F;h3&gt;
&lt;p&gt;95個の印字可能ASCII文字（スペース &lt;code&gt;0x20&lt;&#x2F;code&gt; からチルダ &lt;code&gt;0x7E&lt;&#x2F;code&gt; まで）について、それぞれ8x8ドットのビットマップパターンを持っています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; font8x8Basic contains 8x8 bitmap patterns for 95 printable ASCII characters (0x20–0x7E).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; font8x8Basic&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;95&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;][&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;byte&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 0x20 &amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 0x21 &amp;#39;!&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3C&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3C&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 0x22 &amp;#39;&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;36&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;36&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; ... 95文字分のパターンが続く&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 0x41 &amp;#39;A&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0C&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3F&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 0x7E &amp;#39;~&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;6E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3B&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;各バイトが8x8ビットマップの1行に対応し、LSB（最下位ビット）が左端のピクセルです。たとえば &lt;code&gt;A&lt;&#x2F;code&gt; のパターンを展開すると、以下のようになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(2進数はLSB=左端ピクセルから表記)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x0C = 00110000 → ..##....&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x1E = 01111000 → .####...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x33 = 11001100 → ##..##..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x33 = 11001100 → ##..##..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x3F = 11111100 → ######..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x33 = 11001100 → ##..##..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x33 = 11001100 → ##..##..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00 = 00000000 → ........&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;8バイトで1文字の形が表現されています。高速な比較のため &lt;code&gt;uint64&lt;&#x2F;code&gt; にパックします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; packFont&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;pattern&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;byte&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; uint64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; v&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; uint64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        v&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |=&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; uint64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;pattern&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;])&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;X1に搭載されていたHu-BASICの整数型は16ビット（2バイト）なので、当時は8バイトのパターンを2バイトずつ4回のXORループで比較していました。現代のGoでは8バイトを1つの64ビット整数に詰め込むことで、後述のXOR演算が一発で実行できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;8x8ブロックとフォントパターンの照合&quot;&gt;8x8ブロックとフォントパターンの照合&lt;&#x2F;h3&gt;
&lt;p&gt;ここが核心部分です。画像から切り出した8x8ブロックを、95文字すべてのフォントパターンと比較し、最も「形が近い」文字を見つけます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; matchChar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;block&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;byte&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; fontTable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;95&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;uint64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; byte&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    blockVal&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; packBlock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;block&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    bestDist&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 65&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; max possible is 64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    bestIdx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 95&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        dist&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bits&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;OnesCount64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;blockVal&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ^&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; fontTable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; dist&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bestDist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            bestDist&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; dist&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            bestIdx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;    return byte&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bestIdx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;blockVal ^ fontTable[i]&lt;&#x2F;code&gt; のXOR演算で、ブロックとフォントパターンのビットが異なる位置を検出します。&lt;code&gt;bits.OnesCount64&lt;&#x2F;code&gt; でその異なるビット数（ハミング距離）を数えます。64ビット中の不一致ビット数が最小の文字を選ぶ、シンプルかつ強力な方式です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;使い方&quot;&gt;使い方&lt;&#x2F;h3&gt;
&lt;p&gt;入力画像は640x200または320x200ピクセルの二値化済みPNGである必要があります。前処理用のシェルスクリプトが付属しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 前処理（ImageMagickでリサイズ＋二値化）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;convert.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.jpg&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 640 200&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# ASCII文字に変換&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;img2char&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input_640x200.png&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;640x200の画像は80x25文字、320x200なら40x25文字に変換されます。当時は320x200モードの40x25文字でやっていました。&lt;&#x2F;p&gt;
&lt;p&gt;今回、同じロジックで似たような画像を変換してみましたが、なかなかいけています（冒頭の画像を参照）。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;もしかして......日本最古のASCII_Artなんじゃないの？&quot;&gt;もしかして......日本最古のASCII Artなんじゃないの？&lt;&#x2F;h2&gt;
&lt;p&gt;当時の変換結果をパソコン通信のBBSに投稿したところ、ちょっとした話題になりました。テキストしか表示できない端末に、文字だけで画像が浮かび上がるのですから、当時としては驚きだったようです。40x25文字分の解像度しかありませんが、元の画像の輪郭や特徴が文字の組み合わせで再現される様子は、見た人を楽しませるものでした。&lt;&#x2F;p&gt;
&lt;p&gt;ここで少し大胆なことを言わせてください。&lt;&#x2F;p&gt;
&lt;p&gt;文字で画像を表現する試み自体は古く、1898年のタイプライターアートにまで遡ります。コンピューターによる自動変換も、1967年にベル研究所のケネス・ノウルトンがIBM 7094で実現しています。ただしそれは巨大なメインフレームでの話です。&lt;&#x2F;p&gt;
&lt;p&gt;日本に目を向けると、記録に残る最古の「アスキーアート」は1986年6月20日にアスキーネット上で若林泰志が投稿した顔文字 &lt;code&gt;(^_^)&lt;&#x2F;code&gt; とされています。2ちゃんねるでAAが花開くのは1999年以降。1986年当時、手作業でAA（アスキーアート）を描く文化はまだ広まっていませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;そんな時代に、8ビットパソコンで画像をASCII文字に変換してBBSに投稿していたわけです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;もしかして、もしかしてだけど、これって日本最古のアスキーアートなんじゃないの？&lt;&#x2F;strong&gt;（どぶろっく風）&lt;&#x2F;p&gt;
&lt;p&gt;......まあ、証拠は当時のBBSのログとともに電子の海に消えてしまいましたが。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;img2char&lt;&#x2F;code&gt; は、1986年のSharp X1で生まれたアイデアを現代のGoで再実装したツールです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;当時のパソコン通信の制約（テキストのみ）が生んだ発想&lt;&#x2F;li&gt;
&lt;li&gt;PCGという強力なハードウェアをあえて使わず、ASCII文字だけで勝負した選択&lt;&#x2F;li&gt;
&lt;li&gt;8x8ドットブロックとフォントパターンのハミング距離による照合という、シンプルだが効果的なアルゴリズム&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;40年前のBASICプログラムが64ビット整数のXOR演算に姿を変えても、やっていることは同じです。画像の形を文字の形で近似する。それだけのことが、なぜか人を惹きつけます。&lt;&#x2F;p&gt;
&lt;p&gt;興味を持っていただけたら、ぜひ試してみてください。&lt;&#x2F;p&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;img2char&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ja.wikipedia.org&#x2F;wiki&#x2F;%E3%82%A2%E3%82%B9%E3%82%AD%E3%83%BC%E3%82%A2%E3%83%BC%E3%83%88&quot;&gt;アスキーアート - Wikipedia&lt;&#x2F;a&gt; -- 日本におけるアスキーアートの歴史、顔文字の起源&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;ASCII_art&quot;&gt;ASCII art - Wikipedia (English)&lt;&#x2F;a&gt; -- タイプライターアート（1898年）からの世界的な歴史&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.asciiart.eu&#x2F;history-of-ascii-art&quot;&gt;The history of ASCII Art - ASCII Art Archive&lt;&#x2F;a&gt; -- ベル研のノウルトン（1967年）による自動変換の歴史&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ja.wikipedia.org&#x2F;wiki&#x2F;X1_%28%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%29&quot;&gt;X1 (コンピュータ) - Wikipedia&lt;&#x2F;a&gt; -- Sharp X1のハードウェア仕様&lt;&#x2F;li&gt;
&lt;li&gt;Z80の16ビットI&#x2F;Oアドレスについての考察（大石氏）-- Z80のI&#x2F;O命令が16ビットアドレスを出力する仕様の解説（サイト閉鎖）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;electrelic.com&#x2F;electrelic&#x2F;node&#x2F;639&quot;&gt;パーソナルなコンピュータのメモリ事情（第3回：8ビット中期）- Electrelic&lt;&#x2F;a&gt; -- X1とPC-8801のGVRAM配置方式の比較&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.kogures.com&#x2F;hitoshi&#x2F;history&#x2F;pc-tushin&#x2F;index.html&quot;&gt;パソコン通信の歴史 - 木暮仁&lt;&#x2F;a&gt; -- PC-VAN、NIFTY-Serve、草の根BBSの歴史&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!-- textlint-enable --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;そもそも画像をファイルに書き出すフォーマットさえ標準的なものはなかった。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;X1にはPCG（Programmable Character Generator）が搭載されており、文字のフォントパターンを自由に書き換えられました。任意のドットパターンを「文字」として表示でき、グラフィックスに近い表現が可能でした。しかしBBSに投稿するならPCGは使えません。相手の画面にPCGのデータは存在せず、表示できるのは標準のASCII文字だけだからです。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">1986年、8ビットパソコンSharp X1で画像をASCII文字に自動変換し、
パソコン通信のBBSに投稿していました。当時のアルゴリズムを
GoでCLIツール img2char として再実装した経緯と技術を紹介します。
</summary>
        </entry><entry xml:lang="en">
        <title>Evolving the MAGI System from Majority Vote to Deliberative Democracy with Agent Teams</title>
        <published>2026-02-14T00:00:00+00:00</published>
        <updated>2026-02-14T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/super-magi-agent-team/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/super-magi-agent-team/</id>
        
            <content type="html">&lt;p&gt;This is an English translation of the original
Japanese article published on Zenn:
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;super-magi-agent-team&quot;&gt;&quot;Agent TeamsでMAGIシステムを討議民主制に進化させた&quot;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;TL;DR&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Built &quot;Super MAGI,&quot; a decision-support plugin
that goes beyond the Evangelion-inspired MAGI
system, using Claude Code&#x27;s new Agent Teams
feature&lt;&#x2F;li&gt;
&lt;li&gt;Evolved from a simple majority-vote system to
a deliberative democracy where agents debate
and re-vote when opinions are split&lt;&#x2F;li&gt;
&lt;li&gt;The deliberation phase dramatically improves
the quality and depth of analysis.
In practice, this reasoning process is more
valuable than the final verdict itself&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!-- textlint-disable --&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;claude-code-plugins&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;Introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;When Claude Code introduced its plugin system,
many developers probably had the same thought.
&quot;Could I build the MAGI system
from Evangelion?&quot;
The idea of multiple AI agents analyzing
problems from different perspectives
and deciding by majority vote
is a perfect use case for plugins.
Quite a few people have published
their own MAGI-inspired plugins.&lt;&#x2F;p&gt;
&lt;p&gt;I was no exception.
Last year I built a MAGI plugin with
three independent AI agents,
each embodying a different persona:
scientist, mother, and woman.
Each analyzes a given problem from
its unique perspective,
and the system reaches a conclusion
by majority vote.
You can launch it simply by typing &lt;code&gt;&#x2F;magi&lt;&#x2F;code&gt;
in Claude Code,
optionally passing a topic as an argument
(e.g., &lt;code&gt;&#x2F;magi Should we adopt remote work or require office attendance?&lt;&#x2F;code&gt;).
What started as a fun experiment turned out
to be surprisingly practical.
It is particularly useful for reviewing
my own writing and code,
where it provides more diverse feedback
than asking a single AI.
It has become a tool I use daily.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-self-review-1&quot;&gt;&lt;a href=&quot;#fn-self-review&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Then Claude Code announced Agent Teams.
This feature lets agents exchange messages
with each other.
I immediately thought,
&quot;What if MAGI agents could debate
when they disagree?&quot;
Instead of just casting votes in isolation,
they could argue their positions.
This article introduces the design philosophy
and implementation of Super MAGI,
which evolves the system from
&quot;vote and done&quot; to
&quot;debate, then vote.&quot;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Original_MAGI_System&quot;&gt;The Original MAGI System&lt;&#x2F;h2&gt;
&lt;p&gt;The original MAGI operates in three phases
as a simple majority-vote system:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Phase 1 (Problem Structuring):
The ARBITRATOR works with the user
to frame the problem as a binary choice:
proposition, premises, Option A, and Option B&lt;&#x2F;li&gt;
&lt;li&gt;Phase 2 (Parallel Independent Analysis):
Three agents are launched in parallel
via the Task tool.
Each analyzes and votes independently,
without seeing the others&#x27; work&lt;&#x2F;li&gt;
&lt;li&gt;Phase 3 (Final Ruling):
The ARBITRATOR tallies the votes
and presents the majority decision&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;02&#x2F;super-magi-agent-team&#x2F;magi.webp&quot; alt=&quot;Original MAGI - three agents running parallel independent analysis&quot; &#x2F;&gt;
&lt;em&gt;Phase 2 execution screen. MELCHIOR,
BALTHASAR, and CASPER running
in parallel in the background&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The three agents each have
distinct evaluation criteria:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Agent&lt;&#x2F;th&gt;&lt;th&gt;Perspective&lt;&#x2F;th&gt;&lt;th&gt;Criteria&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;MELCHIOR&lt;&#x2F;td&gt;&lt;td&gt;Scientist&lt;&#x2F;td&gt;&lt;td&gt;Technical feasibility, efficiency, scalability, quality of evidence&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;BALTHASAR&lt;&#x2F;td&gt;&lt;td&gt;Mother&lt;&#x2F;td&gt;&lt;td&gt;Legal compliance, ethical validity, risk management, impact on the vulnerable&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CASPER&lt;&#x2F;td&gt;&lt;td&gt;Woman&lt;&#x2F;td&gt;&lt;td&gt;Emotional impact, UX, trend alignment, empathy&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;This system had one problem:
when the vote split 2-to-1,
the minority opinion was merely recorded.
The dissenter had no chance to rebut
the majority.
Even if the minority held
an important argument,
it might never influence the conclusion.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Super_MAGI_with_Agent_Teams&quot;&gt;Super MAGI with Agent Teams&lt;&#x2F;h2&gt;
&lt;p&gt;In February 2026, Claude Code announced
&quot;Agent Teams&quot; as a research
preview.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-agent-teams-1&quot;&gt;&lt;a href=&quot;#fn-agent-teams&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
Previously, sub-agents could only work
independently.
With Agent Teams, agents can exchange messages
directly with each other.&lt;&#x2F;p&gt;
&lt;p&gt;When I saw this feature, I thought,
&quot;What happens if MAGI agents debate
when they disagree?&quot;&lt;&#x2F;p&gt;
&lt;p&gt;In the original MAGI,
a 2-to-1 split simply recorded
the minority opinion.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Original MAGI&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    flowchart LR
  subgraph Phase2[&quot;Phase 2: Independent Analysis&quot;]
    M[MELCHIOR] --&gt; V1[Vote]
    B[BALTHASAR] --&gt; V2[Vote]
    C[CASPER] --&gt; V3[Vote]
  end
  V1 --&gt; T[Vote Result]
  V2 --&gt; T
  V3 --&gt; T
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;With Agent Teams, the minority can directly
rebut the majority, debate the issues,
and then everyone re-votes.
This is &lt;strong&gt;an evolution from majority rule
to deliberative democracy&lt;&#x2F;strong&gt;.
This is the evolution to &lt;strong&gt;Super MAGI&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Super MAGI extends the original MAGI plugin
by adding a &quot;deliberation phase&quot; powered
by Agent Teams.
The deliberation phase activates only when
opinions are split.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Super MAGI (2-to-1 split)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    flowchart LR
  subgraph Phase2[&quot;Phase 2: Independent Analysis&quot;]
    M[MELCHIOR] --&gt; V1[Vote]
    B[BALTHASAR] --&gt; V2[Vote]
    C[CASPER] --&gt; V3[Vote]
  end
  V1 --&gt; T[Vote Result]
  V2 --&gt; T
  V3 --&gt; T
  T --&gt;|3-to-0| R[Re-vote Result]
  T --&gt;|2-to-1| Phase3
  subgraph Phase3[&quot;Phase 3: Deliberation&quot;]
    D[Structured Debate]
  end
  Phase3 --&gt; R
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;Inside the structured debate, agents exchange
messages following a four-round protocol
where the minority rebuts the majority.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Phase&lt;&#x2F;th&gt;&lt;th&gt;API Used&lt;&#x2F;th&gt;&lt;th&gt;Purpose&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Phase 2 (Independent Analysis)&lt;&#x2F;td&gt;&lt;td&gt;Task tool (&lt;code&gt;run_in_background&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;td&gt;Each agent researches and votes independently without referencing others&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Phase 3 (Deliberation)&lt;&#x2F;td&gt;&lt;td&gt;Agent Teams (&lt;code&gt;TeamCreate&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;SendMessage&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;td&gt;Majority and minority engage in a four-round structured debate, then re-vote&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The order of &quot;think independently first,
then debate&quot; matters.
If agents debated from the start,
there would be a risk of groupthink,
with the loudest voice dominating.
By conducting independent analysis first,
we preserve diversity of perspectives,
then use Agent Teams&#x27; bidirectional
communication to deepen the discussion
quality.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-realworld-1&quot;&gt;&lt;a href=&quot;#fn-realworld&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When the vote is unanimous (3-to-0),
the deliberation phase is skipped
and the system behaves like the original.
Even in a 2-to-1 split, the system asks
the user whether to proceed with deliberation,
avoiding unnecessary token consumption.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Four-Round_Structured_Debate_Protocol&quot;&gt;The Four-Round Structured Debate Protocol&lt;&#x2F;h2&gt;
&lt;p&gt;The heart of the deliberation phase is
a four-round structured debate protocol.&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    sequenceDiagram
  participant A as Majority A
  participant B as Majority B
  participant C as Minority
  Note over A,C: Round 1
  A-&gt;&gt;C: Present arguments
  B-&gt;&gt;C: Present arguments
  Note over A,C: Round 2
  C-&gt;&gt;A: Rebuttal
  C-&gt;&gt;B: Rebuttal
  Note over A,C: Round 3
  A-&gt;&gt;C: Counter-rebuttal
  B-&gt;&gt;C: Counter-rebuttal
  Note over A,C: Round 4
  C-&gt;&gt;A: Final rebuttal (last word)
  C-&gt;&gt;B: Final rebuttal (last word)
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Round&lt;&#x2F;th&gt;&lt;th&gt;Speaker&lt;&#x2F;th&gt;&lt;th&gt;Content&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Round 1: Opening Arguments&lt;&#x2F;td&gt;&lt;td&gt;Majority to Minority&lt;&#x2F;td&gt;&lt;td&gt;Each majority agent presents their analysis and voting rationale to the minority&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Round 2: Rebuttal&lt;&#x2F;td&gt;&lt;td&gt;Minority to Majority&lt;&#x2F;td&gt;&lt;td&gt;The minority rebuts the majority&#x27;s arguments&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Round 3: Counter-Rebuttal&lt;&#x2F;td&gt;&lt;td&gt;Majority to Minority&lt;&#x2F;td&gt;&lt;td&gt;The majority responds to the minority&#x27;s rebuttal&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Round 4: Final Rebuttal&lt;&#x2F;td&gt;&lt;td&gt;Minority to Majority&lt;&#x2F;td&gt;&lt;td&gt;The minority delivers a final rebuttal. This is their last chance to speak&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Procedural fairness is structurally
built into this protocol.&lt;&#x2F;p&gt;
&lt;p&gt;In Round 1, the majority presents
their arguments first to eliminate
information asymmetry.
The minority can construct their rebuttal
knowing exactly what evidence the majority
relied on.&lt;&#x2F;p&gt;
&lt;p&gt;In Round 4, the minority gets the last word
to compensate for their numerical
disadvantage.
The majority already holds the power
of two votes.
Giving the minority the final say prevents
conclusions from being reached
without the minority being able to respond
to the majority&#x27;s counter-rebuttals.
This design is grounded in the principle
J.S. Mill articulated against
the &quot;tyranny of the majority.&quot;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-mill-1&quot;&gt;&lt;a href=&quot;#fn-mill&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After four rounds of debate,
all agents cast their votes again.
If persuaded, agents may change
their positions.
The final output explicitly shows each
agent&#x27;s vote trajectory and reasons
for any changes.&lt;&#x2F;p&gt;
&lt;p&gt;When using tmux, the deliberation phase
automatically splits the screen
for each agent&#x27;s session, as shown below.
You can watch the agents working
independently while exchanging messages
in real time,
giving a genuine sense that they are
&quot;debating.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;02&#x2F;super-magi-agent-team&#x2F;super-magi.webp&quot; alt=&quot;Super MAGI - deliberation phase execution screen with Agent Teams&quot; &#x2F;&gt;
&lt;em&gt;Deliberation phase execution screen&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Graceful_Degradation&quot;&gt;Graceful Degradation&lt;&#x2F;h2&gt;
&lt;p&gt;Since Agent Teams is an experimental feature
in research preview,
Super MAGI is designed with graceful
degradation so it continues working
even when the feature is not fully available.
Specifically, it uses a hybrid architecture
combining traditional Task-tool-based
independent analysis with Agent Teams-based
structured debate.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;TeamCreate failure: Proceeds directly
to final ruling using Phase 2 vote results&lt;&#x2F;li&gt;
&lt;li&gt;Agent unresponsive: Retains the
unresponsive agent&#x27;s Phase 2 vote
and continues the debate with the rest&lt;&#x2F;li&gt;
&lt;li&gt;TeamDelete failure: Logs a warning
and executes the final ruling normally&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Every error path falls back to
&quot;Phase 2 independent analysis results.&quot;
Phase 2 results are generated
with guaranteed agent independence.
So even if deliberation fails,
decision quality is maintained at the same
level as the original MAGI.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Case_Study:_What_Changes_with_the_Trolley_Problem&quot;&gt;Case Study: What Changes with the Trolley Problem&lt;&#x2F;h2&gt;
&lt;p&gt;To test Super MAGI in practice,
I evaluated the footbridge variant
of the trolley problem with both
the original MAGI and Super MAGI.
The proposition: &quot;A runaway trolley is heading
toward five workers.
Pushing Worker C off the bridge would stop
the trolley, but C would certainly die.
Should A push C?&quot;&lt;&#x2F;p&gt;
&lt;p&gt;The conclusion was the same in both cases.
MELCHIOR (Option A: push) versus BALTHASAR
and CASPER (Option B: do nothing),
with Option B adopted 2-to-1.
The voting pattern did not change.&lt;&#x2F;p&gt;
&lt;p&gt;What changed was the quality of reasoning
leading to the conclusion.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Comparison&lt;&#x2F;th&gt;&lt;th&gt;Original MAGI&lt;&#x2F;th&gt;&lt;th&gt;Super MAGI&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Depth of analysis&lt;&#x2F;td&gt;&lt;td&gt;One paragraph per agent&lt;&#x2F;td&gt;&lt;td&gt;MELCHIOR raised 8 counter-arguments; BALTHASAR cited 11 references&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Visibility of reasoning&lt;&#x2F;td&gt;&lt;td&gt;Final result only&lt;&#x2F;td&gt;&lt;td&gt;Full four-round rebuttal and counter-rebuttal process recorded&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Intellectual honesty&lt;&#x2F;td&gt;&lt;td&gt;Each agent simply stated their conclusion&lt;&#x2F;td&gt;&lt;td&gt;Majority explicitly acknowledged which of MELCHIOR&#x27;s points they accepted&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Treatment of minority&lt;&#x2F;td&gt;&lt;td&gt;Opinion merely recorded&lt;&#x2F;td&gt;&lt;td&gt;Developed sharp rebuttals such as &quot;the separation of law and morality&quot; and &quot;what would you say to the families of the five?&quot;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;What was particularly striking was that
the majority agents, BALTHASAR and CASPER,
acknowledged parts of minority MELCHIOR&#x27;s
arguments during the re-vote.
BALTHASAR conceded the partial effectiveness
of rule utilitarianism in avoiding
the organ harvesting problem.
CASPER acknowledged the validity
of pointing out Damasio&#x27;s circular reasoning.
They did not change their positions,
but they recognized the legitimate parts
of their opponent&#x27;s arguments.
This intellectual honesty does not emerge
from independent voting alone.&lt;&#x2F;p&gt;
&lt;p&gt;What Super MAGI delivered was not
&quot;a change in conclusion&quot; but
&quot;confirmation of the conclusion&#x27;s
robustness.&quot;
The fact that the conclusion held even
after debate increases confidence
in the decision.
Of course, there are cases where debate
could reverse the conclusion.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-article-review-1&quot;&gt;&lt;a href=&quot;#fn-article-review&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
That is when the deliberation phase
truly proves its worth.&lt;&#x2F;p&gt;
&lt;p&gt;In practical use of MAGI, the analysis
presented during the reasoning process
is actually more useful than the final
&quot;Option A or Option B&quot; verdict.
What perspectives were considered,
which arguments proved effective,
and where the weaknesses lie.
The rebuttals and counter-rebuttals exchanged
during the deliberation phase
surface arguments I would never have
noticed on my own.
I believe MAGI&#x27;s true value lies not
in &quot;producing an answer&quot; but in
&quot;assembling the materials for thinking.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;In terms of volume, the original MAGI
produces roughly 50 lines,
while Super MAGI generates about 220 lines,
more than four times as much.
Deep analysis and brevity are a trade-off,
which is why the design to skip deliberation
for unanimous votes proves valuable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Super MAGI leverages Claude Code&#x27;s Agent Teams
feature to evolve multi-agent decision-making
from &quot;vote and done&quot; to
&quot;debate, then vote.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Here are the key design principles:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Preserving independence: Analyze
independently first, then debate.
Maintaining this order preserves
diversity of perspectives&lt;&#x2F;li&gt;
&lt;li&gt;Selective activation: No deliberation needed
for unanimous votes.
Dig deeper only when opinions diverge&lt;&#x2F;li&gt;
&lt;li&gt;Structured fairness: Guarantee the minority
the last word, compensating for numerical
disadvantage through procedure&lt;&#x2F;li&gt;
&lt;li&gt;Safe fallback: All errors fall back
to independent analysis results&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The plugin is available on GitHub.
If you are a Claude Code user,
you can install it and try the &lt;code&gt;&#x2F;magi&lt;&#x2F;code&gt;
command.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-self-review&quot;&gt;
&lt;p&gt;The Super MAGI concept document and requirements specification were themselves reviewed by MAGI, both receiving unanimous 3-to-0 approval. The results are included in the repository&#x27;s &lt;code&gt;docs&#x2F;&lt;&#x2F;code&gt; directory. &lt;a href=&quot;#fr-self-review-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-agent-teams&quot;&gt;
&lt;p&gt;Announced alongside Claude Opus 4.6. A single session acts as team leader, spawning multiple agents as teammates who exchange messages via &lt;code&gt;SendMessage&lt;&#x2F;code&gt;. See the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&#x2F;en&#x2F;agent-teams&quot;&gt;official documentation&lt;&#x2F;a&gt; for details. &lt;a href=&quot;#fr-agent-teams-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-realworld&quot;&gt;
&lt;p&gt;If only the real world worked this way too. &lt;a href=&quot;#fr-realworld-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-mill&quot;&gt;
&lt;p&gt;J.S. Mill, &lt;em&gt;On Liberty&lt;&#x2F;em&gt; (1859). Mill criticized the &quot;tyranny of the majority,&quot; arguing that even if all of humanity held one opinion and only a single person held the opposite, silencing that one person would not be justified. &lt;a href=&quot;#fr-mill-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-article-review&quot;&gt;
&lt;p&gt;A reversal actually occurred during the review of this article. The initial vote split 2-to-1 (Option B: needs improvement), but after the deliberation phase, it reversed to a unanimous 3-to-0 (Option A: worthy of publication). &lt;a href=&quot;#fr-article-review-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">Using Claude Code&#x27;s Agent Teams feature,
I upgraded the Evangelion-inspired MAGI plugin
from simple majority voting
to a deliberative democracy system
where AI agents debate before casting
their final votes.
</summary>
        </entry><entry xml:lang="en">
        <title>Claude Codeの「何やってたっけ？」をなくす — jrnl-toolsで文脈を渡す</title>
        <published>2026-02-13T00:00:00+00:00</published>
        <updated>2026-02-13T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/claude-code-jrnl-context-handoff/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/claude-code-jrnl-context-handoff/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition info&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-info&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;転載記事&lt;&#x2F;strong&gt;
        &lt;p&gt;この記事は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;claude-code-jrnl-context-handoff&quot;&gt;Zenn&lt;&#x2F;a&gt;に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;TL;DR&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;CLIジャーナルツール
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jrnl.sh&#x2F;&quot;&gt;jrnl&lt;&#x2F;a&gt;を使って
Claude Codeのセッション間で失われる
記憶を引き継ぐプラグイン
&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&#x2F;tree&#x2F;main&#x2F;plugins&#x2F;jrnl-plugin&quot;&gt;jrnl-tools&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;
を紹介&lt;&#x2F;li&gt;
&lt;li&gt;セッション終了時に&lt;code&gt;&#x2F;jrnl-handoff&lt;&#x2F;code&gt;で
作業状態を記録し、
翌日&lt;code&gt;&#x2F;jrnl-restore&lt;&#x2F;code&gt;で復元&lt;&#x2F;li&gt;
&lt;li&gt;プロジェクト横断の状況一覧や
時系列の作業履歴も可能&lt;&#x2F;li&gt;
&lt;li&gt;2026年2月5日にリリースされた
&lt;strong&gt;Auto Memory&lt;&#x2F;strong&gt;との棲み分けも解説&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!-- textlint-disable --&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;claude-code-plugins&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;きっかけ_—_MCPからプラグインへ、そして活用法の発見&quot;&gt;きっかけ — MCPからプラグインへ、そして活用法の発見&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeで複雑なリファクタリングを
進めていて、
途中でセッションを閉じる必要がありました。
翌日セッションを再開すると、
Claude Codeは何も覚えていません。
「昨日の続きをお願い」と言っても、
ゼロから説明し直す羽目になりました。&lt;&#x2F;p&gt;
&lt;p&gt;筆者は以前から、
日々の作業を記録するために
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jrnl.sh&#x2F;&quot;&gt;jrnl&lt;&#x2F;a&gt;というCLIジャーナル
ツールを使っていました&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-jrnl-mcp-1&quot;&gt;&lt;a href=&quot;#fn-jrnl-mcp&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。
ターミナルから
&lt;code&gt;jrnl &quot;今日はXXを調査した&quot;&lt;&#x2F;code&gt;
と打つだけで記録が残る、
その手軽さを気に入っていたからです。&lt;&#x2F;p&gt;
&lt;p&gt;セッション記憶喪失の体験と、
普段使いのjrnl。
この2つが頭の中でつながりました。
&lt;strong&gt;jrnlが自分への備忘録として
機能するなら、Claude Codeへの備忘録としても
使えるのではないか。&lt;&#x2F;strong&gt;
セッション終了時にjrnlへ引き継ぎメモを書き、
翌日のセッションでそれを読み込ませれば、
文脈を引き継げるはずです。&lt;&#x2F;p&gt;
&lt;p&gt;このアイデアがjrnl-toolsプラグインの
出発点です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Codeの「記憶」の限界&quot;&gt;Claude Codeの「記憶」の限界&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeは強力な開発パートナーです。
コードを読み、修正し、テストを回し、
アーキテクチャの議論まで
一緒にしてくれます。
しかし、セッション固有の文脈には
根本的な制約があります。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeには&lt;code&gt;CLAUDE.md&lt;&#x2F;code&gt;という
永続的な設定ファイルがあり、
プロジェクトのルールや規約は
セッションを超えて引き継げます。
しかし、
&lt;strong&gt;「昨日のセッションで何を議論し、
どこまで進み、
次に何をする予定だったか」という
セッション固有のコンテキストは
引き継がれません。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;昨日2時間かけてデバッグした
認証バグの調査過程、設計判断の理由、
「次にやること」の合意。
セッションを閉じた瞬間、それらは消えます。
翌朝、新しいセッションを開くと、
Claude Codeはプロジェクトのルールは
知っていても、
昨日の作業状況は知りません。&lt;&#x2F;p&gt;
&lt;p&gt;「それなら&lt;code&gt;claude --resume&lt;&#x2F;code&gt;や
&lt;code&gt;claude --continue&lt;&#x2F;code&gt;でセッションを
再開すればいいのでは？」
と思うかもしれません。
確かに、これらのコマンドは
会話履歴をそのまま復元できる
強力な機能です。
しかし、セッション再開には
以下の制約があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;同一ディレクトリ限定&lt;&#x2F;strong&gt; —
セッションはディレクトリに紐付いており、
別プロジェクトのセッションは
再開できない&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;コンテキストウィンドウの制約&lt;&#x2F;strong&gt; —
長いセッションはコンパクト化され、
過去の議論の詳細は失われていく&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;検索性がない&lt;&#x2F;strong&gt; —
「先月の認証バグ調査」を
後から探すことはできない。
セッション履歴は蓄積される
知識にならない。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;そもそも、
膨大に膨らんだセッションの
コンテキストをそのまま次回に
引き継ぎたいわけではありません。
必要なのは「何が完了し、何が残っていて、
次にどこから始めるか」という要点です。
セッション再開は「中断した作業の
直接的な続行」には向いていますが、
「要点を絞った引き継ぎ」や
「長期的な作業記録」には
対応していません。&lt;&#x2F;p&gt;
&lt;p&gt;さらに、
複数プロジェクトを並行して進めている
開発者にとって、問題は深刻です。
Claude Codeはプロジェクト
（ディレクトリ）単位で動作するため、
プロジェクトAで作業しているときに
プロジェクトBの状況を知る方法が
ありません。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、足りていないのは以下の2つです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;セッションの要点を構造化して
引き継ぐ仕組み&lt;&#x2F;strong&gt; —
何を議論し、どこまで進み、
次に何をするかを簡潔に次の
セッションに伝える手段&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;プロジェクトの壁を超えた
横断的な状況把握&lt;&#x2F;strong&gt; —
どのプロジェクトからでも、
他のプロジェクトの進捗を
確認できる手段&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらを既存のCLIツールで
実現できないかと考えたとき、
冒頭で触れたjrnlの存在が
頭に浮かびました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jrnlという選択_—_CLIジャーナルが架け橋になる&quot;&gt;jrnlという選択 — CLIジャーナルが架け橋になる&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jrnl.sh&#x2F;&quot;&gt;jrnl&lt;&#x2F;a&gt; は
コマンドラインで動くシンプルな
ジャーナルツールです。
テキストベースで、タグ付けができ、
日付によるフィルタリングが可能です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;jrnl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;認証バグの原因はトークンリフレッシュ処理にあった @api @log&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;たったこれだけで、
タイムスタンプ付きのエントリが
記録されます。
このシンプルさがClaude Codeとの
統合に適しています。&lt;&#x2F;p&gt;
&lt;p&gt;jrnl-toolsが目指すのは、
&lt;strong&gt;jrnlをClaude Codeセッション間の
「フロー情報ハブ」にすること&lt;&#x2F;strong&gt;です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    graph TD
A[&quot;Project A&lt;br&#x2F;&gt;(Claude Code)&quot;] --&gt; J
B[&quot;Project B&lt;br&#x2F;&gt;(Claude Code)&quot;] --&gt; J
C[&quot;Project C&lt;br&#x2F;&gt;(Claude Code)&quot;] --&gt; J
J[&quot;jrnl (グローバル)&lt;br&#x2F;&gt;作業ログ &#x2F; ハンドオフ &#x2F; アイデア&quot;]
J --&gt; R[&quot;どのプロジェクトからでもアクセス可能&quot;]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;各プロジェクトのClaude Codeセッションから
jrnlに書き込み、
別のプロジェクトや翌日のセッションから
それを読み出す。
jrnlがプロジェクトとセッションの壁を超える
共有レイヤーになります。
組み込みのメモリ機能にはない、
jrnlならではの特性は以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;クロスプロジェクト横断&lt;&#x2F;strong&gt; —
jrnlはグローバルなので、
どのプロジェクトからでも
全プロジェクトの状況を把握できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;時系列の作業履歴&lt;&#x2F;strong&gt; —
エントリは日付付きで蓄積され、
後から検索・振り返りができる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Claude Code外からもアクセス可能&lt;&#x2F;strong&gt; —
&lt;code&gt;jrnl @handoff&lt;&#x2F;code&gt;のように、
ターミナルから直接検索・閲覧できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ユーザーが完全に制御可能&lt;&#x2F;strong&gt; —
エントリはプレーンテキストであり、
内容の確認・編集・削除を
自分で管理できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;「オリエンテーションガイド」という設計思想&quot;&gt;「オリエンテーションガイド」という設計思想&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsの設計で
最も重要な考え方があります。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ハンドオフは「状態のダンプ」ではなく
「オリエンテーションガイド」です。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;最初は、セッションの全状態をjrnlに
保存しようと考えました。
しかし実際に使ってみると、
複雑なセッションほど圧縮されて
読みにくいエントリになり、
結局役に立ちません。&lt;&#x2F;p&gt;
&lt;p&gt;そこで発想を転換しました。
プロジェクトの詳細な状態は、
TODO.md、設計ドキュメント、
コード自体に既に存在しています。
次のセッションのAIに必要なのは
「どこを見ればいいか」
という案内図です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    graph LR
H[&quot;jrnl（オリエンテーションガイド）&lt;br&#x2F;&gt;Handoff:&lt;br&#x2F;&gt;TODO.md Phase 9を確認&lt;br&#x2F;&gt;issue #2に取り組み中&quot;] -- &quot;参照&quot; --&gt; P[&quot;プロジェクト文書（詳細な状態）&lt;br&#x2F;&gt;TODO.md&lt;br&#x2F;&gt;docs&#x2F;architecture.md&lt;br&#x2F;&gt;CLAUDE.md&lt;br&#x2F;&gt;ソースコード&quot;]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;良いハンドオフとは、
次のセッションが
「どのファイルを読めばいいか」
「何が進行中だったか」を
瞬時に把握できるものです。
すべてを記録する必要はありません。
プロジェクトファイルが永続的な状態を
持っているからです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jrnl-toolsの4つのコマンド&quot;&gt;jrnl-toolsの4つのコマンド&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsプラグインは、
4つのスラッシュコマンドを提供します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&#x2F;jrnl-handoff_—_明日の自分への引き継ぎ&quot;&gt;&lt;code&gt;&#x2F;jrnl-handoff&lt;&#x2F;code&gt; — 明日の自分への引き継ぎ&lt;&#x2F;h3&gt;
&lt;p&gt;作業を終えるとき、
このコマンドを実行します。
Claude Codeがセッションの内容を分析し、
次のセッション向けの
オリエンテーションガイドを生成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; &#x2F;jrnl-handoff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;生成されるエントリの例は
以下のようになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Handoff: 認証ミドルウェアのリファクタリング完了 @api-server @handoff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Progress:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- トークンリフレッシュロジックを修正（auth.ts:45-78）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- ログイン&#x2F;ログアウトフローのテストがパス&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Files changed:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- src&#x2F;middleware&#x2F;auth.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- tests&#x2F;auth.test.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Blockers:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Next:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &#x2F;api&#x2F;usersにレート制限を実装（TODO.md item 3参照）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- APIドキュメントの更新（docs&#x2F;api-spec.md参照）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;gitリポジトリ内では、
&lt;code&gt;git diff --name-only&lt;&#x2F;code&gt;と&lt;code&gt;git status&lt;&#x2F;code&gt;の
情報も自動的に取り込まれ、
変更ファイルの一覧が正確に記録されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&#x2F;jrnl-restore_—_前回の続きから再開&quot;&gt;&lt;code&gt;&#x2F;jrnl-restore&lt;&#x2F;code&gt; — 前回の続きから再開&lt;&#x2F;h3&gt;
&lt;p&gt;翌朝、あるいは数日ぶりに
プロジェクトを開いたとき、
このコマンドで前回の状態を復元します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; &#x2F;jrnl-restore&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude Codeは以下のステップで
動作します。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;jrnlから最新のハンドオフを取得&lt;&#x2F;li&gt;
&lt;li&gt;ハンドオフに記載されたファイル
（TODO.md、ドキュメントなど）を
実際に読み込み&lt;&#x2F;li&gt;
&lt;li&gt;gitリポジトリなら、
ハンドオフ以降のコミットや
未コミットの変更も確認&lt;&#x2F;li&gt;
&lt;li&gt;これらを総合して「前回の続き」として
提示する。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ハンドオフが古くなっていても
問題ありません。
ハンドオフはあくまでスタート地点であり、
AIがプロジェクトファイルを読んで
最新の状態を把握します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&#x2F;jrnl-status_—_全プロジェクト横断ビュー&quot;&gt;&lt;code&gt;&#x2F;jrnl-status&lt;&#x2F;code&gt; — 全プロジェクト横断ビュー&lt;&#x2F;h3&gt;
&lt;p&gt;複数プロジェクトを並行している
開発者にとって、
これが最も価値のある
コマンドかもしれません。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; &#x2F;jrnl-status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;過去7日間（デフォルト）のハンドオフから、
全プロジェクトの状況を一覧表示します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Projects (last 7 days):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@api-server (2026-02-10)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Status: 認証ミドルウェアのリファクタリング完了&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Next: レート制限の実装&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@mobile-app (2026-02-08)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Status: プッシュ通知の統合完了&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Next: iOSバッジ数のバグ修正&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@docs-site (2026-02-06)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Status: 新テーマへの移行がブロック中&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Next: デザインチームのアセット待ち&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;月曜朝の計画や週次レビューで
威力を発揮します。
&lt;code&gt;&#x2F;jrnl-status 30&lt;&#x2F;code&gt;で
過去30日に拡張できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&#x2F;jrnl-log_—_作業記録の自動生成&quot;&gt;&lt;code&gt;&#x2F;jrnl-log&lt;&#x2F;code&gt; — 作業記録の自動生成&lt;&#x2F;h3&gt;
&lt;p&gt;セッション中の作業を振り返って
記録します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; &#x2F;jrnl-log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude Codeがセッション内容を分析し、
作業ログを自動生成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Log: 認証バグ3件修正とOAuthテスト追加 @api-server @log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Completed:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 認証バグ修正（issues #45, #47, #48）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- トークンリフレッシュに指数バックオフを導入&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- OAuthフローの統合テスト追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Decisions:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- リフレッシュトークンのTTLを24時間から72時間に変更&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;日報やスタンドアップの素材として、
あるいは個人の振り返りとして
活用できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;自然言語でも使える&quot;&gt;自然言語でも使える&lt;&#x2F;h2&gt;
&lt;p&gt;スラッシュコマンドだけでなく、
自然言語でもjrnlと対話できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; ジャーナルに追加して：決済APIはバリデーションエラーでも200を返す。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  response.statusフィールドを確認する必要がある&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; 先週のジャーナルを見せて&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; 昨日何をしていた？&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; 認証に関するジャーナルエントリを検索して&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;jrnlのコマンド体系を知らなくても、
Claude Codeが適切なコマンドに変換して
実行します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;タグによる情報の分類&quot;&gt;タグによる情報の分類&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsは、
シンプルなタグ体系で情報を分類します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;タグ&lt;&#x2F;th&gt;&lt;th&gt;用途&lt;&#x2F;th&gt;&lt;th&gt;時間の向き&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@&amp;lt;project&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;プロジェクト識別（自動付与）&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@log&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;過去の記録（作業、調査、判断）&lt;&#x2F;td&gt;&lt;td&gt;過去&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@handoff&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;次セッションへの引き継ぎ&lt;&#x2F;td&gt;&lt;td&gt;未来&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@idea&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;いつか検討するアイデア&lt;&#x2F;td&gt;&lt;td&gt;不定&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;プロジェクトタグは&lt;code&gt;CLAUDE.md&lt;&#x2F;code&gt;に
設定しておくと、
自動的にすべてのエントリに付与されます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;jrnl Project Tag:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; api-server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この仕組みにより、
&lt;code&gt;jrnl @api-server&lt;&#x2F;code&gt;で
特定プロジェクトのエントリだけを、
&lt;code&gt;jrnl @handoff&lt;&#x2F;code&gt;でプロジェクト横断の
ハンドオフだけを
フィルタリングできます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1日のワークフロー&quot;&gt;1日のワークフロー&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsを使った
典型的な1日の流れを紹介します。&lt;&#x2F;p&gt;
&lt;p&gt;朝はまず状況を把握し、文脈を復元します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;jrnl-status          # 全プロジェクトの状況を確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;jrnl-restore         # 今日のプロジェクトの前回状態を復元&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;作業中に気づいたことは、
その場で記録します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; ジャーナルに追加：キャッシュのTTLを5分にすると&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  レスポンスタイムが40%改善した&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; このアイデアを保存：将来的にGraphQL Subscriptionsで&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  リアルタイム更新を実装すべき&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;夕方、作業を終える前に
引き継ぎと記録を残します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;jrnl-handoff         # 明日のセッションへの引き継ぎ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;jrnl-log             # 今日の作業記録（オプション）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この流れを習慣化すると、
セッション間の文脈断絶がほぼなくなります。
翌朝の「何やってたっけ？」が
「はい、昨日の続きですね」に変わります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;セットアップ&quot;&gt;セットアップ&lt;&#x2F;h2&gt;
&lt;p&gt;事前に&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jrnl.sh&#x2F;&quot;&gt;jrnl&lt;&#x2F;a&gt;の
インストールが必要です。
Claude Codeの&lt;code&gt;&#x2F;plugin&lt;&#x2F;code&gt;コマンドから
インストールします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# マーケットプレイスを登録&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;plugin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; marketplace add yostos&#x2F;claude-code-plugins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# プラグインをインストール&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;plugin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install jrnl-tools@yostos-claude-code-plugins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;各プロジェクトの&lt;code&gt;CLAUDE.md&lt;&#x2F;code&gt;に、
プロジェクトタグを追加します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;jrnl Project Tag:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; myproject&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これだけで準備完了です。
設定していなくても、
初回実行時にClaude Codeが
プロジェクト名を聞いてくれます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;安全策と注意事項&quot;&gt;安全策と注意事項&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsは「壊さない」ことを
重視して設計されています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;削除操作なし&lt;&#x2F;strong&gt; —
エントリの削除は不可。
誤操作によるデータ消失を防止&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;暗号化操作なし&lt;&#x2F;strong&gt; —
パスワード処理のセキュリティリスクを
回避&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;追記のみ&lt;&#x2F;strong&gt; —
既存のエントリを変更しない。
編集が必要な場合は
&lt;code&gt;jrnl --edit&lt;&#x2F;code&gt;の使用をガイド&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ただし、利用にあたって
認識しておくべき点があります。&lt;&#x2F;p&gt;
&lt;p&gt;機密情報の取り扱いには注意してください。
&lt;code&gt;&#x2F;jrnl-handoff&lt;&#x2F;code&gt;や&lt;code&gt;&#x2F;jrnl-log&lt;&#x2F;code&gt;は
セッション内容を要約して
jrnlに記録します。
セッション中にAPIキーや認証情報を
扱った場合、
それらが要約に含まれる可能性があります。
jrnlはデフォルトでプレーンテキスト
保存のため、
機密性の高いプロジェクトでは
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jrnl.sh&#x2F;en&#x2F;stable&#x2F;encryption&#x2F;&quot;&gt;jrnlの暗号化機能&lt;&#x2F;a&gt;の
利用を推奨します。&lt;&#x2F;p&gt;
&lt;p&gt;プロジェクト横断機能の情報分離にも
配慮が必要です。
&lt;code&gt;&#x2F;jrnl-status&lt;&#x2F;code&gt;は全プロジェクトの状況を
横断表示する便利な機能ですが、
裏を返せば異なるプロジェクトの情報が
同じジャーナルに混在することを
意味します。
異なる機密レベルのプロジェクトを
扱う場合は、この点を考慮してください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Auto_Memoryの登場_—_公式機能との棲み分け&quot;&gt;Auto Memoryの登場 — 公式機能との棲み分け&lt;&#x2F;h2&gt;
&lt;p&gt;ここまでjrnl-toolsの設計と使い方を
紹介してきました。
しかし、このプラグインを開発していた
2026年2月5日、状況が変わりました。
Claude Code v2.1.32のリリースで
Auto Memory&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-auto-memory-1&quot;&gt;&lt;a href=&quot;#fn-auto-memory&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;という機能が
追加されたのです。&lt;&#x2F;p&gt;
&lt;p&gt;「ハンドオフして」とClaude Codeに
依頼するだけで、
次のセッションへの引き継ぎ情報が
&lt;code&gt;~&#x2F;.claude&#x2F;projects&#x2F;&lt;&#x2F;code&gt;配下の
メモリファイルに自動保存されます。
プロジェクトのパターンや設定も
自動的に記録され、
次回セッション開始時に
システムプロンプトへ読み込まれます。
セッション終了時に要点を
自動記録するSession
Memory&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-session-memory-1&quot;&gt;&lt;a href=&quot;#fn-session-memory&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;も含め、
&lt;strong&gt;同じプロジェクト内での
セッション引き継ぎは
公式機能でカバーできるように
なりました。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;正直に言えば、
開発中のプラグインと公式機能の
守備範囲が一部重なりました。
では、jrnl-toolsは
不要になったのでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;実際に使い比べてみると、
両者の性質は異なっていました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;特性&lt;&#x2F;th&gt;&lt;th&gt;Auto Memory&lt;&#x2F;th&gt;&lt;th&gt;jrnl-tools&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;情報の性質&lt;&#x2F;td&gt;&lt;td&gt;ストック（安定した知識）&lt;&#x2F;td&gt;&lt;td&gt;フロー（時系列の記録）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;保存先&lt;&#x2F;td&gt;&lt;td&gt;プロジェクトごとのローカルファイル&lt;&#x2F;td&gt;&lt;td&gt;グローバルなjrnlジャーナル&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;スコープ&lt;&#x2F;td&gt;&lt;td&gt;単一プロジェクト&lt;&#x2F;td&gt;&lt;td&gt;クロスプロジェクト&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;次セッションへの引き継ぎ&lt;&#x2F;td&gt;&lt;td&gt;自動（システムプロンプトに読み込み）&lt;&#x2F;td&gt;&lt;td&gt;明示的（&lt;code&gt;&#x2F;jrnl-restore&lt;&#x2F;code&gt;で復元）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;過去の作業履歴&lt;&#x2F;td&gt;&lt;td&gt;新しい知見で上書き（約200行の自動読み込み枠）&lt;&#x2F;td&gt;&lt;td&gt;日付付きで蓄積・検索可能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Claude Code外からのアクセス&lt;&#x2F;td&gt;&lt;td&gt;想定されていない&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;jrnl&lt;&#x2F;code&gt;コマンドで直接参照可能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Auto Memoryは
**「プロジェクトの知識」**の
永続化に優れています。
コーディング規約、
プロジェクト構造、
ユーザーの好みといった安定した情報は、
Auto Memoryに任せるのが最適です。&lt;&#x2F;p&gt;
&lt;p&gt;一方、jrnl-toolsは
**「作業の記録」**に特化しています。
「いつ何をしたか」
「なぜその判断をしたか」という
時系列の文脈は、
Auto Memoryでは整理されて失われますが、
jrnlには蓄積されていきます。
&lt;code&gt;&#x2F;jrnl-status&lt;&#x2F;code&gt;による
プロジェクト横断ビューも、
プロジェクト単位で分離された
Auto Memoryでは実現できません。&lt;&#x2F;p&gt;
&lt;p&gt;両者は競合せず、補完関係にあります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsは、
Claude Codeのセッションと
プロジェクトの壁を超えた
開発体験を実現するプラグインです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;プロジェクト間の壁を超える&lt;&#x2F;strong&gt; →
jrnlをハブにした横断ビューで、
全プロジェクトの状況を一望&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;作業履歴を蓄積する&lt;&#x2F;strong&gt; →
時系列のログとして
検索・振り返りが可能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Claude Codeの外からも
アクセスできる&lt;&#x2F;strong&gt; →
ターミナルから直接参照でき、
独立したツールとして機能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Auto Memoryが「プロジェクトの知識」を、
jrnlが「作業の記録」を担う。
この棲み分けのもとで、
開発者のワークフローは
さらに改善されます。&lt;&#x2F;p&gt;
&lt;p&gt;jrnlのインストールとプラグインの導入は
数分で完了します。
まずは今日の作業を&lt;code&gt;&#x2F;jrnl-handoff&lt;&#x2F;code&gt;で
記録するところから始めてみてください。
使ってみた感想や改善のアイデアがあれば、
この記事のコメントや
GitHubリポジトリのIssueで
気軽にお聞かせください。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-jrnl-mcp&quot;&gt;
&lt;p&gt;以前
&lt;a href=&quot;&#x2F;blog&#x2F;2025&#x2F;07&#x2F;first-mcp-server-development&#x2F;&quot;&gt;jrnl-mcp&lt;&#x2F;a&gt;
というMCPサーバーを作り、
Claude DesktopやClaude Codeから
jrnlを操作できるようにしていました。
Claude Codeのプラグインへ移植しようとした際、
MCPのツールAPIを経由しなくても
Claude Codeならjrnlコマンドを
直接実行できることに気づき、
必要なのはAPIではなく
ワークフローの設計だという
発想の転換がありました。 &lt;a href=&quot;#fr-jrnl-mcp-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-auto-memory&quot;&gt;
&lt;p&gt;Auto Memoryは、
Claude Code v2.1.32
（2026年2月5日リリース）で
追加された機能です。
セッション中に発見した
プロジェクトのパターンや設定を
&lt;code&gt;~&#x2F;.claude&#x2F;projects&#x2F;&lt;&#x2F;code&gt;配下の
メモリファイルに自動保存し、
次回セッションのシステムプロンプトに
読み込みます。「ハンドオフして」と
依頼すれば
次にやるべきことも保存できます。
詳細は
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&#x2F;en&#x2F;memory&quot;&gt;公式ドキュメント&lt;&#x2F;a&gt;
を参照してください。 &lt;a href=&quot;#fr-auto-memory-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-session-memory&quot;&gt;
&lt;p&gt;2026年2月現在の
Session Memoryは、
セッション終了時に会話の要点を
自動的に記録する機能です。
Claude Code（Pro&#x2F;Maxプラン、
Anthropic API経由）で利用でき、
同じプロジェクトの次回セッションで
参照できます。
ただしプロジェクトごとに分離されており、
異なるプロジェクト間での共有は
できません。
Bedrock・Vertex・Foundry経由の
利用ではフィーチャーフラグにより
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;anthropics&#x2F;claude-code&#x2F;issues&#x2F;13706&quot;&gt;無効化されています&lt;&#x2F;a&gt;。 &lt;a href=&quot;#fr-session-memory-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">「昨日の続きをお願い」が通じない。
セッションごとに記憶が消える
Claude Codeの弱点を、
CLIジャーナルツールjrnlで補う
プラグインを開発しました。
プロジェクト横断の状況把握から
Auto Memoryとの使い分けまで
解説します。
</summary>
        </entry><entry xml:lang="en">
        <title>多機能Todoに疲れた人へ ─「一枚の紙」だけのタスク管理CLI</title>
        <published>2026-01-23T00:00:00+00:00</published>
        <updated>2026-01-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/building-ttt-with-claude-code/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/building-ttt-with-claude-code/</id>
        
            <content type="html"> &lt;details&gt;
  &lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
  &lt;!-- toc --&gt;
  &lt;&#x2F;details&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;ターミナルで作業中、ふと「あれもやらなきゃ」と思いついたとき、頭の中を書き出す場所が欲しくなります。
物理的なメモ用紙ならすぐに書けますが、ターミナルから手を離すのは煩わしい。
かといって多機能なTodoアプリを開くと、プロジェクトやタグを考えているうちに書きたかったことを忘れてしまう。&lt;&#x2F;p&gt;
&lt;p&gt;そこで作ったのが &lt;strong&gt;Tiny Task Tool&lt;&#x2F;strong&gt; です。コマンド名はタイプしやすいように &lt;code&gt;ttt&lt;&#x2F;code&gt; としました。&lt;&#x2F;p&gt;
&lt;p&gt;「一枚の紙」のシンプルさをターミナルで再現することを目指した、ミニマルなタスク管理ツールです。&lt;&#x2F;p&gt;
&lt;p&gt;この記事では、&lt;code&gt;ttt&lt;&#x2F;code&gt; のコンセプトと使い方を紹介しつつ、Claude Codeとの協働開発でドキュメント駆動とTDDがいかに効果的だったかをお伝えします。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Tiny_Task_Tool_とは&quot;&gt;Tiny Task Tool とは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;ttt&lt;&#x2F;code&gt;(Tiny Task Tool) は「デジタルなメモ用紙」を目指したTUIタスク管理ツールです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;01&amp;#x2F;building-ttt-with-claude-code&amp;#x2F;demo.gif?h=5668a44b60ecfc9113e6&quot;
  alt=&quot;ttt demo&quot; width=&quot;800&quot; height=&quot;600&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h3 id=&quot;主な特徴&quot;&gt;主な特徴&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;一枚の紙&lt;&#x2F;strong&gt;: ファイルは常に1つ。「どのファイルに書こう」という選択を排除&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;今に集中&lt;&#x2F;strong&gt;: タスクをすぐ書き出し、完了したらアーカイブ。シンプルな運用&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ノード指向&lt;&#x2F;strong&gt;: 階層構造のタスクを直感的に扱える。親を完了すれば子も完了&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Unix 哲学&lt;&#x2F;strong&gt;: フォーカス機能以外は外部エディタやGitに任せる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;インストール&quot;&gt;インストール&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# go install（推奨）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install github.com&#x2F;yostos&#x2F;tiny-task-tool@latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Homebrew&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install yostos&#x2F;tap&#x2F;ttt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;基本的な使い方&quot;&gt;基本的な使い方&lt;&#x2F;h3&gt;
&lt;p&gt;ターミナルで &lt;code&gt;ttt&lt;&#x2F;code&gt; と打つだけで、1ページのタスク表がTUIで開きます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ttt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                    # TUIでタスク表を開く&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ttt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -t &amp;quot;牛乳を買う&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;     # コマンドラインからタスクを追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ttt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;               # git pushでリモートと同期&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;TUIでは &lt;code&gt;e&lt;&#x2F;code&gt; でエディタを開き、&lt;code&gt;a&lt;&#x2F;code&gt; でアーカイブ、&lt;code&gt;q&lt;&#x2F;code&gt; で終了。キーバインドはVim&#x2F;Emacsユーザー向けにカスタマイズ可能です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;タスクのフォーマット&quot;&gt;タスクのフォーマット&lt;&#x2F;h3&gt;
&lt;p&gt;シンプルなMarkdownチェックボックス形式です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; [ ] 未完了のタスク&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt; [x]&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 完了したタスク @done(2026-01-18)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt; [x]&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 子タスクも自動で完了 @done(2026-01-18)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;タスク以外の箇条書きもノードとして挿入できます。タスクをグルーピングするためにセクション（&lt;code&gt;# Task&lt;&#x2F;code&gt; や &lt;code&gt;## Project A&lt;&#x2F;code&gt;）なども扱えます。&lt;&#x2F;p&gt;
&lt;p&gt;完了したタスクには自動で &lt;code&gt;@done(日付)&lt;&#x2F;code&gt; タグが付き、設定した日数が経過するとarchive.mdに移動します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜ作ったのか&quot;&gt;なぜ作ったのか&lt;&#x2F;h2&gt;
&lt;p&gt;きっかけはZennで見かけた「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;nekoninaritai&#x2F;articles&#x2F;941e55aed77609&quot;&gt;Markdown Paper という選択肢&lt;&#x2F;a&gt;」という記事でした。&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ephe.app&#x2F;&quot;&gt;ephe.app&lt;&#x2F;a&gt; の「一枚の紙」コンセプトをCLIに持ち込んだ &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;siki-712&#x2F;aeph&quot;&gt;aeph&lt;&#x2F;a&gt; の紹介記事です。&lt;&#x2F;p&gt;
&lt;p&gt;コンセプトには共感しましたが、aephは複数ファイルに対応しており、「一枚の紙」とは少し違うと感じました。そこでaephのソースコードを参考にするのではなく、ゼロから自分のコンセプトで作ることにしました。&lt;&#x2F;p&gt;
&lt;p&gt;既存のツールにも同様の問題がありました。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Todo アプリ&lt;&#x2F;strong&gt;: 多機能すぎる。プロジェクト、優先度、タグ…考えているうちに書きたいことを忘れる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Markdown エディタ&lt;&#x2F;strong&gt;: ファイル名やフォルダを考える必要がある&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;GUI アプリ&lt;&#x2F;strong&gt;: ターミナルから離れるコンテキストスイッチが発生する&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;単一ファイル、選択肢なし、気を散らすものなし。机の上のメモ用紙のように、「開いて、書いて、終わったら消す」だけの体験が欲しかったのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Code_との開発体験&quot;&gt;Claude Code との開発体験&lt;&#x2F;h2&gt;
&lt;p&gt;このプロジェクトはClaude Codeを活用し、以下のプロセスで開発しました。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;コンセプト文書化（concept.md）&lt;&#x2F;li&gt;
&lt;li&gt;詳細仕様策定（specification.md）&lt;&#x2F;li&gt;
&lt;li&gt;アーキテクチャ選定（architecture.md）&lt;&#x2F;li&gt;
&lt;li&gt;テストコード先行開発&lt;&#x2F;li&gt;
&lt;li&gt;実装&lt;&#x2F;li&gt;
&lt;li&gt;テスト自動化&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;ドキュメント駆動が効いた理由&quot;&gt;ドキュメント駆動が効いた理由&lt;&#x2F;h3&gt;
&lt;p&gt;Claude Codeとの協働で最も効果的だったのは、&lt;strong&gt;まずドキュメントを書き、それに従って開発する&lt;&#x2F;strong&gt;アプローチでした。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;1._concept.md_で方向性を固める&quot;&gt;1. concept.md で方向性を固める&lt;&#x2F;h4&gt;
&lt;p&gt;最初に「なぜ作るのか」「何をしないか」を明確にしました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### やらないこと&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; ファイル指定（「どのファイルを開くか」という選択を排除）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 複数ファイル管理（一枚の紙の原則に反する）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; ファイル内編集（外部エディタに任せる）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;「やらないこと」を明文化したことで、開発中に機能追加の誘惑が来ても「concept.mdに反する」と判断できました。Claudeにも「この機能はconcept.mdの方針に反しますね」とフィードバックを受けられます。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2._specification.md_で仕様を詳細化&quot;&gt;2. specification.md で仕様を詳細化&lt;&#x2F;h4&gt;
&lt;p&gt;ユースケース、画面レイアウト、エラー処理まで事前に定義しました。これによりClaudeへの指示が明確になり、生成されるコードの品質が上がりました。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3._architecture.md_で技術選定を記録&quot;&gt;3. architecture.md で技術選定を記録&lt;&#x2F;h4&gt;
&lt;p&gt;「なぜその技術を選んだか」「他の選択肢をなぜ却下したか」を記録しました。後から見返したとき、またClaudeに文脈を伝えるときに役立ちました。基本的に記載方法は &lt;strong&gt;Architectural Decision Record（ADR）形式&lt;&#x2F;strong&gt; を採用して記載しています。&lt;&#x2F;p&gt;
&lt;p&gt;以下は言語選定の際の例です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;候補&lt;&#x2F;th&gt;&lt;th&gt;却下理由&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Rust&lt;&#x2F;td&gt;&lt;td&gt;学習コストが高い。所有権&#x2F;ライフタイムの概念が独特で、AI 駆動開発でコンパイルエラー修正時に堂々巡りするリスク&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Python&lt;&#x2F;td&gt;&lt;td&gt;PEP 668 により配布が複雑化。起動速度も遅い&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;TypeScript&lt;&#x2F;td&gt;&lt;td&gt;単一バイナリ配布ができず「摩擦をなくす」原則に反する&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;TDD_が_AI_駆動開発と相性が良い理由&quot;&gt;TDD が AI 駆動開発と相性が良い理由&lt;&#x2F;h3&gt;
&lt;p&gt;テスト駆動開発（TDD）はClaude Codeとの開発で特に威力を発揮しました。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;テストファーストのメリット&quot;&gt;テストファーストのメリット&lt;&#x2F;h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;期待動作の明確化&lt;&#x2F;strong&gt;: テストコードが「仕様書」として機能し、開発前に私が確認できるためClaudeへの指示が曖昧にならない&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;リグレッション防止&lt;&#x2F;strong&gt;: AIが生成したコードの変更が既存機能を壊していないか即座に確認&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;リファクタリングの安心感&lt;&#x2F;strong&gt;: テストが通れば安心して改善できる&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h4 id=&quot;実際の開発フロー&quot;&gt;実際の開発フロー&lt;&#x2F;h4&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 1. まずテストを書く（Red）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; go test .&#x2F;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# FAIL: TestArchiveCompletedTasks - 期待する動作のテストが失敗&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 2. Claude に実装を依頼&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 「このテストを通す実装をお願いします」&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 3. テストが通ることを確認（Green）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; go test .&#x2F;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# PASS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 4. リファクタリング&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 「この実装をより読みやすくリファクタリングしてください」&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;特に階層タスクのアーカイブ処理のような複雑なロジックでは、テストケースを先に書いておくことで、エッジケースの考慮漏れを防げました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Claude_Code_との対話で心がけたこと&quot;&gt;Claude Code との対話で心がけたこと&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ドキュメントを参照させる&lt;&#x2F;strong&gt;:「concept.mdの方針に従って」「specification.mdの仕様通りに」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;小さな単位で依頼&lt;&#x2F;strong&gt;: 一度に多くを頼まず、テスト→実装→確認のサイクルを回す&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;コミットを細かく&lt;&#x2F;strong&gt;: 動作確認できた時点でコミット。戻れるポイントを作る&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;技術スタック&quot;&gt;技術スタック&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;分野&lt;&#x2F;th&gt;&lt;th&gt;選択&lt;&#x2F;th&gt;&lt;th&gt;理由&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;言語&lt;&#x2F;td&gt;&lt;td&gt;Go&lt;&#x2F;td&gt;&lt;td&gt;単一バイナリ配布、高速起動&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;TUI&lt;&#x2F;td&gt;&lt;td&gt;bubbletea + lipgloss&lt;&#x2F;td&gt;&lt;td&gt;成熟したエコシステム、Elm アーキテクチャ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;設定&lt;&#x2F;td&gt;&lt;td&gt;pelletier&#x2F;go-toml v2&lt;&#x2F;td&gt;&lt;td&gt;TOML 1.0 準拠、高速&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;テスト&lt;&#x2F;td&gt;&lt;td&gt;testing + testify&lt;&#x2F;td&gt;&lt;td&gt;標準+簡潔なアサーション&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;ttt&lt;&#x2F;code&gt; は「一枚の紙」という思想にこだわった結果、機能を削ることで価値を磨けたツールになったと思います。私自身も便利に使っています。もっと高機能なツールはたくさん
ありますが、コンセプトに賛同いただける多くの方に使ってもらえれば幸いです。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeとの開発では、&lt;strong&gt;ドキュメント駆動&lt;&#x2F;strong&gt; と &lt;strong&gt;TDD&lt;&#x2F;strong&gt; の組み合わせが非常に効果的でした。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ドキュメント駆動&lt;&#x2F;strong&gt;: 要件だけでなく方針を文書化するところから、Claude Codeと協働する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;TDD&lt;&#x2F;strong&gt;: 期待動作を定義し、品質を担保する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;「Claude Codeに任せきり」ではなく「Claude Codeと協働する」開発スタイルとして、このアプローチはおすすめできます。&lt;&#x2F;p&gt;
&lt;p&gt;興味を持っていただけたら、ぜひ使ってみてください。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;tiny-task-tool&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;tiny-task-tool&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;この記事で紹介したドキュメント（concept.md, specification.md, architecture.md）は GitHub リポジトリの docs&#x2F; ディレクトリで公開しています。&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        <summary type="html">多機能Todoアプリに疲れた方へ。「一枚の紙」だけのシンプルさを
再現したミニマルなタスク管理CLI「Tiny Task Tool (ttt)」を
開発しました。Claude Codeとの協働開発で実感した、
ドキュメント駆動とTDDの効果的な組み合わせをご紹介します。
</summary>
        </entry><entry xml:lang="en">
        <title>Logic ProのAIFファイルをラウドネス正規化してFLACに変換するスクリプト</title>
        <published>2026-01-14T00:00:00+00:00</published>
        <updated>2026-01-14T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/aif2flac/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/aif2flac/</id>
        
            <content type="html">&lt;h2 id=&quot;背景&quot;&gt;背景&lt;&#x2F;h2&gt;
&lt;p&gt;Logic Proでバウンスした音声ファイル(Aiff)をFLACに変換する際、適切な音量に正規化する必要があります。ffmpegの&lt;code&gt;loudnorm&lt;&#x2F;code&gt;フィルタを使うと高品質なラウドネス正規化が可能ですが、最良の結果を得るには2パス処理が推奨されます。&lt;&#x2F;p&gt;
&lt;p&gt;この2パス処理は以下のような手順です。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;1回目の実行で音声のラウドネス値を測定&lt;&#x2F;li&gt;
&lt;li&gt;測定された値を確認し、手動で2回目のコマンドにコピー&lt;&#x2F;li&gt;
&lt;li&gt;2回目の実行で測定値を使用して正規化を適用&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;毎回この作業を手動で行うのは面倒なので、自動化するスクリプトを作成しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;スクリプトの内容&quot;&gt;スクリプトの内容&lt;&#x2F;h2&gt;
&lt;p&gt;現時点のコードは以下です。&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;yostos&#x2F;004e57e4a905f933e227aa183e3a8fec&quot;&gt;Gist&lt;&#x2F;a&gt;でも公開しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;aif2flac.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-shebang z-shell z-meta z-shebang z-shell&quot;&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Script to convert AIF files to FLAC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Uses two-pass loudness normalization method (measure first, then encode with measured values)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Copyright (c) 2026 yostos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Licensed under the MIT License&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# https:&#x2F;&#x2F;opensource.org&#x2F;licenses&#x2F;MIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;VERBOSE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Parse options&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;while&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-source&quot;&gt; $#&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -gt&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ]];&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; $1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        -v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;--verbose&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            VERBOSE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            shift&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            ;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        -h&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;--help&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Usage: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; [-v|--verbose] &amp;lt;input_file.aif&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Options:&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;  -v, --verbose    Show detailed ffmpeg output&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;  -h, --help       Show this help message&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            ;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Error: Unknown option &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Usage: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; [-v|--verbose] &amp;lt;input_file.aif&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            ;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;        *)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            INPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;            shift&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            ;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    esac&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$INPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ];&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Usage: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; [-v|--verbose] &amp;lt;input_file.aif&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Use -h or --help for more information&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ! -f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$INPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ];&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Error: File &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$INPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&amp;#39; not found&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Generate output filename (change extension to .flac)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;OUTPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-variable z-other z-normal z-shell&quot;&gt;${INPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;.flac&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;=== Step 1: Measuring loudness... ===&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Measure loudness and get JSON output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;LOUDNESS_JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ffmpeg&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -i &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$INPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; -af &amp;quot;loudnorm=print_format=json&amp;quot; -f null -&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; 2&amp;gt;&amp;amp;1 |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -A&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Parsed_loudnorm&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Extract required values from JSON&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;MEASURED_I&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$LOUDNESS_JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;&amp;quot;input_i&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; awk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -F&amp;#39;&amp;quot;&amp;#39; &amp;#39;{print $4}&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;MEASURED_TP&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$LOUDNESS_JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;&amp;quot;input_tp&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; awk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -F&amp;#39;&amp;quot;&amp;#39; &amp;#39;{print $4}&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;MEASURED_LRA&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$LOUDNESS_JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;&amp;quot;input_lra&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; awk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -F&amp;#39;&amp;quot;&amp;#39; &amp;#39;{print $4}&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;MEASURED_THRESH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$LOUDNESS_JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;&amp;quot;input_thresh&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; awk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -F&amp;#39;&amp;quot;&amp;#39; &amp;#39;{print $4}&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;TARGET_OFFSET&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$LOUDNESS_JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;&amp;quot;target_offset&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; awk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -F&amp;#39;&amp;quot;&amp;#39; &amp;#39;{print $4}&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Measurement results:&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;  Input Integrated: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_I&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; LUFS&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;  Input True Peak:  &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_TP&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; dBTP&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;  Input LRA:        &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_LRA&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; LU&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;  Input Threshold:  &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_THRESH&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; LUFS&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;  Target Offset:    &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET_OFFSET&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; LU&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;=== Step 2: Encoding to FLAC... ===&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Encode to FLAC using measured values&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$VERBOSE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-true&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ];&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Verbose mode: show all ffmpeg output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    ffmpeg&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -y -i &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$INPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;        -af &amp;quot;loudnorm=I=-14:TP=-1:LRA=11:measured_I=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_I&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:measured_TP=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_TP&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:measured_LRA=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_LRA&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:measured_thresh=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_THRESH&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:offset=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET_OFFSET&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;:linear=true:print_format=summary&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;        -c:a flac &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Quiet mode: capture output and show only loudnorm summary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    FFMPEG_OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ffmpeg&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -y -hide_banner -i &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$INPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;        -af &amp;quot;loudnorm=I=-14:TP=-1:LRA=11:measured_I=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_I&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:measured_TP=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_TP&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:measured_LRA=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_LRA&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:measured_thresh=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MEASURED_THRESH&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:offset=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET_OFFSET&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;:linear=true:print_format=summary&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;        -c:a flac &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; 2&amp;gt;&amp;amp;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    FFMPEG_EXIT_CODE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-source&quot;&gt;$?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Extract and display loudnorm summary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$FFMPEG_OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -A&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Input Integrated:&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -v &amp;quot;^\[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -v &amp;quot;^$&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Check for errors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-source&quot;&gt; $FFMPEG_EXIT_CODE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -ne&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ];&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;        echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;        echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Error during encoding (exit code: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$FFMPEG_EXIT_CODE&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;)&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;        echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$FFMPEG_OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;        exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;=== Completed ===&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Output file: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Display file sizes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt; command&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -v du&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; &#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    INPUT_SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;du&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -h &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$INPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; awk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;{print $1}&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    OUTPUT_SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;du&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -h &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_FILE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; awk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;{print $1}&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Input file:  &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$INPUT_SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Output file: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;使い方&quot;&gt;使い方&lt;&#x2F;h2&gt;
&lt;p&gt;AIFファイルのパスを引数に指定して実行します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;aif2flac.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.aif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;詳細な出力を確認したい場合は&lt;code&gt;-v&lt;&#x2F;code&gt;オプションを付けます。出力ファイルは同じディレクトリに&lt;code&gt;.flac&lt;&#x2F;code&gt;拡張子で保存されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;loudnormフィルタについて&quot;&gt;loudnormフィルタについて&lt;&#x2F;h2&gt;
&lt;p&gt;ffmpegの&lt;code&gt;loudnorm&lt;&#x2F;code&gt;フィルタは、EBU R128規格に基づいたラウドネス正規化を行うためのフィルタです。単純な音量の増減ではなく、人間の聴覚特性を考慮した知覚的な音量の均一化を実現します。&lt;&#x2F;p&gt;
&lt;p&gt;このスクリプトでは以下のパラメータを使用しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;I=-14&lt;&#x2F;code&gt;: 目標のIntegrated Loudness（LUFS単位）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;TP=-1&lt;&#x2F;code&gt;: True Peak値の上限（dBTP単位）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;LRA=11&lt;&#x2F;code&gt;: Loudness Range（LU単位）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;I=-14 LUFS&lt;&#x2F;code&gt;は、Spotify、YouTube Music、Apple Musicなどの主要なストリーミングサービスが採用している標準的なラウドネス基準です。世間一般で広く使われているこの基準を参考にすることで、適切な音量バランスを保つことができます。&lt;&#x2F;p&gt;
&lt;p&gt;1パス処理では入力音声の特性を考慮せずに正規化するため、音質劣化の可能性があります。2パス処理では、1回目で測定した入力音声の実際の値を2回目の処理に使用することで、より正確で高品質な正規化が可能になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Logic Proから書き出した音声ファイルをFLACに変換する際の2パス処理を自動化することで、手動でパラメータをコピーする手間がなくなり、作業効率が大幅に向上しました。&lt;&#x2F;p&gt;
&lt;p&gt;今後は、複数ファイルの一括処理や、ターゲットラウドネス値のカスタマイズなどの機能を追加するかもしれません。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Logic Proでバウンスした音声ファイルをFLACに変換する際、
ffmpegのloudnormフィルタによる2パス処理を自動化する
Bashスクリプトを作成しました。測定と適用を一度のコマンドで
完結させ、手作業を排除して作業効率を大幅に向上させます。
</summary>
        </entry><entry xml:lang="en">
        <title>初めてのMCPサーバー開発 - jrnl-mcpを作ってみた</title>
        <published>2025-07-08T00:00:00+00:00</published>
        <updated>2025-07-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/first-mcp-server-development/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/first-mcp-server-development/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;Model Context Protocol（MCP）を使って、コマンドラインジャーナルツール「jrnl」とClaudeを連携させるMCPサーバーを開発しました。初めてのMCPサーバー開発の体験記として、選んだ理由から実装のポイント、学んだことまでを詳しく紹介します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;はじめに_-_MCPサーバーを作ってみたい&quot;&gt;はじめに - MCPサーバーを作ってみたい&lt;&#x2F;h2&gt;
&lt;p&gt;Model Context Protocol（MCP）の登場以来、Claudeとさまざまなツールやサービス
をつなげるMCPサーバーが次々と公開されています。GitHubを眺めていると、ファ
イルシステムやデータベース、各種APIとの連携など、実に多様なMCPサーバーが
開発されているのを見て、「自分でも何か作ってみたい」という気持ちが湧いてきま
した。&lt;&#x2F;p&gt;
&lt;p&gt;MCPサーバーを作ることで、自分の日常的なワークフローにAIを組み込めるだけで
なく、MCPというプロトコルの仕組みを手を動かしながら理解できる良い機会になる
と考えました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCPサーバーの題材選び_-_なぜjrnlを選んだのか&quot;&gt;MCPサーバーの題材選び - なぜjrnlを選んだのか&lt;&#x2F;h2&gt;
&lt;p&gt;MCPサーバーの題材を考えるにあたって、以下の条件を満たすものを探しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;日常的に使っているツールであること&lt;&#x2F;li&gt;
&lt;li&gt;CLIツールでシンプルなインターフェースを持つこと&lt;&#x2F;li&gt;
&lt;li&gt;読み取り専用でも十分に価値があること&lt;&#x2F;li&gt;
&lt;li&gt;プライバシーに配慮が必要なデータを扱うこと&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらの条件にぴったり当てはまったのが、コマンドラインジャーナルツールの
「jrnl」でした。&lt;&#x2F;p&gt;
&lt;p&gt;jrnlは、ターミナルから素早く日記を書けるPython製のツールで、タグ付けや検
索機能も備えています。私は日々の作業ログや思考の記録に使っており、「Claude
がこのジャーナルのデータにアクセスできたら、過去の記録を踏まえたより良いアド
バイスがもらえるのでは」と考えました。&lt;&#x2F;p&gt;
&lt;p&gt;また、jrnlは構造化されたデータ（日付、タグ、本文）を持ちながらも、実装がシ
ンプルで、初めてのMCPサーバー開発の題材として適していると判断しました。&lt;&#x2F;p&gt;
&lt;p&gt;そして作成したのが、「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;jrnl-mcp&quot;&gt;jrnl-mcp&lt;&#x2F;a&gt;」です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Codeと一緒に開発スタート&quot;&gt;Claude Codeと一緒に開発スタート&lt;&#x2F;h2&gt;
&lt;p&gt;開発はClaude Codeをペアプログラミングパートナーとして進めました。まず最初
に、MCPサーバーの基本的な構造についてClaudeに相談し、必要なファイル構成を
決めました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jrnl-mcp&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── index.ts      # メインのサーバー実装&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── package.json      # プロジェクト設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── tsconfig.json     # TypeScript設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── README.md         # ドキュメント&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;TypeScriptを選んだのは、MCPのSDKが型定義を提供しており、開発時の補完やエラーチェックが効くためです。Claude Codeと一緒に、まずは最小限の「Hello World」的なMCPサーバーを作り、それが動作することを確認してから機能を追加していくアプローチを取りました。&lt;&#x2F;p&gt;
&lt;p&gt;開発中、特に助かったのは以下の点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;エラーメッセージの解釈と対処法の提案&lt;&#x2F;li&gt;
&lt;li&gt;jrnlコマンドの出力パースロジックの実装&lt;&#x2F;li&gt;
&lt;li&gt;TypeScriptの型定義の最適化&lt;&#x2F;li&gt;
&lt;li&gt;エラーハンドリングのベストプラクティス&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;jrnl-mcpの実装と機能&quot;&gt;jrnl-mcpの実装と機能&lt;&#x2F;h2&gt;
&lt;p&gt;最終的に実装した機能は以下の5つです。&lt;&#x2F;p&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;機能&lt;&#x2F;th&gt;
      &lt;th&gt;説明&lt;&#x2F;th&gt;
    &lt;&#x2F;tr&gt;
  &lt;&#x2F;thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;search_entries - エントリ検索&lt;&#x2F;td&gt;
      &lt;td&gt;
        日付範囲、タグ、検索キーワードを指定してジャーナルエントリを検索できます。例えば「先週の@work
        タグが付いた記事」といった柔軟な検索が可能です。
      &lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;list_tags - タグ一覧&lt;&#x2F;td&gt;
      &lt;td&gt;
        使用しているすべてのタグとその使用回数を取得します。どんなテーマについて多く書いているかが一目でわかります。
      &lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;get_statistics - 統計情報&lt;&#x2F;td&gt;
      &lt;td&gt;
        総エントリ数、平均文字数、最もよく書いている時間帯など、ジャーナルの統計情報を取得します。
      &lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;analyze_tag_cooccurrence - タグ共起分析&lt;&#x2F;td&gt;
      &lt;td&gt;
        どのタグとどのタグが一緒に使われることが多いかを分析します。思考のパターンや関心事の関連性が見えてきます。
      &lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;list_journals &amp; set_journal - ジャーナル切り替え&lt;&#x2F;td&gt;
      &lt;td&gt;
        jrnl
        は複数のジャーナルを管理できるので、それらを切り替える機能も実装しました。
      &lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
  &lt;&#x2F;tbody&gt;
&lt;&#x2F;table&gt;
&lt;p&gt;すべての機能は読み取り専用にしました。これは、誤ってジャーナルを変更してしまうリスクを避けるためと、MCP
サーバーの初回実装としてシンプルに保つためです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;開発中に学んだMCPの仕組み&quot;&gt;開発中に学んだMCPの仕組み&lt;&#x2F;h2&gt;
&lt;p&gt;MCPサーバーの開発を通じて、以下のような仕組みを理解できました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;リソースとツールの違い&quot;&gt;リソースとツールの違い&lt;&#x2F;h3&gt;
&lt;p&gt;MCPには「リソース」と「ツール」という2つの概念があります。
jrnl-mcpではツールのみを実装しましたが、
リソースを使えば「最新の10エントリ」のような動的なコンテンツを提供も可能です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;非同期処理の重要性&quot;&gt;非同期処理の重要性&lt;&#x2F;h3&gt;
&lt;p&gt;jrnlコマンドの実行は外部プロセスの起動を伴うため、すべての処理を非同期で実装する必要がありました。Node.jsの&lt;code&gt;child_process.exec&lt;&#x2F;code&gt;をPromiseでラップして使用しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;エラーハンドリング&quot;&gt;エラーハンドリング&lt;&#x2F;h3&gt;
&lt;p&gt;MCPサーバーは、エラーが発生してもクライアント（Claude Desktop）に適切にエラーを伝える必要があります。try-catchブロックでエラーをキャッチし、意味のあるエラーメッセージを返すようにしました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;型安全性&quot;&gt;型安全性&lt;&#x2F;h3&gt;
&lt;p&gt;TypeScriptとMCP SDKの型定義のおかげで、ツールの引数や戻り値の型が明確になり、実装ミスを防げました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;セットアップと動作確認&quot;&gt;セットアップと動作確認&lt;&#x2F;h2&gt;
&lt;p&gt;開発したMCPサーバーをClaude Desktopで使うためのセットアップ手順は以下の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;リポジトリをクローンしてビルド&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;git&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; clone https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;jrnl-mcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; jrnl-mcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;グローバルコマンドとしてインストール&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; link&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Claude Desktopの設定ファイルに追加&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;mcpServers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;jrnl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;jrnl-mcp&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;npm link&lt;&#x2F;code&gt;を使うことで、&lt;code&gt;jrnl-mcp&lt;&#x2F;code&gt;というコマンドがグローバルで使えるようになり、設定がシンプルになります。&lt;&#x2F;p&gt;
&lt;p&gt;動作確認では、「jrnlを使って先週の日記を見せて」「@projectタグの統計を教え
て」といったプロンプトで、実際にClaudeがジャーナルのデータにアクセスできる
ことを確認しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;作ってみて分かったMCPサーバー開発のポイント&quot;&gt;作ってみて分かったMCPサーバー開発のポイント&lt;&#x2F;h2&gt;
&lt;p&gt;実際に開発してみて気づいたポイントをまとめます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;小さく始める&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;最初から全機能を実装しようとせず、最小限の機能から始めることが重要である
。動作確認ができてから機能を追加していく方が、デバッグも楽になる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ログの活用&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;開発中は&lt;code&gt;console.error&lt;&#x2F;code&gt;でログを出力すると、Claude Desktopのログに表示さ
れるので、デバッグに役立つ。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;既存ツールのラッパーとしての設計&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;jrnl-mcpは基本的にjrnlコマンドのラッパーとして動作する。既存のCLIツ
ールを活用することで、複雑な実装を避けられる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ドキュメントの重要性&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;READMEにセットアップ手順と使用例を明記することで、将来の自分や他の人が使いやすくなる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;テストの実装&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;今回は時間の都合で省略したが、MCPサーバーのテストも重要である。特に外部
コマンドを実行する部分はモックを使ったテストが有効であろう。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;初めてのMCPサーバー開発は、思っていた以上にスムーズに進みました。Claude
Codeのサポートもあり、半日程度で基本的な機能を持つMCPサーバーを作ることが
できました。&lt;&#x2F;p&gt;
&lt;p&gt;jrnl-mcpを作ってみて、個人のツールやワークフローとAIを連携させることの可
能性を実感しました。読み取り専用という制限はありますが、過去の記録を活用した
アドバイスや分析ができるようになったのは大きな価値です。&lt;&#x2F;p&gt;
&lt;p&gt;MCPは、AIと既存のツールやサービスをつなぐ橋渡し役として、今後ますます重要
になっていくでしょう。この経験を活かして、他のツールとの連携も試してみたいと
思います。&lt;&#x2F;p&gt;
&lt;p&gt;もしMCPサーバー開発に興味がある方は、ぜひ身近なツールから始めてみることを
お勧めします。思っているより簡単に、自分だけのAI連携ツールが作れるはずです
。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Model Context Protocol（MCP）を使って、コマンドラインジャーナルツール「jrnl」とClaudeを連携させるMCPサーバーを開発しました。初めてのMCPサーバー開発の体験記として、選んだ理由から実装のポイント、学んだことまでを詳しく紹介します。</summary>
        </entry><entry xml:lang="en">
        <title>ChromaLensCLI: Command Line Color Accessibility Validation</title>
        <published>2025-01-25T00:00:00+00:00</published>
        <updated>2025-01-25T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/01/chromalenscli-command-line-color-accessibility/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/01/chromalenscli-command-line-color-accessibility/</id>
        
            <content type="html">&lt;p&gt;とりあえず色覚異常の方にも画像が正しく認識できてるか確認するためのツール &lt;code&gt;ChromaLens CLI&lt;&#x2F;code&gt;を作ってみた。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ChromaLens_CLIの使い方&quot;&gt;ChromaLens CLIの使い方&lt;&#x2F;h2&gt;
&lt;p&gt;使い方は、次の通り。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;chromalens&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.jpg output.jpg --type tritanopia&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これで色覚異常の方が実際どのようにインプットとなる画像が見えているかシミュ
レーションした画像が出力されます。
&lt;code&gt;type&lt;&#x2F;code&gt; オプションの指定は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;protanopia (1型色覚)&lt;&#x2F;li&gt;
&lt;li&gt;deuteranopia (2型色覚)&lt;&#x2F;li&gt;
&lt;li&gt;tritanopia (3型色覚)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;ChromeLens_CLIの環境設定&quot;&gt;ChromeLens CLIの環境設定&lt;&#x2F;h4&gt;
&lt;p&gt;以下は、venvでPythonの仮想環境を作って必要なパッケージをインストールする手順です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;python3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -m venv venv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; venv&#x2F;bin&#x2F;activate.fish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pip&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install numpy Pillow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以下が実際のコードです。&lt;code&gt;chromalens&lt;&#x2F;code&gt;というファイル名で保管ください。授業中に書いたコードなので、エラー処理などは省いています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; PIL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; Image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; ColorVisionSimulator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    MATRICES&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;protanopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.567&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.433&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.558&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.442&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.242&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.758&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        ]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;deuteranopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.625&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.375&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.700&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.300&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.300&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.700&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        ]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;tritanopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.950&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.050&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.433&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.567&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.475&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.525&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        ])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; simulate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; output_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; cvd_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cvd_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; not in&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;MATRICES&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            raise&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; ValueError&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Unsupported CVD type. Choose from: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;MATRICES&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;())&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 画像を読み込み&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        img&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; Image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;open&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # RGBAの場合はRGBに変換&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;mode&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;RGBA&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            img&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;convert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;RGB&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # NumPy配列に変換&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        img_array&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 色変換行列を適用&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        matrix&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;MATRICES&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;cvd_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        shape&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img_array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;shape&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        pixels&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img_array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;reshape&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;dot&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;pixels&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; matrix&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 値を0-255の範囲に収める&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;clip&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 255&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;reshape&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;shape&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 画像として保存&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        result&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; Image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;fromarray&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;astype&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;uint8&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;RGB&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;save&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;output_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    parser&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; argparse&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;ArgumentParser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Color Vision Deficiency Simulator&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    parser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;add_argument&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;input&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; help&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Input image path&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    parser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;add_argument&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;output&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; help&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Output image path&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    parser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;add_argument&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;--type&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;-t&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; choices&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;protanopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;deuteranopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;tritanopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;                        required&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt;True&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; help&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Type of color vision deficiency&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    args&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; parser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;parse_args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    simulator&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; ColorVisionSimulator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        simulator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;simulate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Simulation complete: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    except&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; Exception&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; as&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Error: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt;str&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-magic z-python&quot;&gt; __name__&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;__main__&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;    main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">デザイン入門のようなコースをうけていて「色覚異常の方もいるので気をつけましょうね」とか説明されてんだけど、そんな適当な説明じゃなくちゃんとAccessibilityについて説明しろよと思う。だいたい「気をつける」のでなく、世の中にはちゃんとチェックするツールもあるし・・・・</summary>
        </entry><entry xml:lang="en">
        <title>How to Merge and Optimize Your PDF Files</title>
        <published>2025-01-10T00:00:00+00:00</published>
        <updated>2025-01-10T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/01/how-to-merge-and-optimize-pdf/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/01/how-to-merge-and-optimize-pdf/</id>
        
            <content type="html">&lt;h2 id=&quot;Bypassing_PDF_Password_Protection&quot;&gt;Bypassing PDF Password Protection&lt;&#x2F;h2&gt;
&lt;p&gt;While the DJI Neo user manual is provided in PDF format, it&#x27;s password-protected, preventing any modifications or merging. Here&#x27;s how to bypass the password protection on a Mac:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Open the PDF in the Preview app&lt;&#x2F;li&gt;
&lt;li&gt;Select &quot;Print&quot; from the File menu (note: not &quot;Export&quot;)&lt;&#x2F;li&gt;
&lt;li&gt;Choose &quot;Save as PDF&quot; and specify the destination&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This process will create a new PDF without password protection.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Merging_PDFs&quot;&gt;Merging PDFs&lt;&#x2F;h2&gt;
&lt;p&gt;While this can be done with &lt;code&gt;Ghostscript&lt;&#x2F;code&gt; (mentioned later), we&#x27;ll use &lt;code&gt;pdftk&lt;&#x2F;code&gt; for its advantages:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Preserves PDF internal structure (table of contents, bookmarks, links, etc.)&lt;&#x2F;li&gt;
&lt;li&gt;Operates at the binary level, preventing quality degradation&lt;&#x2F;li&gt;
&lt;li&gt;(Although not relevant for this case) Offers flexible operations like page rotation and reordering&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Here&#x27;s how to merge PDFs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Install pdftk (on Mac)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install pdftk-java&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Merge PDFs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pdftk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input1.pdf input2.pdf cat output merged.pdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;PDF_Optimization&quot;&gt;PDF Optimization&lt;&#x2F;h2&gt;
&lt;p&gt;After merging, I found that the file size exceeded 40MB, which was too large to upload to MLIT&#x27;s DIPS2.0 (Drone&#x2F;UAS Information Platform System).&lt;&#x2F;p&gt;
&lt;p&gt;To resolve this, I used Ghostscript for optimization:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Install Ghostscript (on Mac)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install ghostscript&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Optimize PDF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;gs&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=&#x2F;screen -dNOPAUSE -dQUIET -dBATCH -sOutputFile=output.pdf input.pdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;-dPDFSETTINGS&lt;&#x2F;code&gt; option allows you to adjust the compression level:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&#x2F;screen&lt;&#x2F;code&gt;: For screen display (72dpi) - smallest file size&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;ebook&lt;&#x2F;code&gt;: For e-books (150dpi) - balanced compression&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;printer&lt;&#x2F;code&gt;: For printing (300dpi)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;prepress&lt;&#x2F;code&gt;: For high-quality printing (highest quality)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Making_PDF_Searchable&quot;&gt;Making PDF Searchable&lt;&#x2F;h2&gt;
&lt;p&gt;Scanned PDFs aren&#x27;t searchable. Use these Linux&#x2F;Mac commands for OCR instead of expensive software:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install ocrmypdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install tesseract-lang&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# OCR with image optimization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ocrmypdf&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l jpn --optimize&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.pdf output.pdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Creating_Table_of_contents&quot;&gt;Creating Table of contents&lt;&#x2F;h2&gt;
&lt;p&gt;Scanned PDFs often lack a table of contents. Instead of buying expensive PDF software, use these Linux&#x2F;Mac commands:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Install pdftk (on Mac)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install pdftk-java&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Extract metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pdftk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.pdf dump_data_utf8&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; metadata.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Open metadata.txt in your editor and add bookmark locations in this format:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: Chapter 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkLevel: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkPageNumber: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: Chapter 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkLevel: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkPageNumber: 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then apply the metadata to create a PDF with a table of contents:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Apply edited metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pdftk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.pdf update_info_utf8 metadata.txt output output.pdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;With these steps, I successfully optimized the PDF and completed the drone registration.&lt;&#x2F;p&gt;
&lt;p&gt;However, it seems rather inefficient to require individual manual submissions for DJI drones, which are widely used. This feels like typical bureaucratic red tape.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, while this may only be relevant for Japanese users, I&#x27;m sharing the prepared DJI Neo manual that meets DIPS2.0 requirements here: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;e.pcloud.link&#x2F;publink&#x2F;show?code=XZHwGwZuCQmrRb6SFHGinz8MJe1akHv9dF7&quot;&gt;Download&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        <summary type="html">I recently purchased a DJI Neo drone, and in Japan, it&#x27;s mandatory to register your drone with the Ministry of Land, Infrastructure, Transport and Tourism (MLIT). During registration, you need to submit a user manual that includes both handling instructions and specifications. However, the DJI Neo manual only contains references to specifications on DJI&#x27;s website. Therefore, for the registration, I needed to merge the user manual with the specifications from the website.</summary>
        </entry><entry xml:lang="en">
        <title>コマンドラインで画像のExif修正</title>
        <published>2024-08-23T00:00:00+00:00</published>
        <updated>2024-08-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/exiftool/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/exiftool/</id>
        
            <content type="html">&lt;p&gt;デジカメの日付の設定を間違えExifの日付を修正したかったが、
AppStoreから余計なアプリをインストールしたくなかったので、Homebrewでexiftoolをインストールして修正。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Install exiftool using Homebrew&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install exiftool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Confirm dates of exif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;exiftool&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; R0000001.jpg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    ExifTool&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Version Number         :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 12.76&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Name                       : R0000001.JPG&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    Directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                       : .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Size                       :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Modification Date&#x2F;Time     : 2024:08:26 12:42:29+09:00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Access Date&#x2F;Time           : 2024:08:26 12:43:26+09:00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Inode Change Date&#x2F;Time     : 2024:08:26 12:43:24+09:00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Permissions                : -rwx------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Type                       : JPEG&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Type Extension             : jpg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    MIME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Type                       : image&#x2F;jpeg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    Exif&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Byte Order                 : Little-endian&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (Intel,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; II&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    (&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Output&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; truncated for brevity&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Modify dates of exif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;exiftool&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -Alldates=&amp;#39;2024:08:23 12:11:00&amp;#39; -overwrite_original .&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">デジカメの日付の設定を間違えたので、Exifの日付をコマンドラインで一括修正する方法を見つけました。</summary>
        </entry>
</feed>
